@wolfstar/cli 2.1.0 → 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
@@ -1,5 +1,6 @@
1
- import { r as formatError } from "./errors-Crt4hu0b.js";
1
+ import { r as formatError } from "./errors-COFWKKKw.js";
2
2
  import { t as loadAutoImportsModule } from "./framework-auto-imports-Gu_PXSyr.js";
3
+ import { a as modulesPreloadWarning, o as prepareModulesPreload } from "./hooks-BfDFM38k.js";
3
4
  import { createRequire } from "node:module";
4
5
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
5
6
  import { mkdir, readFile, writeFile } from "node:fs/promises";
@@ -122,7 +123,8 @@ async function prepareProject(config, hooks, check = false) {
122
123
  const tsconfig = await prepareTsconfig(config, check);
123
124
  const result = {
124
125
  ...await prepareAutoImports(config, check),
125
- tsconfig
126
+ tsconfig,
127
+ modules: await prepareModulesPreload(config, check)
126
128
  };
127
129
  await hooks?.callHook("prepare:done", config, {
128
130
  dts: result.dts,
@@ -130,11 +132,16 @@ async function prepareProject(config, hooks, check = false) {
130
132
  });
131
133
  return result;
132
134
  }
133
- /** Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version). */
134
- async function reportWarnings(config, write) {
135
+ /**
136
+ * Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version), and, unless `production`
137
+ * is `false` (`stars dev`, which does that itself), what a production start of the project still needs to do.
138
+ */
139
+ async function reportWarnings(config, write, options = {}) {
135
140
  for (const warning of config.warnings) write(await formatError(warning));
141
+ const preload = options.production === false ? null : modulesPreloadWarning(config);
142
+ if (preload) write(await formatError(preload));
136
143
  }
137
144
 
138
145
  //#endregion
139
146
  export { reportWarnings as n, prepareProject as t };
140
- //# sourceMappingURL=_shared-B-hRZDRS.js.map
147
+ //# sourceMappingURL=_shared-DJrpalNQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_shared-DJrpalNQ.js","names":[],"sources":["../src/utils/tsconfig.ts","../src/commands/_shared.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { createRequire } from 'node:module';\r\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\r\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\r\n\r\nconst require = createRequire(import.meta.url);\r\nconst sapphireOptions = Object.assign(\r\n\t{},\r\n\t...['@sapphire/ts-config', '@sapphire/ts-config/extra-strict', '@sapphire/ts-config/decorators'].map(\r\n\t\t(id) => (require(id) as { compilerOptions: Record<string, unknown> }).compilerOptions\r\n\t)\r\n) as Record<string, unknown>;\r\n\r\n/** Generates an extendable config without changing the project's own tsconfig. */\r\nexport async function prepareTsconfig(config: ResolvedStarsConfig, check = false) {\r\n\tconst path = join(config.root, '.stars', 'tsconfig.json');\r\n\tconst fromGenerated = (target: string) => `./${relative(dirname(path), target).replaceAll('\\\\', '/')}`;\r\n\tconst paths: Record<string, string[]> = {};\r\n\tif (config.build.tool === 'tsdown') {\r\n\t\tconst source = dirname(config.entry);\r\n\t\tconst defaults = config.build.configFile === null ? { '~': source, '@': source, '~~': config.root, '@@': config.root } : {};\r\n\t\tconst aliases = { ...defaults, ...(config.tsdown.alias as Record<string, unknown> | undefined) };\r\n\t\tfor (const [alias, target] of Object.entries(aliases)) {\r\n\t\t\t// Module redirects belong to the bundler; only filesystem targets become TypeScript paths.\r\n\t\t\tif (typeof target !== 'string' || (!isAbsolute(target) && !/^\\.\\.?[/\\\\]/.test(target))) continue;\r\n\t\t\tconst resolved = fromGenerated(resolve(config.root, target));\r\n\t\t\tpaths[alias] = [resolved];\r\n\t\t\tpaths[`${alias}/*`] = [`${resolved}/*`];\r\n\t\t}\r\n\t} else if (config.experimental.enableNitro) {\r\n\t\t// `NitroBuilder` turns on Vite's native `resolve.tsconfigPaths` (see https://nitro.build/examples/import-alias),\r\n\t\t// which reads these `paths` straight out of the generated tsconfig — no `tsdown.alias` equivalent to merge\r\n\t\t// with, `vite`/Nitro projects only have this file's own `compilerOptions.paths` to extend or replace.\r\n\t\tconst source = dirname(config.entry);\r\n\t\tconst defaults = { '~': source, '@': source, '~~': config.root, '@@': config.root };\r\n\t\tfor (const [alias, target] of Object.entries(defaults)) {\r\n\t\t\tconst resolved = fromGenerated(resolve(config.root, target));\r\n\t\t\tpaths[alias] = [resolved];\r\n\t\t\tpaths[`${alias}/*`] = [`${resolved}/*`];\r\n\t\t}\r\n\t}\r\n\tconst content = `${JSON.stringify(\r\n\t\t{\r\n\t\t\tcompilerOptions: {\r\n\t\t\t\t...sapphireOptions,\r\n\t\t\t\t// Bundlers emit the application; TypeScript only checks it. Keep Node16 emit for tsc.\r\n\t\t\t\t...(config.build.tool === 'tsdown' || config.build.tool === 'vite'\r\n\t\t\t\t\t? {\r\n\t\t\t\t\t\t\tmodule: 'ESNext',\r\n\t\t\t\t\t\t\tmoduleResolution: 'Bundler',\r\n\t\t\t\t\t\t\tmoduleDetection: 'force',\r\n\t\t\t\t\t\t\tisolatedModules: true,\r\n\t\t\t\t\t\t\tverbatimModuleSyntax: true,\r\n\t\t\t\t\t\t\tallowJs: true,\r\n\t\t\t\t\t\t\tallowImportingTsExtensions: true,\r\n\t\t\t\t\t\t\tresolvePackageJsonImports: true,\r\n\t\t\t\t\t\t\tlib: ['ESNext', 'DOM'],\r\n\t\t\t\t\t\t\tnoEmit: true\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t: {}),\r\n\t\t\t\ttarget: 'ES2022',\r\n\t\t\t\tforceConsistentCasingInFileNames: true,\r\n\t\t\t\tskipLibCheck: true,\r\n\t\t\t\ttsBuildInfoFile: './tsconfig.tsbuildinfo',\r\n\t\t\t\tpaths\r\n\t\t\t},\r\n\t\t\tinclude: [`${fromGenerated(dirname(config.entry))}/**/*`, ...(config.imports.enabled ? [fromGenerated(config.imports.dts)] : [])],\r\n\t\t\texclude: [fromGenerated(join(config.root, 'node_modules')), fromGenerated(config.build.outDir)]\r\n\t\t},\r\n\t\tnull,\r\n\t\t2\r\n\t)}\\n`;\r\n\tif (check) {\r\n\t\tconst existing = await readFile(path, 'utf-8').catch(() => null);\r\n\t\treturn { path, status: existing === content ? ('up-to-date' as const) : ('outdated' as const) };\r\n\t}\r\n\tawait mkdir(dirname(path), { recursive: true });\r\n\tawait writeFile(path, content);\r\n\treturn { path, status: 'written' as const };\r\n}\r\n","import type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\r\nimport { dirname } from 'node:path';\r\nimport { loadAutoImportsModule } from '../utils/framework-auto-imports.js';\r\nimport { formatError } from '../utils/errors.js';\r\nimport type { StarsHookable } from '../utils/hooks.js';\r\nimport { modulesPreloadWarning, prepareModulesPreload } from '../utils/modules.js';\r\nimport { prepareTsconfig } from '../utils/tsconfig.js';\r\n\r\nexport type PrepareResult =\r\n\t| { enabled: false; dts: null; status: null }\r\n\t| { enabled: true; dts: string; status: 'written' | 'up-to-date' | 'outdated' };\r\n\r\n/**\r\n * Regenerates `imports.dts` unconditionally, used by `stars dev`/`stars build` before the first build so the\r\n * declaration file exists (and is current) even when the user never ran `stars prepare` themselves.\r\n */\r\nexport async function prepareAutoImports(config: ResolvedStarsConfig, check = false): Promise<PrepareResult> {\r\n\tif (!config.imports.enabled) return { enabled: false, dts: null, status: null };\r\n\r\n\tconst { dirs, presets, exclude, dts } = config.imports;\r\n\tconst { generateAutoImportsDts } = await loadAutoImportsModule(config.root);\r\n\tconst content = await generateAutoImportsDts({ root: config.root, dirs, presets, exclude });\r\n\r\n\tif (check) {\r\n\t\tconst existing = await readFile(dts, 'utf-8').catch(() => null);\r\n\t\treturn { enabled: true, dts, status: existing === content ? 'up-to-date' : 'outdated' };\r\n\t}\r\n\r\n\tawait mkdir(dirname(dts), { recursive: true });\r\n\tawait writeFile(dts, content);\r\n\treturn { enabled: true, dts, status: 'written' };\r\n}\r\n\r\n/** Prepares TypeScript configuration and auto import declarations before building. */\r\nexport async function prepareProject(config: ResolvedStarsConfig, hooks?: StarsHookable, check = false) {\r\n\tawait hooks?.callHook('prepare:before', config);\r\n\tconst tsconfig = await prepareTsconfig(config, check);\r\n\tconst result = { ...(await prepareAutoImports(config, check)), tsconfig, modules: await prepareModulesPreload(config, check) };\r\n\tawait hooks?.callHook('prepare:done', config, { dts: result.dts, status: result.status });\r\n\treturn result;\r\n}\r\n\r\n/**\r\n * Prints the non-fatal configuration diagnostics (e.g. an end-of-life compatibility version), and, unless `production`\r\n * is `false` (`stars dev`, which does that itself), what a production start of the project still needs to do.\r\n */\r\nexport async function reportWarnings(\r\n\tconfig: ResolvedStarsConfig,\r\n\twrite: (text: string) => void,\r\n\toptions: { production?: boolean } = {}\r\n): Promise<void> {\r\n\tfor (const warning of config.warnings) write(await formatError(warning));\r\n\r\n\tconst preload = options.production === false ? null : modulesPreloadWarning(config);\r\n\tif (preload) write(await formatError(preload));\r\n}\r\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
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";
2
+ import { t as cliDiagnostics } from "./diagnostics-3JRAy8Xj.js";
3
+ import { n as createBuilder, t as Locales } from "./locales-BzOLRBVg.js";
4
+ import { l as projectArgs, n as loadProject, t as applyEnvOptions, u as resolveCwd } from "./hooks-BfDFM38k.js";
5
+ import { n as reportWarnings, t as prepareProject } from "./_shared-DJrpalNQ.js";
6
6
  import { defineCommand } from "citty";
7
7
  import { displayPath } from "@wolfstar/schema";
8
8
  import { createColors } from "colorette";
@@ -53,4 +53,4 @@ var build_default = defineCommand({
53
53
 
54
54
  //#endregion
55
55
  export { build_default as default };
56
- //# sourceMappingURL=build-CPnSLYME.js.map
56
+ //# sourceMappingURL=build-CluOR8dJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-CluOR8dJ.js","names":[],"sources":["../src/commands/build.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\r\nimport { defineCommand } from 'citty';\r\nimport { createColors } from 'colorette';\r\nimport { createBuilder } from '../builders/index.js';\r\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\r\nimport { cliDiagnostics } from '../utils/diagnostics.js';\r\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\r\nimport { Locales } from '../utils/locales.js';\r\nimport { shouldUseColor } from '../utils/output-mode.js';\r\nimport { prepareProject, reportWarnings } from './_shared.js';\r\n\r\nexport interface BuildTaskOptions extends ProjectArgs {\r\n\tstdout?: NodeJS.WritableStream;\r\n}\r\n\r\nexport async function runBuild(options: BuildTaskOptions): Promise<void> {\r\n\tconst stdout = options.stdout ?? process.stdout;\r\n\tconst colors = createColors({ useColor: shouldUseColor() });\r\n\tconst { config: resolved, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\r\n\tawait reportWarnings(resolved, (text) => process.stderr.write(`${text}\\n`));\r\n\r\n\tif (resolved.build.tool === 'none') {\r\n\t\tawait prepareProject(resolved, hooks);\r\n\t\tstdout.write(`${colors.dim('stars')} nothing to build, ${displayPath(resolved.root, resolved.entry)} runs as-is (build.tool is 'none')\\n`);\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Same hook order as `stars dev`: `env:options` and `builder:created` before `prepare:*`.\r\n\tconst config = await applyEnvOptions(resolved, hooks);\r\n\tconst builder = await createBuilder(config, hooks);\r\n\tawait hooks.callHook('builder:created', builder, config);\r\n\tawait prepareProject(config, hooks);\r\n\tbuilder.on('log', (level, text) => {\r\n\t\tconst paint = level === 'error' ? colors.red : level === 'warn' ? colors.yellow : (value: string) => value;\r\n\t\tstdout.write(`${paint(text)}\\n`);\r\n\t});\r\n\r\n\tstdout.write(`${colors.dim('stars')} building with ${colors.bold(config.build.tool)}…\\n`);\r\n\tawait hooks.callHook('build:before', config);\r\n\tconst outcome = await builder.build();\r\n\tawait hooks.callHook('build:done', outcome, config);\r\n\tif (!outcome.ok) {\r\n\t\tthrow cliDiagnostics.BUILD_FAILED({ message: outcome.message ?? '' });\r\n\t}\r\n\tnew Locales(config).copy();\r\n\r\n\tstdout.write(`${colors.dim('stars')} ${colors.green(`built in ${outcome.durationMs}ms`)} → ${displayPath(config.root, config.build.output)}\\n`);\r\n}\r\n\r\nexport default defineCommand({\r\n\tmeta: {\r\n\t\tname: 'build',\r\n\t\tdescription: 'Build the project once with the configured build tool'\r\n\t},\r\n\targs: { ...projectArgs },\r\n\tasync run({ args }) {\r\n\t\tawait runBuild({ config: args.config, cwd: args.cwd });\r\n\t}\r\n});\r\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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as runMain } from "./run-Ddwrxe1O.js";
2
+ import { t as runMain } from "./run-BiLZqib3.js";
3
3
 
4
4
  //#region src/cli.ts
5
5
  await runMain();
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { runMain } from './run.js';\n\nawait runMain();\n"],"mappings":";;;;AAIA,MAAM,QAAQ"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { runMain } from './run.js';\r\n\r\nawait runMain();\r\n"],"mappings":";;;;AAIA,MAAM,QAAQ"}
@@ -1,7 +1,7 @@
1
1
  import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
3
- import { i as resolveFromProject } from "./project-MD4dIo2X.js";
4
- import { a as projectArgs, n as loadProject, o as resolveCwd } from "./hooks-H9kjLCMk.js";
2
+ import { t as cliDiagnostics } from "./diagnostics-3JRAy8Xj.js";
3
+ import { i as resolveFromProject } from "./project-D-8VIcyF.js";
4
+ import { l as projectArgs, n as loadProject, u as resolveCwd } from "./hooks-BfDFM38k.js";
5
5
  import { defineCommand } from "citty";
6
6
  import { join } from "node:path";
7
7
  import { displayPath } from "@wolfstar/schema";
@@ -121,4 +121,4 @@ var codegen_default = defineCommand({
121
121
 
122
122
  //#endregion
123
123
  export { codegen_default as default };
124
- //# sourceMappingURL=codegen-BqpLGLLs.js.map
124
+ //# sourceMappingURL=codegen-D6V1i_fa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen-D6V1i_fa.js","names":[],"sources":["../src/commands/codegen.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { loadProject } from '../utils/hooks.js';\r\nimport { defineCommand } from 'citty';\r\nimport { createColors } from 'colorette';\r\nimport { spawn } from 'node:child_process';\r\nimport { mkdtemp, readFile, rm } from 'node:fs/promises';\r\nimport { tmpdir } from 'node:os';\r\nimport { join } from 'node:path';\r\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\r\nimport { cliDiagnostics } from '../utils/diagnostics.js';\r\nimport { shouldUseColor } from '../utils/output-mode.js';\r\nimport { resolveFromProject } from '../utils/project.js';\r\n\r\nexport interface CodegenTaskOptions extends ProjectArgs {\r\n\tcheck?: boolean;\r\n\tjson?: boolean;\r\n\tstdout?: NodeJS.WritableStream;\r\n}\r\n\r\nexport interface CodegenResult {\r\n\tgenerator: 'i18n';\r\n\toutput: string;\r\n\tstatus: 'written' | 'up-to-date' | 'outdated';\r\n}\r\n\r\nexport async function runCodegen(options: CodegenTaskOptions): Promise<void> {\r\n\tconst stdout = options.stdout ?? process.stdout;\r\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\r\n\tconst { config } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\r\n\tconst results: CodegenResult[] = [];\r\n\r\n\tif (config.codegen.i18n) results.push(await runI18n(config, Boolean(options.check)));\r\n\r\n\tif (options.json) {\r\n\t\tstdout.write(`${JSON.stringify({ check: Boolean(options.check), results }, null, 2)}\\n`);\r\n\t} else if (results.length === 0) {\r\n\t\tstdout.write(`${colors.dim('stars')} nothing to generate (no code generators are configured)\\n`);\r\n\t} else {\r\n\t\tfor (const result of results) {\r\n\t\t\tconst paint = result.status === 'outdated' ? colors.red : colors.green;\r\n\t\t\tstdout.write(`${colors.dim('stars')} ${result.generator}: ${paint(result.status)} ${displayPath(config.root, result.output)}\\n`);\r\n\t\t}\r\n\t}\r\n\r\n\tif (results.some((result) => result.status === 'outdated')) {\r\n\t\tthrow cliDiagnostics.CODEGEN_OUTDATED({});\r\n\t}\r\n}\r\n\r\nasync function runI18n(config: ResolvedStarsConfig, check: boolean): Promise<CodegenResult> {\r\n\tconst { locales, output } = config.codegen.i18n!;\r\n\tconst cli = resolveFromProject(config.root, '@wolfstar/i18next-type-generator');\r\n\tif (!cli) {\r\n\t\tthrow cliDiagnostics.DEPENDENCY_MISSING({\r\n\t\t\tname: '@wolfstar/i18next-type-generator',\r\n\t\t\troot: config.root,\r\n\t\t\thint: 'Install it with `pnpm add -D @wolfstar/i18next-type-generator`, or set `codegen.i18n` to false.'\r\n\t\t});\r\n\t}\r\n\r\n\tif (!check) {\r\n\t\tawait generate(config.root, cli, locales, output);\r\n\t\treturn { generator: 'i18n', output, status: 'written' };\r\n\t}\r\n\r\n\tconst directory = await mkdtemp(join(tmpdir(), 'stars-codegen-'));\r\n\ttry {\r\n\t\tconst candidate = join(directory, 'i18next.d.ts');\r\n\t\tawait generate(config.root, cli, locales, candidate);\r\n\t\tconst [expected, actual] = await Promise.all([readFile(candidate, 'utf-8'), readFile(output, 'utf-8').catch(() => null)]);\r\n\t\treturn { generator: 'i18n', output, status: expected === actual ? 'up-to-date' : 'outdated' };\r\n\t} finally {\r\n\t\tawait rm(directory, { recursive: true, force: true });\r\n\t}\r\n}\r\n\r\nfunction generate(root: string, cli: string, locales: string, output: string): Promise<void> {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tconst child = spawn(process.execPath, [cli, locales, output], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });\r\n\t\tlet stderr = '';\r\n\t\tchild.stderr?.on('data', (chunk: Buffer) => (stderr += chunk.toString()));\r\n\t\tchild.once('error', reject);\r\n\t\tchild.once('exit', (code) => {\r\n\t\t\tif (code === 0) resolve();\r\n\t\t\telse reject(cliDiagnostics.CODEGEN_FAILED({ code, stderr: stderr.trim() }));\r\n\t\t});\r\n\t});\r\n}\r\n\r\nexport default defineCommand({\r\n\tmeta: {\r\n\t\tname: 'codegen',\r\n\t\tdescription: 'Run the configured code generators (i18next types)'\r\n\t},\r\n\targs: {\r\n\t\t...projectArgs,\r\n\t\tcheck: {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdescription: 'Fail when the generated files are out of date instead of writing them',\r\n\t\t\tdefault: false\r\n\t\t},\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 runCodegen({ config: args.config, cwd: args.cwd, check: args.check, json: args.json });\r\n\t}\r\n});\r\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
3
- import { a as projectArgs, n as loadProject, o as resolveCwd } from "./hooks-H9kjLCMk.js";
4
- import { n as readDiscordCredentials } from "./tunnel-DT1FH6oA.js";
2
+ import { t as cliDiagnostics } from "./diagnostics-3JRAy8Xj.js";
3
+ import { l as projectArgs, n as loadProject, u as resolveCwd } from "./hooks-BfDFM38k.js";
4
+ import { n as readDiscordCredentials } from "./tunnel-DHSxOZKr.js";
5
5
  import { defineCommand } from "citty";
6
6
  import { createColors } from "colorette";
7
7
 
@@ -295,4 +295,4 @@ var commands_default = defineCommand({
295
295
 
296
296
  //#endregion
297
297
  export { commands_default as default };
298
- //# sourceMappingURL=commands-ExM8HILu.js.map
298
+ //# sourceMappingURL=commands-BJ589_AC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-BJ589_AC.js","names":[],"sources":["../src/utils/discord.ts","../src/utils/prompts.ts","../src/commands/commands.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { cliDiagnostics } from './diagnostics.js';\r\nimport { readDiscordCredentials } from '../dev/tunnel.js';\r\n\r\nconst API = 'https://discord.com/api/v10';\r\n\r\nexport interface ApplicationCommand {\r\n\tid: string;\r\n\tapplication_id: string;\r\n\tname: string;\r\n\tdescription?: string;\r\n\ttype?: number;\r\n\tguild_id?: string;\r\n\tversion?: string;\r\n}\r\n\r\nexport interface DiscordClient {\r\n\tapplicationId: string;\r\n\tlistCommands(guildId: string | null): Promise<ApplicationCommand[]>;\r\n\tdeleteCommand(guildId: string | null, commandId: string): Promise<void>;\r\n}\r\n\r\nexport const COMMAND_TYPE_NAMES: Record<number, string> = { 1: 'chat input', 2: 'user', 3: 'message' };\r\n\r\n/**\r\n * A minimal Discord REST client for what `stars commands` manages. The credentials come from the environment or the\r\n * project's `.env`, the same place the bot reads them from once it starts.\r\n */\r\nexport function createDiscordClient(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordClient {\r\n\tconst credentials = readDiscordCredentials(config, env);\r\n\tif (!credentials) {\r\n\t\tthrow cliDiagnostics.DISCORD_TOKEN_MISSING({});\r\n\t}\r\n\r\n\tif (!credentials.applicationId) {\r\n\t\tthrow cliDiagnostics.DISCORD_APPLICATION_ID_MISSING({});\r\n\t}\r\n\r\n\tconst applicationId = credentials.applicationId;\r\n\tconst scope = (guildId: string | null) =>\r\n\t\tguildId ? `/applications/${applicationId}/guilds/${guildId}/commands` : `/applications/${applicationId}/commands`;\r\n\r\n\tconst request = async (method: string, path: string): Promise<unknown> => {\r\n\t\tconst response = await fetch(`${API}${path}`, {\r\n\t\t\tmethod,\r\n\t\t\theaders: { authorization: `Bot ${credentials.token}` },\r\n\t\t\tsignal: AbortSignal.timeout(15_000)\r\n\t\t});\r\n\r\n\t\tif (response.status === 204) return null;\r\n\r\n\t\tconst body: unknown = await response.json().catch(() => null);\r\n\t\tif (!response.ok) {\r\n\t\t\tconst detail = typeof body === 'object' && body !== null && 'message' in body ? String((body as { message: unknown }).message) : '';\r\n\t\t\tthrow cliDiagnostics.DISCORD_REQUEST_FAILED({ status: response.status, detail });\r\n\t\t}\r\n\r\n\t\treturn body;\r\n\t};\r\n\r\n\treturn {\r\n\t\tapplicationId,\r\n\t\tasync listCommands(guildId) {\r\n\t\t\tconst body = await request('GET', scope(guildId));\r\n\t\t\treturn Array.isArray(body) ? (body as ApplicationCommand[]) : [];\r\n\t\t},\r\n\t\tasync deleteCommand(guildId, commandId) {\r\n\t\t\tawait request('DELETE', `${scope(guildId)}/${commandId}`);\r\n\t\t}\r\n\t};\r\n}\r\n","import type { Diagnostic } from 'nostics';\r\nimport type { ApplicationCommand } from './discord.js';\r\nimport { cliDiagnostics } from './diagnostics.js';\r\n\r\nexport interface CommandsPrompt {\r\n\t/** Asks which of the deployed commands to delete. Returns the chosen ids. */\r\n\tpick(commands: readonly ApplicationCommand[], scope: string): Promise<string[]>;\r\n\t/** Final go/no-go before anything is deleted. */\r\n\tconfirm(message: string): Promise<boolean>;\r\n}\r\n\r\n/**\r\n * The interactive wizard behind `stars commands clean`: a checklist of what Discord has deployed, then a\r\n * confirmation, so a destructive cleanup is never one keystroke away. `@clack/prompts` is loaded lazily — the\r\n * non-interactive paths (`--yes`, `--json`, CI) never pay for it.\r\n */\r\nexport function createClackPrompt(): CommandsPrompt {\r\n\treturn {\r\n\t\tasync pick(commands, scope) {\r\n\t\t\tconst { isCancel, multiselect } = await import('@clack/prompts');\r\n\t\t\tconst answer = await multiselect({\r\n\t\t\t\tmessage: `Which commands should be deleted from ${scope}?`,\r\n\t\t\t\toptions: commands.map((command) => ({\r\n\t\t\t\t\tvalue: command.id,\r\n\t\t\t\t\tlabel: command.name,\r\n\t\t\t\t\thint: [describeType(command), command.id].filter(Boolean).join(' · ')\r\n\t\t\t\t})),\r\n\t\t\t\trequired: false\r\n\t\t\t});\r\n\r\n\t\t\tif (isCancel(answer)) throw aborted();\r\n\t\t\treturn answer as string[];\r\n\t\t},\r\n\t\tasync confirm(message) {\r\n\t\t\tconst { confirm, isCancel } = await import('@clack/prompts');\r\n\t\t\tconst answer = await confirm({ message, initialValue: false });\r\n\r\n\t\t\tif (isCancel(answer)) throw aborted();\r\n\t\t\treturn Boolean(answer);\r\n\t\t}\r\n\t};\r\n}\r\n\r\nfunction describeType(command: ApplicationCommand): string {\r\n\tswitch (command.type) {\r\n\t\tcase 2:\r\n\t\t\treturn 'user';\r\n\t\tcase 3:\r\n\t\t\treturn 'message';\r\n\t\tdefault:\r\n\t\t\treturn 'chat input';\r\n\t}\r\n}\r\n\r\nfunction aborted(): Diagnostic {\r\n\treturn cliDiagnostics.ABORTED({});\r\n}\r\n","import { loadProject } from '../utils/hooks.js';\r\nimport { defineCommand } from 'citty';\r\nimport { createColors } from 'colorette';\r\nimport type { Diagnostic } from 'nostics';\r\nimport { COMMAND_TYPE_NAMES, createDiscordClient, type ApplicationCommand, type DiscordClient } from '../utils/discord.js';\r\nimport { cliDiagnostics } from '../utils/diagnostics.js';\r\nimport { shouldUseColor } from '../utils/output-mode.js';\r\nimport { createClackPrompt, type CommandsPrompt } from '../utils/prompts.js';\r\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\r\n\r\nexport interface CommandsTaskOptions extends ProjectArgs {\r\n\t/** A guild id to work on the guild-scoped commands instead of the global ones. */\r\n\tguild?: string;\r\n\tjson?: boolean;\r\n\tstdout?: NodeJS.WritableStream;\r\n\t/** Overrides the client, for tests. */\r\n\tclient?: DiscordClient;\r\n}\r\n\r\nexport interface CommandsCleanOptions extends CommandsTaskOptions {\r\n\t/** Names to delete; without any, the wizard asks which of the deployed commands to remove. */\r\n\tnames?: string[];\r\n\t/** Deletes without asking. Required in a non-interactive terminal. */\r\n\tyes?: boolean;\r\n\tstdin?: NodeJS.ReadableStream & { isTTY?: boolean };\r\n\t/** Overrides the interactive wizard, for tests. */\r\n\tprompt?: CommandsPrompt;\r\n}\r\n\r\n/**\r\n * Lists the application commands Discord currently has deployed, which is not necessarily what the project would\r\n * register today: renamed and removed commands stay until something deletes them.\r\n */\r\nexport async function runCommandsList(options: CommandsTaskOptions): Promise<void> {\r\n\tconst stdout = options.stdout ?? process.stdout;\r\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\r\n\tconst { client, guild } = await connect(options);\r\n\tconst commands = await client.listCommands(guild);\r\n\r\n\tif (options.json) {\r\n\t\tstdout.write(`${JSON.stringify({ applicationId: client.applicationId, guildId: guild, commands }, null, 2)}\\n`);\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (commands.length === 0) {\r\n\t\tstdout.write(`${colors.dim('stars')} no ${guild ? `commands in guild ${guild}` : 'global commands'} are deployed\\n`);\r\n\t\treturn;\r\n\t}\r\n\r\n\tstdout.write(`${colors.dim('stars')} ${commands.length} ${guild ? `command(s) in guild ${guild}` : 'global command(s)'}\\n`);\r\n\tfor (const command of commands) stdout.write(` ${colors.bold(describeName(command))} ${colors.dim(command.id)}\\n`);\r\n}\r\n\r\n/**\r\n * Deletes deployed application commands. Discord keeps whatever was registered last, so this is the way to clear\r\n * commands a project no longer defines (or a whole guild's test deployment).\r\n */\r\nexport async function runCommandsClean(options: CommandsCleanOptions): Promise<void> {\r\n\tconst stdout = options.stdout ?? process.stdout;\r\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\r\n\tconst { client, guild } = await connect(options);\r\n\tconst deployed = await client.listCommands(guild);\r\n\tconst wanted = options.names?.filter((name) => name.length > 0) ?? [];\r\n\r\n\tconst missing = wanted.filter((name) => !deployed.some((command) => command.name === name));\r\n\tif (missing.length > 0) {\r\n\t\tthrow cliDiagnostics.COMMAND_NOT_FOUND({ names: missing.join(', ') });\r\n\t}\r\n\r\n\tif (deployed.length === 0) {\r\n\t\tif (options.json) stdout.write(`${JSON.stringify({ deleted: [] }, null, 2)}\\n`);\r\n\t\telse stdout.write(`${colors.dim('stars')} nothing to delete\\n`);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst scope = guild ? `guild ${guild}` : 'the global scope';\r\n\tconst targets = await selectTargets(options, deployed, wanted, scope, stdout, colors);\r\n\tif (targets.length === 0) {\r\n\t\tif (options.json) stdout.write(`${JSON.stringify({ deleted: [] }, null, 2)}\\n`);\r\n\t\telse stdout.write(`${colors.dim('stars')} nothing to delete\\n`);\r\n\t\treturn;\r\n\t}\r\n\r\n\tfor (const command of targets) {\r\n\t\tawait client.deleteCommand(guild, command.id);\r\n\t\tif (!options.json) stdout.write(`${colors.dim('stars')} ${colors.red('deleted')} ${describeName(command)}\\n`);\r\n\t}\r\n\r\n\tif (options.json) stdout.write(`${JSON.stringify({ deleted: targets.map((command) => ({ id: command.id, name: command.name })) }, null, 2)}\\n`);\r\n}\r\n\r\n/**\r\n * Works out what to delete: `--name` (and `--yes`) keep the command scriptable, while a bare `stars commands clean`\r\n * on a terminal runs the wizard — a checklist of what Discord has deployed, then a confirmation.\r\n */\r\nasync function selectTargets(\r\n\toptions: CommandsCleanOptions,\r\n\tdeployed: ApplicationCommand[],\r\n\twanted: string[],\r\n\tscope: string,\r\n\tstdout: NodeJS.WritableStream,\r\n\tcolors: ReturnType<typeof createColors>\r\n): Promise<ApplicationCommand[]> {\r\n\tif (wanted.length > 0) {\r\n\t\tconst named = deployed.filter((command) => wanted.includes(command.name));\r\n\t\tif (options.yes) return named;\r\n\r\n\t\tawait confirmOrThrow(options, stdout, colors, `delete ${colors.bold(String(named.length))} command(s) from ${scope}?`);\r\n\t\treturn named;\r\n\t}\r\n\r\n\tif (options.yes) return deployed;\r\n\r\n\tconst stdin = options.stdin ?? process.stdin;\r\n\tif (!options.prompt && !stdin.isTTY) throw confirmationRequired();\r\n\r\n\tconst prompt = options.prompt ?? createClackPrompt();\r\n\tconst chosen = new Set(await prompt.pick(deployed, scope));\r\n\tconst targets = deployed.filter((command) => chosen.has(command.id));\r\n\tif (targets.length === 0) return [];\r\n\r\n\tconst names = targets.map((command) => command.name).join(', ');\r\n\tif (!(await prompt.confirm(`Delete ${targets.length} command(s) from ${scope}: ${names}?`))) {\r\n\t\tthrow cliDiagnostics.ABORTED({});\r\n\t}\r\n\r\n\treturn targets;\r\n}\r\n\r\nasync function connect(options: CommandsTaskOptions): Promise<{ client: DiscordClient; guild: string | null }> {\r\n\tconst { config } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\r\n\treturn { client: options.client ?? createDiscordClient(config), guild: options.guild ?? null };\r\n}\r\n\r\nfunction describeName(command: ApplicationCommand): string {\r\n\tconst type = command.type && command.type !== 1 ? ` (${COMMAND_TYPE_NAMES[command.type] ?? `type ${command.type}`})` : '';\r\n\treturn `${command.name}${type}`;\r\n}\r\n\r\n/**\r\n * Deleting deployed commands is not reversible, so a terminal run asks first; scripts pass `--yes`.\r\n */\r\nasync function confirmOrThrow(\r\n\toptions: CommandsCleanOptions,\r\n\tstdout: NodeJS.WritableStream,\r\n\tcolors: ReturnType<typeof createColors>,\r\n\tquestion: string\r\n): Promise<void> {\r\n\tif (options.prompt) {\r\n\t\tif (await options.prompt.confirm(question)) return;\r\n\t\tthrow cliDiagnostics.ABORTED({});\r\n\t}\r\n\r\n\tconst stdin = options.stdin ?? process.stdin;\r\n\tif (!stdin.isTTY) throw confirmationRequired();\r\n\r\n\tstdout.write(`${colors.dim('stars')} ${question} [y/N] `);\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tstdin.setEncoding?.('utf-8');\r\n\t\tstdin.once('data', (chunk: string) => {\r\n\t\t\tstdin.pause?.();\r\n\t\t\tconst answer = chunk.trim().toLowerCase();\r\n\t\t\tif (answer === 'y' || answer === 'yes') resolve();\r\n\t\t\telse reject(cliDiagnostics.ABORTED({}));\r\n\t\t});\r\n\t\tstdin.resume?.();\r\n\t});\r\n}\r\n\r\nfunction confirmationRequired(): Diagnostic {\r\n\treturn cliDiagnostics.CONFIRMATION_REQUIRED({});\r\n}\r\n\r\nconst scopeArgs = {\r\n\t...projectArgs,\r\n\tguild: {\r\n\t\ttype: 'string',\r\n\t\tdescription: 'Work on a guild’s commands instead of the global ones'\r\n\t},\r\n\tjson: {\r\n\t\ttype: 'boolean',\r\n\t\tdescription: 'Print machine-readable JSON',\r\n\t\tdefault: false\r\n\t}\r\n} as const;\r\n\r\nconst list = defineCommand({\r\n\tmeta: { name: 'list', description: 'List the application commands Discord has deployed' },\r\n\targs: scopeArgs,\r\n\tasync run({ args }) {\r\n\t\tawait runCommandsList({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json });\r\n\t}\r\n});\r\n\r\nconst clean = defineCommand({\r\n\tmeta: { name: 'clean', description: 'Delete deployed application commands (all of them, or the named ones)' },\r\n\targs: {\r\n\t\t...scopeArgs,\r\n\t\tname: {\r\n\t\t\ttype: 'string',\r\n\t\t\tdescription: 'Only delete the command with this name (repeatable)'\r\n\t\t},\r\n\t\tyes: {\r\n\t\t\ttype: 'boolean',\r\n\t\t\talias: 'y',\r\n\t\t\tdescription: 'Delete without asking for a confirmation',\r\n\t\t\tdefault: false\r\n\t\t}\r\n\t},\r\n\tasync run({ args }) {\r\n\t\tconst names = Array.isArray(args.name) ? args.name : args.name ? [args.name] : [];\r\n\t\tawait runCommandsClean({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json, names, yes: args.yes });\r\n\t}\r\n});\r\n\r\nexport default defineCommand({\r\n\tmeta: {\r\n\t\tname: 'commands',\r\n\t\tdescription: 'Inspect and clean the application commands deployed to Discord'\r\n\t},\r\n\tsubCommands: { list, clean },\r\n\targs: scopeArgs,\r\n\tasync run({ args, rawArgs }) {\r\n\t\t// `stars commands` with no subcommand lists, the way `git branch` does.\r\n\t\tif (rawArgs.some((argument) => argument === 'list' || argument === 'clean')) return;\r\n\r\n\t\tawait runCommandsList({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json });\r\n\t}\r\n});\r\n"],"mappings":"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"}
@@ -1,42 +1,22 @@
1
1
  import { i as shouldUseColor, n as prefersReducedMotion, r as resolveOutputMode } from "./output-mode-Bp7Da8vJ.js";
2
- import { i as renderCrashReport, t as ExitCode } from "./errors-Crt4hu0b.js";
3
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
2
+ import { i as renderCrashReport, t as ExitCode } from "./errors-COFWKKKw.js";
3
+ import { t as cliDiagnostics } from "./diagnostics-3JRAy8Xj.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 { i as resolveFromProject, r as resolveBinary } from "./project-MD4dIo2X.js";
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-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";
5
+ import { r as resolveBinary } from "./project-D-8VIcyF.js";
6
+ import { i as createLineSplitter, n as resolveTscBinary, r as ProcessSupervisor } from "./tsc-DEBcwIO0.js";
7
+ import { n as createBuilder, t as Locales } from "./locales-BzOLRBVg.js";
8
+ import { c as moduleImportArgs, l as projectArgs, n as loadProject, r as withProjectEnv, s as envImportArgs, t as applyEnvOptions, u as resolveCwd } from "./hooks-BfDFM38k.js";
9
+ import { n as reportWarnings, t as prepareProject } from "./_shared-DJrpalNQ.js";
10
+ import { t as Tunnel } from "./tunnel-DHSxOZKr.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 { pathToFileURL } from "node:url";
16
15
  import { displayPath } from "@wolfstar/schema";
17
16
  import { EventEmitter } from "node:events";
18
- import { envModuleSource } from "@wolfstar/vite-server/internal";
19
17
  import { spawn } from "node:child_process";
20
18
  import { lookup } from "node:dns/promises";
21
19
 
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
40
20
  //#region src/dev/typechecker.ts
41
21
  const WATCH_START = /Starting (incremental )?compilation/;
42
22
  const WATCH_DONE = /Found (\d+) errors?\. Watching for file changes/;
@@ -565,6 +545,7 @@ function createSupervisor(config) {
565
545
  command: process.execPath,
566
546
  args: [
567
547
  ...envImportArgs(config),
548
+ ...moduleImportArgs(config),
568
549
  ...config.dev.nodeArgs,
569
550
  config.build.output,
570
551
  ...config.dev.args
@@ -686,7 +667,7 @@ async function runDev(options) {
686
667
  builder,
687
668
  hooks
688
669
  });
689
- await reportWarnings(config, (text) => service.log("stars", "warn", text));
670
+ await reportWarnings(config, (text) => service.log("stars", "warn", text), { production: false });
690
671
  const logFile = config.dev.logFile ? new LogFileWriter(config.dev.logFile, service.logs) : null;
691
672
  logFile?.open();
692
673
  const renderer = mode === "tui" ? (await import("./tui-BRddrLQP.js")).createTuiRenderer(service, {
@@ -779,4 +760,4 @@ var dev_default = defineCommand({
779
760
 
780
761
  //#endregion
781
762
  export { dev_default as default };
782
- //# sourceMappingURL=dev-4wpEQC7l.js.map
763
+ //# sourceMappingURL=dev-DJJZN4NJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-DJJZN4NJ.js","names":[],"sources":["../src/dev/typechecker.ts","../src/dev/dev-service.ts","../src/dev/host.ts","../src/dev/log-file.ts","../src/commands/dev.ts"],"sourcesContent":["import type { ResolvedStarsConfig, StarsTypechecker } from '@wolfstar/schema';\r\nimport { spawn, type ChildProcess } from 'node:child_process';\r\nimport { EventEmitter } from 'node:events';\r\nimport type { Diagnostic } from 'nostics';\r\nimport { resolveTscBinary } from '../builders/tsc.js';\r\nimport { cliDiagnostics } from '../utils/diagnostics.js';\r\nimport type { LogLevel } from '../utils/log-buffer.js';\r\nimport { createLineSplitter } from '../utils/process-supervisor.js';\r\nimport { resolveBinary } from '../utils/project.js';\r\n\r\nconst WATCH_START = /Starting (incremental )?compilation/;\r\nconst WATCH_DONE = /Found (\\d+) errors?\\. Watching for file changes/;\r\nconst ONE_SHOT_DONE = /Found (\\d+) errors?/;\r\nconst ERROR_LINE = /error TS\\d+:/;\r\n\r\nexport type TypecheckState = 'idle' | 'checking' | 'ok' | 'failed';\r\n\r\nexport interface TypecheckerEvents {\r\n\tlog: [level: LogLevel, text: string];\r\n\tstate: [state: TypecheckState, errors: number];\r\n}\r\n\r\nexport interface TypecheckCommand {\r\n\t/** The executable, and whether it is a script `node` has to run. */\r\n\treadonly command: string;\r\n\treadonly args: readonly string[];\r\n\treadonly node: boolean;\r\n\t/** Whether the checker watches the project itself, or has to be re-run after every build. */\r\n\treadonly watch: boolean;\r\n}\r\n\r\n/**\r\n * Runs a type checker next to the bot and reports type errors on their own channel, without ever blocking builds or\r\n * restarts: `stars dev` keeps running whatever the build tool produced, the way Seedcord's `hmr.typecheck` and\r\n * Vite's `checker` plugin do.\r\n *\r\n * `tsc` and `golar` (which forwards to TypeScript) watch the project themselves; `tsz` has no watch mode, so\r\n * {@link Typechecker.check} re-runs it after every build instead.\r\n */\r\nexport class Typechecker extends EventEmitter<TypecheckerEvents> {\r\n\t#child: ChildProcess | null = null;\r\n\t#state: TypecheckState = 'idle';\r\n\t#errors = 0;\r\n\t#pending = false;\r\n\r\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\r\n\t\tsuper();\r\n\t}\r\n\r\n\tpublic get state(): TypecheckState {\r\n\t\treturn this.#state;\r\n\t}\r\n\r\n\tpublic get errors(): number {\r\n\t\treturn this.#errors;\r\n\t}\r\n\r\n\t/** Whether the checker re-runs per build instead of watching on its own. */\r\n\tpublic get oneShot(): boolean {\r\n\t\treturn this.config.dev.typecheck.enabled && !resolveTypecheckCommand(this.config).watch;\r\n\t}\r\n\r\n\tpublic start(): void {\r\n\t\tif (!this.config.dev.typecheck.enabled) return;\r\n\t\tthis.#run();\r\n\t}\r\n\r\n\t/**\r\n\t * Re-runs a checker that cannot watch. Called after every successful build; a run already in flight is replaced,\r\n\t * so a fast series of builds only leaves the last check standing.\r\n\t */\r\n\tpublic check(): void {\r\n\t\tif (!this.oneShot) return;\r\n\t\tif (this.#child) {\r\n\t\t\tthis.#pending = true;\r\n\t\t\tthis.#child.kill();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.#run();\r\n\t}\r\n\r\n\tpublic close(): Promise<void> {\r\n\t\tconst child = this.#child;\r\n\t\tthis.#child = null;\r\n\t\tthis.#pending = false;\r\n\t\tif (!child || child.exitCode !== null) return Promise.resolve();\r\n\r\n\t\treturn new Promise((resolve) => {\r\n\t\t\tchild.once('exit', () => resolve());\r\n\t\t\tchild.kill();\r\n\t\t});\r\n\t}\r\n\r\n\t#run(): void {\r\n\t\tconst { command, args, node, watch } = resolveTypecheckCommand(this.config);\r\n\t\tconst child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {\r\n\t\t\tcwd: this.config.root,\r\n\t\t\tenv: process.env,\r\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\r\n\t\t\twindowsHide: true\r\n\t\t});\r\n\t\tthis.#child = child;\r\n\t\tthis.#setState('checking', 0);\r\n\r\n\t\tlet errors = 0;\r\n\t\tconst handleLine = (line: string) => {\r\n\t\t\tif (ERROR_LINE.test(line)) errors++;\r\n\t\t\tthis.#handleLine(line);\r\n\t\t};\r\n\r\n\t\tconst stdout = createLineSplitter(handleLine);\r\n\t\tconst stderr = createLineSplitter(handleLine);\r\n\t\tchild.stdout?.on('data', stdout.push);\r\n\t\tchild.stderr?.on('data', stderr.push);\r\n\r\n\t\tchild.once('exit', (code) => {\r\n\t\t\tstdout.flush();\r\n\t\t\tstderr.flush();\r\n\t\t\tthis.#child = null;\r\n\r\n\t\t\tif (!watch && this.#state === 'checking') {\r\n\t\t\t\t// A one-shot checker only reports through its exit code when it prints no summary line.\r\n\t\t\t\tthis.#setState(code === 0 && errors === 0 ? 'ok' : 'failed', errors);\r\n\t\t\t}\r\n\r\n\t\t\tif (this.#pending) {\r\n\t\t\t\tthis.#pending = false;\r\n\t\t\t\tthis.#run();\r\n\t\t\t}\r\n\t\t});\r\n\t\tchild.once('error', (error: NodeJS.ErrnoException) => {\r\n\t\t\tthis.#child = null;\r\n\t\t\tthis.emit('log', 'error', error.code === 'ENOENT' ? `${command} is not installed` : error.message);\r\n\t\t\tthis.#setState('failed', this.#errors);\r\n\t\t});\r\n\t}\r\n\r\n\t#handleLine(line: string): void {\r\n\t\tconst text = line.trim();\r\n\t\tif (text.length === 0) return;\r\n\r\n\t\tif (WATCH_START.test(text)) {\r\n\t\t\tthis.#setState('checking', 0);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (ERROR_LINE.test(text)) {\r\n\t\t\tthis.emit('log', 'error', text);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst done = WATCH_DONE.exec(text) ?? ONE_SHOT_DONE.exec(text);\r\n\t\tif (done) {\r\n\t\t\tconst errors = Number(done[1]);\r\n\t\t\tthis.#setState(errors === 0 ? 'ok' : 'failed', errors);\r\n\t\t\tthis.emit('log', errors === 0 ? 'success' : 'error', errors === 0 ? 'No type errors' : `${errors} type error${errors === 1 ? '' : 's'}`);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.emit('log', 'info', text);\r\n\t}\r\n\r\n\t#setState(state: TypecheckState, errors: number): void {\r\n\t\tthis.#state = state;\r\n\t\tthis.#errors = errors;\r\n\t\tthis.emit('state', state, errors);\r\n\t}\r\n}\r\n\r\n/**\r\n * Builds the command line of the configured type checker, resolved from the project's own `node_modules`.\r\n *\r\n * @throws {Diagnostic} when the checker is not installed in the project.\r\n */\r\nexport function resolveTypecheckCommand(config: ResolvedStarsConfig): TypecheckCommand {\r\n\tconst { checker, tsconfig } = config.dev.typecheck;\r\n\tconst project = tsconfig!;\r\n\r\n\tswitch (checker) {\r\n\t\tcase 'golar': {\r\n\t\t\t// `golar tsc` forwards everything after it to the TypeScript CLI, watch mode included.\r\n\t\t\tconst golar = resolveBinary(config.root, 'golar', 'golar');\r\n\t\t\tif (!golar) throw missing(config, 'golar', 'Install it with `pnpm add -D golar`');\r\n\r\n\t\t\treturn { command: golar, args: ['tsc', ...WATCH_ARGS, '-p', project], node: true, watch: true };\r\n\t\t}\r\n\r\n\t\tcase 'tsz': {\r\n\t\t\t// `tsz` is an early, tsc-compatible checker with no watch mode; `try-tsz` is its comparison harness.\r\n\t\t\tconst tsz = resolveBinary(config.root, '@mohsen-azimi/tsz-dev', 'tsz');\r\n\t\t\tif (tsz) return { command: tsz, args: ['--noEmit', '-p', project], node: true, watch: false };\r\n\r\n\t\t\tconst tryTsz = resolveBinary(config.root, 'try-tsz', 'try-tsz');\r\n\t\t\tif (tryTsz) return { command: tryTsz, args: ['-p', project], node: true, watch: false };\r\n\r\n\t\t\tthrow missing(config, 'tsz', 'Install it with `pnpm add -D @mohsen-azimi/tsz-dev` (or `try-tsz`)');\r\n\t\t}\r\n\r\n\t\tdefault: {\r\n\t\t\tconst tsc = resolveTscBinary(config.root);\r\n\t\t\tif (!tsc) throw missing(config, 'typescript', 'Install it with `pnpm add -D typescript`');\r\n\r\n\t\t\treturn { command: tsc, args: [...WATCH_ARGS, '-p', project], node: true, watch: true };\r\n\t\t}\r\n\t}\r\n}\r\n\r\nconst WATCH_ARGS = ['--noEmit', '--watch', '--preserveWatchOutput', '--pretty', 'false'] as const;\r\n\r\nfunction missing(config: ResolvedStarsConfig, name: string, install: string): Diagnostic {\r\n\treturn cliDiagnostics.DEPENDENCY_MISSING({\r\n\t\tname,\r\n\t\troot: config.root,\r\n\t\thint: `${install}, pick another \\`dev.typecheck.checker\\`, or set \\`dev.typecheck\\` to false.`\r\n\t});\r\n}\r\n\r\nexport type { StarsTypechecker };\r\n","import { EventEmitter } from 'node:events';\r\nimport type { Builder, BuildOutcome } from '../builders/types.js';\r\nimport { displayPath, type ResolvedStarsConfig, type StarsHooks, type StarsRestartReason } from '@wolfstar/schema';\r\nimport { envImportArgs, moduleImportArgs } from '../utils/env-import.js';\r\nimport type { StarsHookable } from '../utils/hooks.js';\r\nimport { classifyAppLine, LogBuffer, type LogLevel, type LogSource } from '../utils/log-buffer.js';\r\nimport { Locales } from '../utils/locales.js';\r\nimport { ProcessSupervisor, type ProcessExit, type ProcessState } from '../utils/process-supervisor.js';\r\nimport { Tunnel, type TunnelState } from './tunnel.js';\r\nimport { Typechecker, type TypecheckState } from './typechecker.js';\r\n\r\nexport type BuildState = 'idle' | 'building' | 'ok' | 'failed';\r\nexport type HealthState = 'unknown' | 'ok' | 'down';\r\nexport type RestartReason = StarsRestartReason;\r\n\r\nexport interface DevStatus {\r\n\treadonly progress: { readonly fraction: number; readonly message: string; readonly startedAt: number; readonly readyMs: number | null };\r\n\treadonly process: ProcessState;\r\n\treadonly build: BuildState;\r\n\treadonly health: HealthState;\r\n\treadonly pid: number | null;\r\n\treadonly startedAt: number | null;\r\n\treadonly restarts: number;\r\n\treadonly lastRestartReason: RestartReason | null;\r\n\treadonly lastBuild: BuildOutcome | null;\r\n\treadonly lastExit: ProcessExit | null;\r\n\treadonly url: string | null;\r\n\treadonly typecheck: TypecheckState;\r\n\treadonly typeErrors: number;\r\n\treadonly tunnel: TunnelState;\r\n\treadonly tunnelUrl: string | null;\r\n}\r\n\r\nexport interface DevServiceEvents {\r\n\tstatus: [status: DevStatus];\r\n}\r\n\r\nexport interface DevServiceOptions {\r\n\tbuilder: Builder;\r\n\t/** The `stars.config` hooks; `build:*` and `dev:restart` run from here. */\r\n\thooks?: StarsHookable;\r\n\tlogs?: LogBuffer;\r\n\t/** Overrides for tests. */\r\n\tsupervisor?: ProcessSupervisor;\r\n\ttypechecker?: Typechecker;\r\n\ttunnel?: Tunnel;\r\n\thealthInterval?: number;\r\n}\r\n\r\n/**\r\n * The headless heart of `stars dev`: builds, (re)starts the bot and exposes state and logs.\r\n * Renderers (plain or TUI) only subscribe to it, they never own behaviour.\r\n */\r\nexport class DevService extends EventEmitter<DevServiceEvents> {\r\n\tpublic readonly logs: LogBuffer;\r\n\tpublic readonly builder: Builder;\r\n\tpublic readonly supervisor: ProcessSupervisor;\r\n\tpublic readonly typechecker: Typechecker;\r\n\tpublic readonly tunnel: Tunnel;\r\n\tpublic readonly locales: Locales;\r\n\treadonly #hooks: StarsHookable | null;\r\n\t/** Runs hooks one at a time, so an async `build:done` settles before the next build's hooks or a restart. */\r\n\t#hookChain: Promise<void> = Promise.resolve();\r\n\r\n\t#build: BuildState = 'idle';\r\n\t#health: HealthState = 'unknown';\r\n\t#restarts = 0;\r\n\t#lastRestartReason: RestartReason | null = null;\r\n\t#lastBuild: BuildOutcome | null = null;\r\n\t#lastExit: ProcessExit | null = null;\r\n\t#restartTimer: NodeJS.Timeout | null = null;\r\n\t#healthTimer: NodeJS.Timeout | null = null;\r\n\t#pendingReason: RestartReason | null = null;\r\n\t#stopped = false;\r\n\t#queue: Promise<void> = Promise.resolve();\r\n\t#progress = { fraction: 0, message: 'preparing your app', startedAt: Date.now(), readyMs: null as number | null };\r\n\r\n\tpublic constructor(\r\n\t\tpublic readonly config: ResolvedStarsConfig,\r\n\t\toptions: DevServiceOptions\r\n\t) {\r\n\t\tsuper();\r\n\t\tthis.logs = options.logs ?? new LogBuffer();\r\n\t\tthis.builder = options.builder;\r\n\t\tthis.supervisor = options.supervisor ?? createSupervisor(config);\r\n\t\tthis.typechecker = options.typechecker ?? new Typechecker(config);\r\n\t\tthis.tunnel = options.tunnel ?? new Tunnel(config);\r\n\t\tthis.locales = new Locales(config);\r\n\t\tthis.#hooks = options.hooks ?? null;\r\n\r\n\t\tthis.builder.on('start', () => {\r\n\t\t\tthis.#progress = { fraction: 0, message: 'preparing build', startedAt: Date.now(), readyMs: null };\r\n\t\t\tthis.#setBuild('building');\r\n\t\t\tvoid this.#startHook('build:before', this.config);\r\n\t\t});\r\n\t\tthis.builder.on('progress', (fraction, message) => {\r\n\t\t\tthis.#progress = { ...this.#progress, fraction: Math.max(this.#progress.fraction, Math.min(0.75, fraction)), message };\r\n\t\t\tthis.#emitStatus();\r\n\t\t});\r\n\t\tthis.builder.on('success', (outcome) => this.#onBuildSuccess(outcome));\r\n\t\tthis.builder.on('failure', (outcome) => this.#onBuildFailure(outcome));\r\n\t\tthis.builder.on('log', (level, text) => this.log('build', level, text));\r\n\r\n\t\tthis.supervisor.on('state', () => {\r\n\t\t\tif (this.supervisor.state === 'running') {\r\n\t\t\t\tthis.#settleProgress();\r\n\t\t\t\tvoid this.#checkHealth();\r\n\t\t\t}\r\n\t\t\tthis.#emitStatus();\r\n\t\t});\r\n\t\tthis.supervisor.on('stdout', (line) => this.log('app', classifyAppLine(line, 'info'), line));\r\n\t\tthis.supervisor.on('stderr', (line) => this.log('app', classifyAppLine(line, 'error'), line));\r\n\t\tthis.supervisor.on('error', (error) => this.log('stars', 'error', `Failed to start the bot: ${error.message}`));\r\n\t\tthis.supervisor.on('exit', (exit) => this.#onExit(exit));\r\n\r\n\t\tthis.typechecker.on('log', (level, text) => this.log('tsc', level, text));\r\n\t\tthis.typechecker.on('state', () => this.#emitStatus());\r\n\t\tthis.tunnel.on('log', (level, text) => this.log('tunnel', level, text));\r\n\t\tthis.tunnel.on('state', () => this.#emitStatus());\r\n\t\tthis.locales.on('log', (level, text) => this.log('build', level, text));\r\n\t\tthis.locales.on('change', () => {\r\n\t\t\tif (this.#build === 'ok') this.#scheduleRestart('build');\r\n\t\t});\r\n\r\n\t\tif (config.dev.url && config.dev.health) {\r\n\t\t\tconst interval = options.healthInterval ?? 5000;\r\n\t\t\tthis.#healthTimer = setInterval(() => void this.#checkHealth(), interval);\r\n\t\t\tthis.#healthTimer.unref();\r\n\t\t}\r\n\t}\r\n\r\n\tpublic get status(): DevStatus {\r\n\t\treturn {\r\n\t\t\tprogress: this.#progress,\r\n\t\t\tprocess: this.supervisor.state,\r\n\t\t\tbuild: this.#build,\r\n\t\t\thealth: this.#health,\r\n\t\t\tpid: this.supervisor.pid,\r\n\t\t\tstartedAt: this.supervisor.startedAt,\r\n\t\t\trestarts: this.#restarts,\r\n\t\t\tlastRestartReason: this.#lastRestartReason,\r\n\t\t\tlastBuild: this.#lastBuild,\r\n\t\t\tlastExit: this.#lastExit,\r\n\t\t\turl: this.config.dev.url,\r\n\t\t\ttypecheck: this.typechecker.state,\r\n\t\t\ttypeErrors: this.typechecker.errors,\r\n\t\t\ttunnel: this.tunnel.state,\r\n\t\t\ttunnelUrl: this.tunnel.url\r\n\t\t};\r\n\t}\r\n\r\n\tpublic log(source: LogSource, level: LogLevel, text: string): void {\r\n\t\tthis.logs.push({ source, level, text });\r\n\t}\r\n\r\n\t/**\r\n\t * Starts watching; the bot starts after the first successful build.\r\n\t */\r\n\tpublic async start(): Promise<void> {\r\n\t\tthis.#stopped = false;\r\n\t\tconst entry = displayPath(this.config.root, this.config.entry);\r\n\t\tthis.log('stars', 'info', this.config.build.tool === 'none' ? `Watching ${entry}` : `Watching ${entry} with ${this.config.build.tool}`);\r\n\t\tif (this.config.dev.typecheck.enabled) this.typechecker.start();\r\n\t\tawait this.locales.watch();\r\n\t\t// The tunnel comes up next to the build: neither waits for the other, and a failed tunnel never stops the bot.\r\n\t\tvoid this.tunnel.start();\r\n\t\tawait this.builder.watch();\r\n\t}\r\n\r\n\t/**\r\n\t * Restarts the bot immediately (used by the `r` key and by `SIGUSR2`).\r\n\t */\r\n\tpublic restart(reason: RestartReason = 'manual'): Promise<void> {\r\n\t\tthis.#clearRestartTimer();\r\n\t\treturn this.#enqueue(async () => {\r\n\t\t\tif (this.#stopped) return;\r\n\t\t\tawait this.#queueHook('dev:restart', reason, this.config);\r\n\t\t\tif (this.#stopped) return;\r\n\t\t\tif (reason === 'manual' || reason === 'crash') {\r\n\t\t\t\tthis.#progress = { fraction: 0, message: 'restarting the bot', startedAt: Date.now(), readyMs: null };\r\n\t\t\t}\r\n\t\t\tthis.#lastRestartReason = reason;\r\n\t\t\tif (this.supervisor.running) {\r\n\t\t\t\tthis.#restarts++;\r\n\t\t\t\tthis.log('stars', 'info', `Restarting (${describeReason(reason)})`);\r\n\t\t\t\tawait this.supervisor.stop();\r\n\t\t\t} else {\r\n\t\t\t\tthis.log('stars', 'info', `Starting (${describeReason(reason)})`);\r\n\t\t\t}\r\n\r\n\t\t\tif (this.#stopped) return;\r\n\t\t\tthis.#progress = { ...this.#progress, fraction: 0.75, message: 'starting the bot' };\r\n\t\t\tthis.#health = 'unknown';\r\n\t\t\tthis.supervisor.start();\r\n\t\t\tthis.#emitStatus();\r\n\t\t});\r\n\t}\r\n\r\n\t/** Opens or closes the public tunnel (used by the `t` key). */\r\n\tpublic toggleTunnel(): Promise<void> {\r\n\t\treturn this.tunnel.toggle();\r\n\t}\r\n\r\n\t/**\r\n\t * Stops the watcher and the bot. Safe to call more than once.\r\n\t */\r\n\tpublic async stop(): Promise<void> {\r\n\t\tthis.#stopped = true;\r\n\t\tthis.#clearRestartTimer();\r\n\t\tif (this.#healthTimer) clearInterval(this.#healthTimer);\r\n\t\tthis.#healthTimer = null;\r\n\t\tawait this.#enqueue(async () => {\r\n\t\t\tawait Promise.allSettled([\r\n\t\t\t\tthis.builder.close(),\r\n\t\t\t\tthis.supervisor.stop(),\r\n\t\t\t\tthis.typechecker.close(),\r\n\t\t\t\tthis.tunnel.close(),\r\n\t\t\t\tthis.locales.close()\r\n\t\t\t]);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Kills the bot and the helper processes without waiting for them. Only for a forced shutdown, {@link stop} is the graceful path.\r\n\t */\r\n\tpublic kill(): void {\r\n\t\tthis.#stopped = true;\r\n\t\tthis.#clearRestartTimer();\r\n\t\tthis.supervisor.kill();\r\n\t\tvoid this.typechecker.close();\r\n\t\tvoid this.tunnel.close();\r\n\t}\r\n\r\n\tpublic clearLogs(): void {\r\n\t\tthis.logs.clear();\r\n\t}\r\n\r\n\t#onBuildSuccess(outcome: BuildOutcome): void {\r\n\t\ttry {\r\n\t\t\tthis.locales.copy();\r\n\t\t} catch (error) {\r\n\t\t\tthis.#onBuildFailure({\r\n\t\t\t\t...outcome,\r\n\t\t\t\tok: false,\r\n\t\t\t\tmessage: `Failed to copy locales: ${error instanceof Error ? error.message : String(error)}`\r\n\t\t\t});\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.#lastBuild = outcome;\r\n\t\tthis.#progress = { ...this.#progress, fraction: 0.75, message: 'starting the bot' };\r\n\t\tthis.#setBuild('ok');\r\n\t\t// Only once locales are copied: until then the build is not done, and may still fail.\r\n\t\tvoid this.#queueHook('build:done', outcome, this.config);\r\n\t\tif (this.#stopped) return;\r\n\t\t// A checker without a watch mode (`tsz`) only knows about the change once the build is through.\r\n\t\tthis.typechecker.check();\r\n\t\tthis.log('stars', 'success', this.builder.tool === 'none' ? 'Sources changed' : `Build succeeded in ${outcome.durationMs}ms`);\r\n\t\tthis.#scheduleRestart(this.supervisor.state === 'idle' ? 'initial' : 'build');\r\n\t}\r\n\r\n\t#onBuildFailure(outcome: BuildOutcome): void {\r\n\t\tthis.#lastBuild = outcome;\r\n\t\tvoid this.#queueHook('build:done', outcome, this.config);\r\n\t\tthis.#setBuild('failed');\r\n\t\tthis.#clearRestartTimer();\r\n\t\tthis.log('stars', 'error', `Build failed${outcome.message ? `: ${outcome.message}` : ''}, waiting for changes`);\r\n\t}\r\n\r\n\t#onExit(exit: ProcessExit): void {\r\n\t\tthis.#lastExit = exit;\r\n\t\tthis.#health = 'unknown';\r\n\t\tif (!exit.requested) {\r\n\t\t\tconst how = exit.signal ? `signal ${exit.signal}` : `code ${exit.code}`;\r\n\t\t\tthis.log('stars', exit.code === 0 ? 'warn' : 'error', `The bot exited with ${how}, waiting for changes (press r to restart)`);\r\n\t\t}\r\n\t\tthis.#emitStatus();\r\n\t}\r\n\r\n\t#scheduleRestart(reason: RestartReason): void {\r\n\t\tthis.#pendingReason = reason;\r\n\t\tthis.#clearRestartTimer();\r\n\t\tthis.#restartTimer = setTimeout(() => {\r\n\t\t\tthis.#restartTimer = null;\r\n\t\t\tconst pending = this.#pendingReason ?? reason;\r\n\t\t\tthis.#pendingReason = null;\r\n\t\t\tvoid this.restart(pending);\r\n\t\t}, this.config.dev.debounce);\r\n\t}\r\n\r\n\t#clearRestartTimer(): void {\r\n\t\tif (this.#restartTimer) clearTimeout(this.#restartTimer);\r\n\t\tthis.#restartTimer = null;\r\n\t}\r\n\r\n\t#enqueue(task: () => Promise<void>): Promise<void> {\r\n\t\tthis.#queue = this.#queue.then(task, task);\r\n\t\treturn this.#queue;\r\n\t}\r\n\r\n\t#setBuild(state: BuildState): void {\r\n\t\tif (this.#build === state) return;\r\n\t\tthis.#build = state;\r\n\t\tthis.#emitStatus();\r\n\t}\r\n\r\n\tasync #checkHealth(): Promise<void> {\r\n\t\tif (!this.supervisor.running || !this.config.dev.url || !this.config.dev.health) return;\r\n\t\tconst pid = this.supervisor.pid;\r\n\r\n\t\tlet next: HealthState;\r\n\t\ttry {\r\n\t\t\tconst response = await fetch(new URL(this.config.dev.health, this.config.dev.url), { signal: AbortSignal.timeout(2000) });\r\n\t\t\tnext = response.status < 500 ? 'ok' : 'down';\r\n\t\t} catch {\r\n\t\t\tnext = 'down';\r\n\t\t}\r\n\r\n\t\tif (this.#stopped || pid !== this.supervisor.pid) return;\r\n\t\tif (next !== this.#health) {\r\n\t\t\tthis.#health = next;\r\n\t\t\tif (next === 'ok') this.#settleProgress();\r\n\t\t\tthis.#emitStatus();\r\n\t\t}\r\n\t}\r\n\r\n\t#settleProgress(): void {\r\n\t\tif (this.config.dev.health && this.#health !== 'ok') return;\r\n\t\tif (this.#build !== 'ok') return;\r\n\t\tthis.#progress = {\r\n\t\t\t...this.#progress,\r\n\t\t\tfraction: 1,\r\n\t\t\tmessage: 'watching for changes',\r\n\t\t\treadyMs: this.#progress.readyMs ?? Date.now() - this.#progress.startedAt\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Runs a hook behind the ones already running (see {@link DevService.#hookChain}), e.g. `dev:close` so shutdown\r\n\t * waits for an unfinished `build:done`.\r\n\t */\r\n\tpublic runHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\r\n\t\treturn this.#queueHook(name, ...args);\r\n\t}\r\n\r\n\t/** Queues a hook behind the ones already running; see {@link DevService.#hookChain}. */\r\n\t#queueHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\r\n\t\tthis.#hookChain = this.#hookChain.then(() => this.#callHook(name, ...args));\r\n\t\treturn this.#hookChain;\r\n\t}\r\n\r\n\t/**\r\n\t * Starts a hook right away, at the moment it describes, instead of queueing it: `build:before` belongs to the\r\n\t * builder's `start` boundary, and a builder such as `none` finishes in the same call stack. Its synchronous part\r\n\t * runs here; later hooks still wait for the rest.\r\n\t */\r\n\t#startHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\r\n\t\tconst running = this.#callHook(name, ...args);\r\n\t\tthis.#hookChain = Promise.all([this.#hookChain, running]).then(() => undefined);\r\n\t\treturn running;\r\n\t}\r\n\r\n\t/**\r\n\t * Runs a `stars.config` hook. A failing hook is logged rather than thrown: a broken hook must never stop the\r\n\t * watcher or keep the bot from restarting.\r\n\t */\r\n\tasync #callHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\r\n\t\tif (this.#hooks === null) return;\r\n\t\ttry {\r\n\t\t\tawait this.#hooks.callHook(name, ...args);\r\n\t\t} catch (error) {\r\n\t\t\tthis.log('stars', 'error', `Hook ${name} failed: ${error instanceof Error ? error.message : String(error)}`);\r\n\t\t}\r\n\t}\r\n\r\n\t#emitStatus(): void {\r\n\t\tthis.emit('status', this.status);\r\n\t}\r\n}\r\n\r\nexport function createSupervisor(config: ResolvedStarsConfig): ProcessSupervisor {\r\n\treturn new ProcessSupervisor({\r\n\t\tcommand: process.execPath,\r\n\t\targs: [...envImportArgs(config), ...moduleImportArgs(config), ...config.dev.nodeArgs, config.build.output, ...config.dev.args],\r\n\t\tcwd: config.root,\r\n\t\tenv: {\r\n\t\t\t...process.env,\r\n\t\t\t...config.dev.env,\r\n\t\t\tSTARS_DEV: '1',\r\n\t\t\tNODE_ENV: 'development',\r\n\t\t\tFORCE_COLOR: process.env.NO_COLOR !== undefined ? undefined : (process.env.FORCE_COLOR ?? (process.stdout.isTTY ? '1' : undefined))\r\n\t\t},\r\n\t\tkillTimeout: config.dev.killTimeout\r\n\t});\r\n}\r\n\r\nexport function describeReason(reason: RestartReason): string {\r\n\tswitch (reason) {\r\n\t\tcase 'initial':\r\n\t\t\treturn 'first build';\r\n\t\tcase 'build':\r\n\t\t\treturn 'sources changed';\r\n\t\tcase 'manual':\r\n\t\t\treturn 'manual restart';\r\n\t\tcase 'crash':\r\n\t\t\treturn 'after crash';\r\n\t}\r\n}\r\n","import { lookup } from 'node:dns/promises';\r\n\r\n/**\r\n * Resolves `localhost` the way Vite's dev server does: Node's default DNS result order (`dns.lookup('localhost')`)\r\n * can disagree with the OS's own, \"verbatim\" resolution order — a well known source of a dev URL that prints fine\r\n * but is not the address the bot actually bound to (e.g. an IPv6-first system where the server listens on IPv4\r\n * only). When the two disagree this returns the OS's own address instead of the literal `localhost` hostname.\r\n */\r\nexport async function resolveLocalhost(): Promise<string> {\r\n\ttry {\r\n\t\tconst [ordered, verbatim] = await Promise.all([lookup('localhost'), lookup('localhost', { verbatim: true })]);\r\n\t\treturn ordered.family === verbatim.family && ordered.address === verbatim.address ? 'localhost' : verbatim.address;\r\n\t} catch {\r\n\t\treturn 'localhost';\r\n\t}\r\n}\r\n\r\n/**\r\n * Replaces a `localhost` hostname in `url` with {@link resolveLocalhost}'s result. Any other hostname (an explicit\r\n * `dev.url` override, a LAN address, …) is returned untouched.\r\n */\r\nexport async function withResolvedLocalhost(url: string): Promise<string> {\r\n\tconst parsed = new URL(url);\r\n\tif (parsed.hostname !== 'localhost') return url;\r\n\r\n\tconst host = await resolveLocalhost();\r\n\tif (host === 'localhost') return url;\r\n\r\n\tparsed.hostname = host.includes(':') ? `[${host}]` : host;\r\n\treturn parsed.href;\r\n}\r\n","import { createWriteStream, mkdirSync, type WriteStream } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type { LogBuffer, LogEntry } from '../utils/log-buffer.js';\r\n\r\n/**\r\n * Mirrors a dev session's logs into a file, so a run can be read back after the terminal UI is gone (the TUI takes\r\n * over the alternate screen and its scrollback disappears on exit). Seedcord keeps a `logs/` directory for the same\r\n * reason; this writes a single, truncated-per-run file instead.\r\n */\r\nexport class LogFileWriter {\r\n\t#stream: WriteStream | null = null;\r\n\r\n\tpublic constructor(\r\n\t\tpublic readonly file: string,\r\n\t\tprivate readonly logs: LogBuffer\r\n\t) {}\r\n\r\n\tpublic open(): void {\r\n\t\tif (this.#stream) return;\r\n\r\n\t\tmkdirSync(dirname(this.file), { recursive: true });\r\n\t\tthis.#stream = createWriteStream(this.file, { flags: 'w' });\r\n\t\t// A broken pipe or a read-only directory must never take the dev session down with it.\r\n\t\tthis.#stream.on('error', () => this.close());\r\n\r\n\t\tfor (const entry of this.logs.entries()) this.#write(entry);\r\n\t\tthis.logs.on('entry', this.#write);\r\n\t}\r\n\r\n\tpublic close(): void {\r\n\t\tconst stream = this.#stream;\r\n\t\tthis.#stream = null;\r\n\t\tif (!stream) return;\r\n\r\n\t\tthis.logs.off('entry', this.#write);\r\n\t\tstream.end();\r\n\t}\r\n\r\n\t#write = (entry: LogEntry): void => {\r\n\t\tthis.#stream?.write(`${format(entry)}\\n`);\r\n\t};\r\n}\r\n\r\nfunction format(entry: LogEntry): string {\r\n\treturn `${new Date(entry.time).toISOString()} ${entry.level.padEnd(7)} ${entry.source.padEnd(6)} ${entry.text}`;\r\n}\r\n","import type { ResolvedStarsConfig } from '@wolfstar/schema';\r\nimport { defineCommand } from 'citty';\r\nimport { createBuilder } from '../builders/index.js';\r\nimport { DevService } from '../dev/dev-service.js';\r\nimport { withResolvedLocalhost } from '../dev/host.js';\r\nimport { LogFileWriter } from '../dev/log-file.js';\r\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\r\nimport { cliDiagnostics } from '../utils/diagnostics.js';\r\nimport { ExitCode, renderCrashReport } from '../utils/errors.js';\r\nimport { applyEnvOptions, loadProject, withProjectEnv } from '../utils/hooks.js';\r\nimport { prefersReducedMotion, resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\r\nimport { THEME_SETTINGS, isThemeSetting, readSavedTheme, resolveThemeSetting, saveTheme } from '../utils/theme.js';\r\nimport { prepareProject, reportWarnings } from './_shared.js';\r\n\r\nexport interface DevTaskOptions extends ProjectArgs {\r\n\ttui?: boolean;\r\n\t/** `--theme`. */\r\n\ttheme?: string;\r\n}\r\n\r\nexport async function runDev(options: DevTaskOptions): Promise<void> {\r\n\tif (options.theme !== undefined && !isThemeSetting(options.theme)) {\r\n\t\tthrow cliDiagnostics.INVALID_THEME({ theme: options.theme, themes: THEME_SETTINGS.join(', ') });\r\n\t}\r\n\r\n\t// Dev mode applies to config evaluation, build plugins, and the supervised application — not only the child.\r\n\tprocess.env.NODE_ENV = 'development';\r\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config, env: { ...process.env, NODE_ENV: 'development' } });\r\n\tconst hooks = project.hooks;\r\n\t// `env:options` first: it may pick env files with another `HTTP_PORT`, which `dev.url` is derived from.\r\n\tconst config = await resolveDevConfig(withProjectEnv(await applyEnvOptions(project.config, hooks)));\r\n\tconst mode = resolveOutputMode({ tui: options.tui });\r\n\tconst color = shouldUseColor();\r\n\tconst theme = resolveThemeSetting({ flag: options.theme, saved: readSavedTheme() });\r\n\r\n\tconst builder = await createBuilder(config, hooks);\r\n\tawait hooks.callHook('builder:created', builder, config);\r\n\tconst service = new DevService(config, { builder, hooks });\r\n\tawait reportWarnings(config, (text) => service.log('stars', 'warn', text), { production: false });\r\n\tconst logFile = config.dev.logFile ? new LogFileWriter(config.dev.logFile, service.logs) : null;\r\n\tlogFile?.open();\r\n\tconst renderer =\r\n\t\tmode === 'tui'\r\n\t\t\t? (await import('../dev/tui/tui.js')).createTuiRenderer(service, {\r\n\t\t\t\t\tcolor,\r\n\t\t\t\t\ttheme,\r\n\t\t\t\t\treducedMotion: prefersReducedMotion(),\r\n\t\t\t\t\tonThemeSave: (setting) => {\r\n\t\t\t\t\t\tif (!saveTheme(setting)) service.log('stars', 'warn', 'Could not save the theme preference.');\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t: (await import('../dev/tui/plain.js')).createPlainRenderer(service, { color });\r\n\r\n\tlet exiting: Promise<never> | null = null;\r\n\tconst shutdown = (code: ExitCode): Promise<never> => {\r\n\t\texiting ??= (async () => {\r\n\t\t\trenderer.stop();\r\n\t\t\t// A failing hook must not keep the bot running.\r\n\t\t\t// Behind any hook still running (an async `build:done`), and logged rather than thrown if it fails.\r\n\t\t\tawait service.runHook('dev:close', config);\r\n\t\t\tawait service.stop();\r\n\t\t\tlogFile?.close();\r\n\t\t\tprocess.exit(code);\r\n\t\t})();\r\n\t\treturn exiting;\r\n\t};\r\n\r\n\t// Like Turborepo: the first signal shuts down gracefully, a second one gives up waiting and kills everything.\r\n\tlet signalled = false;\r\n\tconst onSignal = (code: ExitCode) => () => {\r\n\t\tif (signalled) {\r\n\t\t\tprocess.stderr.write('\\nForcing shutdown.\\n');\r\n\t\t\tservice.kill();\r\n\t\t\tprocess.exit(code);\r\n\t\t}\r\n\r\n\t\tsignalled = true;\r\n\t\tvoid shutdown(code);\r\n\t\tprocess.stderr.write('\\nShutting down gracefully, press Ctrl+C again to force quit.\\n');\r\n\t};\r\n\r\n\tprocess.on('SIGINT', onSignal(ExitCode.Interrupted));\r\n\tprocess.on('SIGTERM', onSignal(ExitCode.Terminated));\r\n\tprocess.on('SIGHUP', onSignal(ExitCode.Terminated));\r\n\tif (process.platform !== 'win32') process.on('SIGUSR2', () => void service.restart('manual'));\r\n\r\n\tconst finished = renderer.start().then(() => shutdown(ExitCode.Ok));\r\n\ttry {\r\n\t\tawait prepareProject(config, hooks);\r\n\t\tawait service.start();\r\n\t\tawait hooks.callHook('dev:start', config);\r\n\t} catch (error) {\r\n\t\tservice.log('stars', 'error', error instanceof Error ? await renderCrashReport(error, config.root) : String(error));\r\n\t\tawait shutdown(ExitCode.Error);\r\n\t}\r\n\tawait finished;\r\n}\r\n\r\n/**\r\n * Resolves `dev.url`'s `localhost` to the address that is actually reachable (see {@link withResolvedLocalhost}),\r\n * the way Vite's dev server does when it starts. Only `stars dev` pays this DNS lookup; `stars info`/`stars build`\r\n * show or use the unresolved config as-is, since they never talk to the bot.\r\n */\r\nasync function resolveDevConfig(config: ResolvedStarsConfig): Promise<ResolvedStarsConfig> {\r\n\tif (!config.dev.url) return config;\r\n\r\n\tconst url = await withResolvedLocalhost(config.dev.url);\r\n\treturn url === config.dev.url ? config : { ...config, dev: { ...config.dev, url } };\r\n}\r\n\r\nexport default defineCommand({\r\n\tmeta: {\r\n\t\tname: 'dev',\r\n\t\tdescription: 'Build, run and restart the bot on changes'\r\n\t},\r\n\targs: {\r\n\t\t...projectArgs,\r\n\t\ttui: {\r\n\t\t\ttype: 'boolean',\r\n\t\t\tdescription: 'Interactive terminal UI; use --no-tui (or STARS_TUI=plain) for plain line output',\r\n\t\t\tdefault: true\r\n\t\t},\r\n\t\ttheme: {\r\n\t\t\ttype: 'string',\r\n\t\t\tdescription: `Colour theme of the interactive UI: ${THEME_SETTINGS.join(', ')} (or STARS_THEME; press T in the UI to pick one)`\r\n\t\t}\r\n\t},\r\n\tasync run({ args }) {\r\n\t\tawait runDev({ config: args.config, cwd: args.cwd, tui: args.tui ? undefined : false, theme: args.theme });\r\n\t}\r\n});\r\n"],"mappings":"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"}
@@ -50,10 +50,26 @@ const cliDiagnostics = defineDiagnostics({
50
50
  why: (p) => `"${p.name}" is not installed in ${p.root}`,
51
51
  fix: (p) => p.hint
52
52
  },
53
+ MODULE_FAILED: {
54
+ why: (p) => p.message,
55
+ fix: (p) => {
56
+ switch (p.reason) {
57
+ case "MODULE_LOAD_FAILED": return `Install "${p.module}" in the project, or fix its specifier in \`modules\` in stars.config.`;
58
+ case "MODULE_INCOMPATIBLE": return "Update the module or @wolfstar/http-framework so their versions match.";
59
+ case "MODULE_INVALID": return "Export the module with `defineModule` from @wolfstar/kit as the default export.";
60
+ case "MODULE_PLUGIN_INVALID": return "Pass `ctx.addPlugin` a package specifier, an absolute path or a `file:` URL, and JSON-serialisable options.";
61
+ default: return "Fix the error the module threw (see the cause), or remove it from `modules` in stars.config.";
62
+ }
63
+ }
64
+ },
65
+ MODULES_PRELOAD_REQUIRED: {
66
+ why: (p) => `The runtime plugins added by modules (${p.plugins}) are registered through \`node --import\` with build.tool "${p.tool}", which only \`stars dev\` does for you`,
67
+ fix: (_p) => "Start the production bot with `node --import ./.stars/modules.mjs <entry>`; `stars prepare` (and `stars build`) writes that file."
68
+ },
53
69
  CODEGEN_FAILED: { why: (p) => `i18next-type-generator exited with code ${p.code}${p.stderr ? `: ${p.stderr}` : ""}` }
54
70
  }
55
71
  });
56
72
 
57
73
  //#endregion
58
74
  export { cliDiagnostics as t };
59
- //# sourceMappingURL=diagnostics-CZBVxlpj.js.map
75
+ //# sourceMappingURL=diagnostics-3JRAy8Xj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics-3JRAy8Xj.js","names":[],"sources":["../src/utils/diagnostics.ts"],"sourcesContent":["import { defineDiagnostics } from 'nostics';\r\n\r\n/**\r\n * Structured, stable diagnostic codes for everything `@wolfstar/cli` itself rejects (as opposed to `stars.config.*`\r\n * validation, which is `@wolfstar/http-framework`'s own {@link import('@wolfstar/schema').configDiagnostics}).\r\n *\r\n * `reporters` stays empty: `runMain` (`src/run.ts`) is the single place that renders a caught `Diagnostic` to the\r\n * terminal (`formatError`) and picks its exit code (`exitCodeOf`), so nothing here should print on its own — a\r\n * command that calls e.g. `runBuild` directly (as the test suite does) gets a plain thrown value instead of stray\r\n * console output.\r\n *\r\n * `why` and `fix` are always given the same, fully-typed params object, even when one of them ignores part of it or\r\n * neither takes any: a bare `() => value` next to a typed sibling loses nostics' param-type inference (a zero-arg\r\n * function widens to `unknown` params, erasing the sibling's fields from the merged type).\r\n */\r\nexport const cliDiagnostics = defineDiagnostics({\r\n\tdocsBase: (code) => `https://stars-components.js.org/docs/cli/errors#${code.toLowerCase()}`,\r\n\treporters: [],\r\n\tcodes: {\r\n\t\tPREPARE_OUTDATED: {\r\n\t\t\twhy: (_p: {}) => 'The generated project files are out of date, run `stars prepare` to update it.'\r\n\t\t},\r\n\t\tDISCORD_TOKEN_MISSING: {\r\n\t\t\twhy: (_p: {}) => 'DISCORD_TOKEN is not set',\r\n\t\t\tfix: (_p: {}) => 'Set DISCORD_TOKEN in the environment or in the project .env file.'\r\n\t\t},\r\n\t\tDISCORD_APPLICATION_ID_MISSING: {\r\n\t\t\twhy: (_p: {}) => 'The Discord application id is not set',\r\n\t\t\tfix: (_p: {}) => 'Set DISCORD_APPLICATION_ID (or APPLICATION_ID) in the environment or in the project .env file.'\r\n\t\t},\r\n\t\tDISCORD_REQUEST_FAILED: {\r\n\t\t\twhy: (p: { status: number; detail: string }) => `Discord answered ${p.status}${p.detail ? `: ${p.detail}` : ''}`,\r\n\t\t\tfix: (p: { status: number; detail: string }) =>\r\n\t\t\t\tp.status === 401 ? 'Check DISCORD_TOKEN.' : 'Check the application id and the bot permissions.'\r\n\t\t},\r\n\t\tBUILD_FAILED: {\r\n\t\t\twhy: (p: { message: string }) => `Build failed${p.message ? `: ${p.message}` : ''}`\r\n\t\t},\r\n\t\tCOMMAND_NOT_FOUND: {\r\n\t\t\twhy: (p: { names: string }) => `No deployed command is named ${p.names}`,\r\n\t\t\tfix: (_p: { names: string }) => 'Run `stars commands list` to see what is deployed.'\r\n\t\t},\r\n\t\tABORTED: {\r\n\t\t\twhy: (_p: {}) => 'Aborted'\r\n\t\t},\r\n\t\tCONFIRMATION_REQUIRED: {\r\n\t\t\twhy: (_p: {}) => 'Refusing to delete commands without a confirmation',\r\n\t\t\tfix: (_p: {}) => 'Pass --yes to delete them, or --name to pick one, from a script.'\r\n\t\t},\r\n\t\tINVALID_THEME: {\r\n\t\t\twhy: (p: { theme: string; themes: string }) => `Unknown theme \\`${p.theme}\\`.`,\r\n\t\t\tfix: (p: { theme: string; themes: string }) => `Use one of: ${p.themes}.`\r\n\t\t},\r\n\t\tCODEGEN_OUTDATED: {\r\n\t\t\twhy: (_p: {}) => 'Generated files are out of date, run `stars codegen` to update them.'\r\n\t\t},\r\n\t\tDEPENDENCY_MISSING: {\r\n\t\t\twhy: (p: { name: string; root: string; hint: string }) => `\"${p.name}\" is not installed in ${p.root}`,\r\n\t\t\tfix: (p: { name: string; root: string; hint: string }) => p.hint\r\n\t\t},\r\n\t\tMODULE_FAILED: {\r\n\t\t\twhy: (p: { module: string; reason: string; message: string }) => p.message,\r\n\t\t\tfix: (p: { module: string; reason: string; message: string }) => {\r\n\t\t\t\tswitch (p.reason) {\r\n\t\t\t\t\tcase 'MODULE_LOAD_FAILED':\r\n\t\t\t\t\t\treturn `Install \"${p.module}\" in the project, or fix its specifier in \\`modules\\` in stars.config.`;\r\n\t\t\t\t\tcase 'MODULE_INCOMPATIBLE':\r\n\t\t\t\t\t\treturn 'Update the module or @wolfstar/http-framework so their versions match.';\r\n\t\t\t\t\tcase 'MODULE_INVALID':\r\n\t\t\t\t\t\treturn 'Export the module with `defineModule` from @wolfstar/kit as the default export.';\r\n\t\t\t\t\tcase 'MODULE_PLUGIN_INVALID':\r\n\t\t\t\t\t\treturn 'Pass `ctx.addPlugin` a package specifier, an absolute path or a `file:` URL, and JSON-serialisable options.';\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\treturn 'Fix the error the module threw (see the cause), or remove it from `modules` in stars.config.';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\tMODULES_PRELOAD_REQUIRED: {\r\n\t\t\twhy: (p: { tool: string; plugins: string }) =>\r\n\t\t\t\t`The runtime plugins added by modules (${p.plugins}) are registered through \\`node --import\\` with build.tool \"${p.tool}\", which only \\`stars dev\\` does for you`,\r\n\t\t\tfix: (_p: { tool: string; plugins: string }) =>\r\n\t\t\t\t'Start the production bot with `node --import ./.stars/modules.mjs <entry>`; `stars prepare` (and `stars build`) writes that file.'\r\n\t\t},\r\n\t\tCODEGEN_FAILED: {\r\n\t\t\twhy: (p: { code: number | null; stderr: string }) => `i18next-type-generator exited with code ${p.code}${p.stderr ? `: ${p.stderr}` : ''}`\r\n\t\t}\r\n\t}\r\n});\r\n\r\nexport type CliDiagnosticCode = keyof typeof cliDiagnostics;\r\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,iBAAiB,kBAAkB;CAC/C,WAAW,SAAS,mDAAmD,KAAK,YAAY;CACxF,WAAW,CAAC;CACZ,OAAO;EACN,kBAAkB,EACjB,MAAM,OAAW,iFAClB;EACA,uBAAuB;GACtB,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,gCAAgC;GAC/B,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,wBAAwB;GACvB,MAAM,MAA0C,oBAAoB,EAAE,SAAS,EAAE,SAAS,KAAK,EAAE,WAAW;GAC5G,MAAM,MACL,EAAE,WAAW,MAAM,yBAAyB;EAC9C;EACA,cAAc,EACb,MAAM,MAA2B,eAAe,EAAE,UAAU,KAAK,EAAE,YAAY,KAChF;EACA,mBAAmB;GAClB,MAAM,MAAyB,gCAAgC,EAAE;GACjE,MAAM,OAA0B;EACjC;EACA,SAAS,EACR,MAAM,OAAW,UAClB;EACA,uBAAuB;GACtB,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,eAAe;GACd,MAAM,MAAyC,mBAAmB,EAAE,MAAM;GAC1E,MAAM,MAAyC,eAAe,EAAE,OAAO;EACxE;EACA,kBAAkB,EACjB,MAAM,OAAW,uEAClB;EACA,oBAAoB;GACnB,MAAM,MAAoD,IAAI,EAAE,KAAK,wBAAwB,EAAE;GAC/F,MAAM,MAAoD,EAAE;EAC7D;EACA,eAAe;GACd,MAAM,MAA2D,EAAE;GACnE,MAAM,MAA2D;IAChE,QAAQ,EAAE,QAAV;KACC,KAAK,sBACJ,OAAO,YAAY,EAAE,OAAO;KAC7B,KAAK,uBACJ,OAAO;KACR,KAAK,kBACJ,OAAO;KACR,KAAK,yBACJ,OAAO;KACR,SACC,OAAO;IACT;GACD;EACD;EACA,0BAA0B;GACzB,MAAM,MACL,yCAAyC,EAAE,QAAQ,8DAA8D,EAAE,KAAK;GACzH,MAAM,OACL;EACF;EACA,gBAAgB,EACf,MAAM,MAA+C,2CAA2C,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,WAAW,KACvI;CACD;AACD,CAAC"}
@@ -16,7 +16,10 @@ const ExitCode = {
16
16
  /** Every `stars.config.*` diagnostic code maps to {@link ExitCode.InvalidConfig}; everything else defaults to `Error`. */
17
17
  const CONFIG_DIAGNOSTIC_CODES = new Set(Object.keys(configDiagnostics));
18
18
  /** CLI-local diagnostic codes whose exit code isn't the default {@link ExitCode.Error}. */
19
- const CLI_EXIT_CODES = { BUILD_FAILED: ExitCode.BuildFailed };
19
+ const CLI_EXIT_CODES = {
20
+ BUILD_FAILED: ExitCode.BuildFailed,
21
+ MODULE_FAILED: ExitCode.InvalidConfig
22
+ };
20
23
  /**
21
24
  * Formats an error for the terminal: a `Diagnostic` (from `stars.config.*` validation, via
22
25
  * `@wolfstar/schema`'s `configDiagnostics`, or from the CLI's own `cliDiagnostics`) renders through
@@ -53,4 +56,4 @@ function exitCodeOf(error) {
53
56
 
54
57
  //#endregion
55
58
  export { renderCrashReport as i, exitCodeOf as n, formatError as r, ExitCode as t };
56
- //# sourceMappingURL=errors-Crt4hu0b.js.map
59
+ //# sourceMappingURL=errors-COFWKKKw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors-COFWKKKw.js","names":[],"sources":["../src/utils/errors.ts"],"sourcesContent":["import { configDiagnostics } from '@wolfstar/schema';\r\nimport { createColors } from 'colorette';\r\nimport { Diagnostic } from 'nostics';\r\nimport { ansiFormatter } from 'nostics/formatters/ansi';\r\nimport { shouldUseColor } from './output-mode.js';\r\n\r\nexport const ExitCode = {\r\n\tOk: 0,\r\n\tError: 1,\r\n\tInvalidConfig: 2,\r\n\tBuildFailed: 3,\r\n\tInterrupted: 130,\r\n\tTerminated: 143\r\n} as const;\r\n\r\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\r\n\r\n/** Every `stars.config.*` diagnostic code maps to {@link ExitCode.InvalidConfig}; everything else defaults to `Error`. */\r\nconst CONFIG_DIAGNOSTIC_CODES = new Set<string>(Object.keys(configDiagnostics));\r\n\r\n/** CLI-local diagnostic codes whose exit code isn't the default {@link ExitCode.Error}. */\r\nconst CLI_EXIT_CODES: Partial<Record<string, ExitCode>> = {\r\n\tBUILD_FAILED: ExitCode.BuildFailed,\r\n\tMODULE_FAILED: ExitCode.InvalidConfig\r\n};\r\n\r\n/**\r\n * Formats an error for the terminal: a `Diagnostic` (from `stars.config.*` validation, via\r\n * `@wolfstar/schema`'s `configDiagnostics`, or from the CLI's own `cliDiagnostics`) renders through\r\n * nostics' own ANSI formatter — message, `fix`, `sources` and `docs` — everything else falls back to a crash report.\r\n */\r\nexport async function formatError(error: unknown): Promise<string> {\r\n\tif (error instanceof Diagnostic) {\r\n\t\tconst colors = createColors({ useColor: shouldUseColor() });\r\n\t\treturn ansiFormatter(colors)(error);\r\n\t}\r\n\r\n\t// citty's CLIError (unknown command, missing argument): the message is enough.\r\n\tif (error instanceof Error && error.name === 'CLIError') return error.message;\r\n\tif (error instanceof Error) return renderCrashReport(error);\r\n\treturn String(error);\r\n}\r\n\r\n/**\r\n * Renders an unexpected error (a bug, not something the CLI already explains through a `Diagnostic`) as a\r\n * sourcemapped, syntax-highlighted report — frames and a snippet of the original source instead of a stack trace\r\n * pointing into the bundled `dist/cli.js`.\r\n */\r\nexport async function renderCrashReport(error: unknown, cwd: string = process.cwd()): Promise<string> {\r\n\tconst { createReport, fsLoader, renderAnsi } = await import('my-bad');\r\n\tconst report = await createReport(error, { cwd, loaders: [fsLoader()] });\r\n\treturn renderAnsi(report, { cwd });\r\n}\r\n\r\nexport function exitCodeOf(error: unknown): ExitCode {\r\n\tif (error instanceof Diagnostic) {\r\n\t\tif (CONFIG_DIAGNOSTIC_CODES.has(error.code)) return ExitCode.InvalidConfig;\r\n\t\treturn CLI_EXIT_CODES[error.code] ?? ExitCode.Error;\r\n\t}\r\n\r\n\treturn ExitCode.Error;\r\n}\r\n"],"mappings":";;;;;;;AAMA,MAAa,WAAW;CACvB,IAAI;CACJ,OAAO;CACP,eAAe;CACf,aAAa;CACb,aAAa;CACb,YAAY;AACb;;AAKA,MAAM,0BAA0B,IAAI,IAAY,OAAO,KAAK,iBAAiB,CAAC;;AAG9E,MAAM,iBAAoD;CACzD,cAAc,SAAS;CACvB,eAAe,SAAS;AACzB;;;;;;AAOA,eAAsB,YAAY,OAAiC;CAClE,IAAI,iBAAiB,YAAY;EAChC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,EAAE,CAAC;EAC1D,OAAO,cAAc,MAAM,CAAC,CAAC,KAAK;CACnC;CAGA,IAAI,iBAAiB,SAAS,MAAM,SAAS,YAAY,OAAO,MAAM;CACtE,IAAI,iBAAiB,OAAO,OAAO,kBAAkB,KAAK;CAC1D,OAAO,OAAO,KAAK;AACpB;;;;;;AAOA,eAAsB,kBAAkB,OAAgB,MAAc,QAAQ,IAAI,GAAoB;CACrG,MAAM,EAAE,cAAc,UAAU,eAAe,MAAM,OAAO;CAE5D,OAAO,WAAW,MADG,aAAa,OAAO;EAAE;EAAK,SAAS,CAAC,SAAS,CAAC;CAAE,CAAC,GAC7C,EAAE,IAAI,CAAC;AAClC;AAEA,SAAgB,WAAW,OAA0B;CACpD,IAAI,iBAAiB,YAAY;EAChC,IAAI,wBAAwB,IAAI,MAAM,IAAI,GAAG,OAAO,SAAS;EAC7D,OAAO,eAAe,MAAM,SAAS,SAAS;CAC/C;CAEA,OAAO,SAAS;AACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"external-CxFKxwi3.js","names":[],"sources":["../src/builders/external.ts"],"sourcesContent":["import type { ResolvedStarsConfig, StarsBuildTool } from '@wolfstar/schema';\nimport { dirname } from 'node:path';\nimport { EventEmitter } from 'node:events';\nimport { displayPath } from '@wolfstar/schema';\nimport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\n\n/**\n * Runs no build of its own: the project drives one itself (`vite dev`, `vite build --watch`, a task runner, …) and\n * this only watches what that build writes, restarting the bot whenever the output changes.\n *\n * This is what `experimental.enableExternalVite` selects — the CLI stays out of the build's way but keeps the rest\n * of `stars dev` (restarts, health, tunnel, type checking, the panel) working.\n */\nexport class ExternalBuilder extends EventEmitter<BuilderEvents> implements Builder {\n\tpublic readonly tool: StarsBuildTool;\n\t#watcher: { close(): Promise<void> } | null = null;\n\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\n\t\tsuper();\n\t\tthis.tool = config.build.tool;\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 target = dirname(this.config.build.output);\n\t\tthis.emit('log', 'info', `Watching ${displayPath(this.config.root, target)} for an external build`);\n\n\t\tconst watcher = watch(target, { ignored: [...this.config.dev.ignore], ignoreInitial: true, cwd: this.config.root });\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":";;;;;;;;;;;;AAaA,IAAa,kBAAb,cAAqC,aAA+C;CAI/C;CAHpC,AAAgB;CAChB,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;EAEnC,KAAK,OAAO,OAAO,MAAM;CAC1B;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,SAAS,QAAQ,KAAK,OAAO,MAAM,MAAM;EAC/C,KAAK,KAAK,OAAO,QAAQ,YAAY,YAAY,KAAK,OAAO,MAAM,MAAM,EAAE,uBAAuB;EAElG,MAAM,UAAU,MAAM,QAAQ;GAAE,SAAS,CAAC,GAAG,KAAK,OAAO,IAAI,MAAM;GAAG,eAAe;GAAM,KAAK,KAAK,OAAO;EAAK,CAAC;EAClH,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":"external-CxFKxwi3.js","names":[],"sources":["../src/builders/external.ts"],"sourcesContent":["import type { ResolvedStarsConfig, StarsBuildTool } from '@wolfstar/schema';\r\nimport { dirname } from 'node:path';\r\nimport { EventEmitter } from 'node:events';\r\nimport { displayPath } from '@wolfstar/schema';\r\nimport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\r\n\r\n/**\r\n * Runs no build of its own: the project drives one itself (`vite dev`, `vite build --watch`, a task runner, …) and\r\n * this only watches what that build writes, restarting the bot whenever the output changes.\r\n *\r\n * This is what `experimental.enableExternalVite` selects — the CLI stays out of the build's way but keeps the rest\r\n * of `stars dev` (restarts, health, tunnel, type checking, the panel) working.\r\n */\r\nexport class ExternalBuilder extends EventEmitter<BuilderEvents> implements Builder {\r\n\tpublic readonly tool: StarsBuildTool;\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.tool = config.build.tool;\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 target = dirname(this.config.build.output);\r\n\t\tthis.emit('log', 'info', `Watching ${displayPath(this.config.root, target)} for an external build`);\r\n\r\n\t\tconst watcher = watch(target, { ignored: [...this.config.dev.ignore], ignoreInitial: true, cwd: this.config.root });\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":";;;;;;;;;;;;AAaA,IAAa,kBAAb,cAAqC,aAA+C;CAI/C;CAHpC,AAAgB;CAChB,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;EAEnC,KAAK,OAAO,OAAO,MAAM;CAC1B;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,SAAS,QAAQ,KAAK,OAAO,MAAM,MAAM;EAC/C,KAAK,KAAK,OAAO,QAAQ,YAAY,YAAY,KAAK,OAAO,MAAM,MAAM,EAAE,uBAAuB;EAElG,MAAM,UAAU,MAAM,QAAQ;GAAE,SAAS,CAAC,GAAG,KAAK,OAAO,IAAI,MAAM;GAAG,eAAe;GAAM,KAAK,KAAK,OAAO;EAAK,CAAC;EAClH,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":"framework-auto-imports-Gu_PXSyr.js","names":["resolveModule"],"sources":["../src/utils/framework-auto-imports.ts"],"sourcesContent":["/**\n * `@wolfstar/http-framework/auto-imports`, resolved from the project's own installation rather than declared as a\n * dependency of this package — the way `@nuxt/cli` resolves the project's own `nuxt` without depending on it.\n * `@wolfstar/http-framework` depends on `@wolfstar/cli` (for its `stars` binary), so the reverse dependency here\n * would make the two packages depend on each other.\n *\n * `mlly`'s `resolve` (the same tool `@wolfstar/http-framework/auto-imports` itself already uses to scan preset\n * packages, see its `scanPresetImports`) anchors the resolution at the project root, respecting its `exports`\n * `import` condition. A plain `require.resolve` anchored the same way (as `tsdown`/`vite`/`nitro` are resolved\n * elsewhere in this package, see `utils/project.ts`) does not work here: those are dual CJS/ESM packages, while\n * `@wolfstar/http-framework` is ESM-only, so a CJS-style resolver reports its `./auto-imports` subpath as\n * unavailable even though it exists. Anchoring at the project root is also what makes this find the project's real,\n * already-built `@wolfstar/http-framework` even though pnpm workspace packages are linked directly (not hoisted or\n * nested under `.pnpm`), which is what makes a plain bare-specifier `import()` from this package's own location\n * unable to reach it.\n *\n * The fallback bare specifier is for this repository's own tests, which alias it to source without a build; a\n * variable (not a string literal) in the `import()` call keeps TypeScript from requiring `@wolfstar/http-framework`\n * to resolve at type-check time too, since only a literal argument triggers module resolution.\n */\nimport type { ResolvedImportsConfig } from '@wolfstar/schema';\nimport { resolve as resolveModule } from 'mlly';\nimport { pathToFileURL } from 'node:url';\n\nconst AUTO_IMPORTS_SPECIFIER = '@wolfstar/http-framework/auto-imports';\n\nexport interface AutoImportsPluginOptions extends Pick<ResolvedImportsConfig, 'dirs' | 'presets' | 'exclude' | 'dts'> {\n\t/** Absolute project root, used to resolve `presets` against the project's own `node_modules`. */\n\troot: string;\n}\n\ninterface AutoImportsModule {\n\tautoImports(options: AutoImportsPluginOptions): Promise<unknown>;\n\tgenerateAutoImportsDts(options: Omit<AutoImportsPluginOptions, 'dts'>): Promise<string>;\n}\n\n/** Loads `@wolfstar/http-framework/auto-imports` from the project at `root`. */\nexport async function loadAutoImportsModule(root: string): Promise<AutoImportsModule> {\n\tconst url = pathToFileURL(`${root}/package.json`).href;\n\tconst target = await resolveModule(AUTO_IMPORTS_SPECIFIER, { url }).catch(() => AUTO_IMPORTS_SPECIFIER);\n\treturn (await import(target)) as AutoImportsModule;\n}\n"],"mappings":";;;;AAwBA,MAAM,yBAAyB;;AAa/B,eAAsB,sBAAsB,MAA0C;CACrF,MAAM,MAAM,cAAc,GAAG,KAAK,cAAc,CAAC,CAAC;CAElD,OAAQ,MAAM,OAAO,MADAA,QAAc,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,sBAAsB;AAEvG"}
1
+ {"version":3,"file":"framework-auto-imports-Gu_PXSyr.js","names":["resolveModule"],"sources":["../src/utils/framework-auto-imports.ts"],"sourcesContent":["/**\r\n * `@wolfstar/http-framework/auto-imports`, resolved from the project's own installation rather than declared as a\r\n * dependency of this package — the way `@nuxt/cli` resolves the project's own `nuxt` without depending on it.\r\n * `@wolfstar/http-framework` depends on `@wolfstar/cli` (for its `stars` binary), so the reverse dependency here\r\n * would make the two packages depend on each other.\r\n *\r\n * `mlly`'s `resolve` (the same tool `@wolfstar/http-framework/auto-imports` itself already uses to scan preset\r\n * packages, see its `scanPresetImports`) anchors the resolution at the project root, respecting its `exports`\r\n * `import` condition. A plain `require.resolve` anchored the same way (as `tsdown`/`vite`/`nitro` are resolved\r\n * elsewhere in this package, see `utils/project.ts`) does not work here: those are dual CJS/ESM packages, while\r\n * `@wolfstar/http-framework` is ESM-only, so a CJS-style resolver reports its `./auto-imports` subpath as\r\n * unavailable even though it exists. Anchoring at the project root is also what makes this find the project's real,\r\n * already-built `@wolfstar/http-framework` even though pnpm workspace packages are linked directly (not hoisted or\r\n * nested under `.pnpm`), which is what makes a plain bare-specifier `import()` from this package's own location\r\n * unable to reach it.\r\n *\r\n * The fallback bare specifier is for this repository's own tests, which alias it to source without a build; a\r\n * variable (not a string literal) in the `import()` call keeps TypeScript from requiring `@wolfstar/http-framework`\r\n * to resolve at type-check time too, since only a literal argument triggers module resolution.\r\n */\r\nimport type { ResolvedImportsConfig } from '@wolfstar/schema';\r\nimport { resolve as resolveModule } from 'mlly';\r\nimport { pathToFileURL } from 'node:url';\r\n\r\nconst AUTO_IMPORTS_SPECIFIER = '@wolfstar/http-framework/auto-imports';\r\n\r\nexport interface AutoImportsPluginOptions extends Pick<ResolvedImportsConfig, 'dirs' | 'presets' | 'exclude' | 'dts'> {\r\n\t/** Absolute project root, used to resolve `presets` against the project's own `node_modules`. */\r\n\troot: string;\r\n}\r\n\r\ninterface AutoImportsModule {\r\n\tautoImports(options: AutoImportsPluginOptions): Promise<unknown>;\r\n\tgenerateAutoImportsDts(options: Omit<AutoImportsPluginOptions, 'dts'>): Promise<string>;\r\n}\r\n\r\n/** Loads `@wolfstar/http-framework/auto-imports` from the project at `root`. */\r\nexport async function loadAutoImportsModule(root: string): Promise<AutoImportsModule> {\r\n\tconst url = pathToFileURL(`${root}/package.json`).href;\r\n\tconst target = await resolveModule(AUTO_IMPORTS_SPECIFIER, { url }).catch(() => AUTO_IMPORTS_SPECIFIER);\r\n\treturn (await import(target)) as AutoImportsModule;\r\n}\r\n"],"mappings":";;;;AAwBA,MAAM,yBAAyB;;AAa/B,eAAsB,sBAAsB,MAA0C;CACrF,MAAM,MAAM,cAAc,GAAG,KAAK,cAAc,CAAC,CAAC;CAElD,OAAQ,MAAM,OAAO,MADAA,QAAc,wBAAwB,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,sBAAsB;AAEvG"}