@wolfstar/cli 2.7.0-next-20261009115919 → 2.7.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 (37) hide show
  1. package/dist/{_shared-Bqw7h4O0.js → _shared-BLXTNq89.js} +2 -2
  2. package/dist/{_shared-Bqw7h4O0.js.map → _shared-BLXTNq89.js.map} +1 -1
  3. package/dist/{build-BYlgPxAE.js → build-DVF5vcSS.js} +3 -3
  4. package/dist/{build-BYlgPxAE.js.map → build-DVF5vcSS.js.map} +1 -1
  5. package/dist/cli.js +1 -1
  6. package/dist/{codegen-CiDXuBHu.js → codegen-DI263aSx.js} +3 -3
  7. package/dist/{codegen-CiDXuBHu.js.map → codegen-DI263aSx.js.map} +1 -1
  8. package/dist/commands-Bd6Dp5Y0.js +3 -0
  9. package/dist/{commands-CURkZI0f.js → commands-CtucWY2d.js} +4 -4
  10. package/dist/{commands-CURkZI0f.js.map → commands-CtucWY2d.js.map} +1 -1
  11. package/dist/commands-D7SFy2_3.js +16 -0
  12. package/dist/{commands-Chpk8BR8.js.map → commands-D7SFy2_3.js.map} +1 -1
  13. package/dist/{completions-DBipETDu.js → completions-D_scEKH1.js} +2 -2
  14. package/dist/{completions-DBipETDu.js.map → completions-D_scEKH1.js.map} +1 -1
  15. package/dist/{dev-GvuLQzWu.js → dev-CnXgPQ8F.js} +4 -4
  16. package/dist/{dev-GvuLQzWu.js.map → dev-CnXgPQ8F.js.map} +1 -1
  17. package/dist/{doctor-C_lTMEjG.js → doctor-BYRkkc5l.js} +4 -4
  18. package/dist/{doctor-C_lTMEjG.js.map → doctor-BYRkkc5l.js.map} +1 -1
  19. package/dist/{hooks-DqlScRZA.js → hooks-CzV2YRoJ.js} +4 -3
  20. package/dist/hooks-CzV2YRoJ.js.map +1 -0
  21. package/dist/index.js +1 -1
  22. package/dist/{info-BX-As3qN.js → info-DLo6tZT5.js} +3 -3
  23. package/dist/{info-BX-As3qN.js.map → info-DLo6tZT5.js.map} +1 -1
  24. package/dist/{local-commands-DkWl97zR.js → local-commands-DKnabUnX.js} +2 -2
  25. package/dist/{local-commands-DkWl97zR.js.map → local-commands-DKnabUnX.js.map} +1 -1
  26. package/dist/{prepare-6abxyJeD.js → prepare-DnNsv3TU.js} +3 -3
  27. package/dist/{prepare-6abxyJeD.js.map → prepare-DnNsv3TU.js.map} +1 -1
  28. package/dist/{run-DlctD5rb.js → run-BVBqR6hV.js} +2 -2
  29. package/dist/{run-DlctD5rb.js.map → run-BVBqR6hV.js.map} +1 -1
  30. package/dist/{tunnel-D3WxypOt.js → tunnel-DlFjqUE7.js} +2 -2
  31. package/dist/{tunnel-D3WxypOt.js.map → tunnel-DlFjqUE7.js.map} +1 -1
  32. package/dist/{typecheck-BIscCUNQ.js → typecheck-B2aRagKp.js} +3 -3
  33. package/dist/{typecheck-BIscCUNQ.js.map → typecheck-B2aRagKp.js.map} +1 -1
  34. package/package.json +5 -5
  35. package/dist/commands-Chpk8BR8.js +0 -16
  36. package/dist/commands-R2m3xweq.js +0 -3
  37. package/dist/hooks-DqlScRZA.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { t as readOwnPackageJson } from "./version-BzclCE19.js";
2
2
  import { i as shouldUseColor, r as resolveOutputMode } from "./output-mode-Bp7Da8vJ.js";
3
3
  import { t as findInstalledVersion } from "./project-EJyKro-M.js";
4
- import { d as projectArgs, f as resolveCwd, n as loadProject, o as modulesPreloadWarning, t as applyEnvOptions } from "./hooks-DqlScRZA.js";
5
- import { n as describeQuickTunnel } from "./tunnel-D3WxypOt.js";
4
+ import { d as projectArgs, f as resolveCwd, n as loadProject, o as modulesPreloadWarning, t as applyEnvOptions } from "./hooks-CzV2YRoJ.js";
5
+ import { n as describeQuickTunnel } from "./tunnel-DlFjqUE7.js";
6
6
  import { defineCommand } from "citty";
7
7
  import { relative } from "node:path";
8
8
  import { displayPath } from "@wolfstar/schema";
@@ -162,4 +162,4 @@ var info_default = defineCommand({
162
162
 
163
163
  //#endregion
164
164
  export { info_default as default };
165
- //# sourceMappingURL=info-BX-As3qN.js.map
165
+ //# sourceMappingURL=info-DLo6tZT5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"info-BX-As3qN.js","names":[],"sources":["../src/commands/info.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig, type StarsEnvSetupOptions } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { arch, platform } from 'node:os';\nimport { relative } from 'node:path';\nimport { describeQuickTunnel } from '../dev/tunnel.js';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\nimport { modulesPreloadWarning } from '../utils/modules.js';\nimport { resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\nimport { findInstalledVersion } from '../utils/project.js';\nimport { readOwnPackageJson } from '../utils/version.js';\n\nexport interface InfoOptions extends ProjectArgs {\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport interface ProjectInfo {\n\tcli: { version: string; node: string; platform: string; outputMode: 'tui' | 'plain' };\n\tproject: {\n\t\tcwd: string;\n\t\troot: string;\n\t\tconfigFile: string | null;\n\t\tname: string | null;\n\t\tversion: string | null;\n\t\tentry: string;\n\t\tframeworkVersion: string | null;\n\t};\n\tbuild: ResolvedStarsConfig['build'];\n\tdev: ResolvedStarsConfig['dev'];\n\tcodegen: ResolvedStarsConfig['codegen'];\n\timports: ResolvedStarsConfig['imports'];\n\texperimental: ResolvedStarsConfig['experimental'];\n\tfuture: ResolvedStarsConfig['future'];\n\tenv: ResolvedStarsConfig['env'];\n\t/** The names of the hooks registered in `stars.config`, flattened (`build:done`). */\n\thooks: string[];\n\t/** The installed modules, and the runtime plugins they registered (`module → export from package`). */\n\tmodules: { installed: string[]; plugins: string[] };\n\t/** Non-fatal configuration diagnostics, as `CODE: message`. */\n\twarnings: string[];\n\t/**\n\t * The option names set in the `tsdown`/`vite` blocks. Only the names: the values hold plugins and callbacks,\n\t * which neither serialize to JSON nor read usefully on a terminal.\n\t */\n\toptions: { tsdown: string[]; vite: string[] };\n}\n\nexport function collectInfo(config: ResolvedStarsConfig): ProjectInfo {\n\treturn {\n\t\tcli: {\n\t\t\tversion: readOwnPackageJson().version,\n\t\t\tnode: process.version,\n\t\t\tplatform: `${platform()} ${arch()}`,\n\t\t\toutputMode: resolveOutputMode()\n\t\t},\n\t\tproject: {\n\t\t\tcwd: config.cwd,\n\t\t\troot: config.root,\n\t\t\tconfigFile: config.configFile,\n\t\t\tname: config.packageJson?.name ?? null,\n\t\t\tversion: config.packageJson?.version ?? null,\n\t\t\tentry: config.entry,\n\t\t\tframeworkVersion: findInstalledVersion(config.root, '@wolfstar/http-framework')\n\t\t},\n\t\tbuild: config.build,\n\t\tdev: config.dev,\n\t\tcodegen: config.codegen,\n\t\timports: config.imports,\n\t\texperimental: config.experimental,\n\t\tfuture: config.future,\n\t\tenv: config.env,\n\t\thooks: Object.keys(config.hooks),\n\t\tmodules: {\n\t\t\tinstalled: (config.runtime?.modules ?? []).map((module) => module.name),\n\t\t\tplugins: (config.runtime?.plugins ?? []).map((plugin) => `${plugin.module} → ${plugin.export} from ${plugin.from}`)\n\t\t},\n\t\twarnings: [...config.warnings, modulesPreloadWarning(config)]\n\t\t\t.filter((warning) => warning !== null)\n\t\t\t.map((warning) => `${warning.code}: ${warning.message}`),\n\t\toptions: { tsdown: Object.keys(config.tsdown), vite: Object.keys(config.vite) }\n\t};\n}\n\nexport function formatInfo(info: ProjectInfo, useColor: boolean): string {\n\tconst colors = createColors({ useColor });\n\tconst { root } = info.project;\n\tconst show = (path: string | null) => (path === null ? colors.dim('none') : displayPath(root, path));\n\tconst row = (label: string, value: string) => ` ${colors.dim(label.padEnd(12))}${value}`;\n\tconst section = (title: string, rows: string[]) => [colors.bold(title), ...rows].join('\\n');\n\n\treturn [\n\t\tsection(`stars ${colors.green(`v${info.cli.version}`)}`, [\n\t\t\trow('node', info.cli.node),\n\t\t\trow('platform', info.cli.platform),\n\t\t\trow('output', info.cli.outputMode),\n\t\t\trow(\n\t\t\t\t'framework',\n\t\t\t\tinfo.project.frameworkVersion\n\t\t\t\t\t? `@wolfstar/http-framework v${info.project.frameworkVersion}`\n\t\t\t\t\t: colors.yellow('@wolfstar/http-framework not installed')\n\t\t\t)\n\t\t]),\n\t\tsection('Project', [\n\t\t\trow(\n\t\t\t\t'name',\n\t\t\t\tinfo.project.name\n\t\t\t\t\t? `${info.project.name}${info.project.version ? colors.dim(` v${info.project.version}`) : ''}`\n\t\t\t\t\t: colors.dim('unnamed')\n\t\t\t),\n\t\t\trow('root', root),\n\t\t\trow(\n\t\t\t\t'config',\n\t\t\t\tinfo.project.configFile ? relative(root, info.project.configFile) || info.project.configFile : colors.dim('none (defaults)')\n\t\t\t),\n\t\t\trow('entry', show(info.project.entry))\n\t\t]),\n\t\tsection('Build', [\n\t\t\trow('tool', info.build.tool),\n\t\t\t// Which file the build tool is configured from: its own, or this project's `stars.config`.\n\t\t\trow('config', info.build.configFile ? show(info.build.configFile) : colors.dim('stars.config')),\n\t\t\trow('options', describeOptions(info, colors)),\n\t\t\trow('outDir', show(info.build.outDir)),\n\t\t\trow('tsconfig', show(info.build.tsconfig)),\n\t\t\t// Everything `stars typecheck` checks: the generated app and node projects from compatibility version 6 (a `tsc`\n\t\t\t// or `none` project keeps its own tsconfig for the bot and gets the node one on top).\n\t\t\trow('typechecks', info.dev.typecheck.projects.length > 0 ? info.dev.typecheck.projects.map(show).join(', ') : colors.dim('none')),\n\t\t\trow('runs', show(info.build.output))\n\t\t]),\n\t\tsection('Dev', [\n\t\t\trow('watch', info.dev.watch.map(show).join(', ')),\n\t\t\trow('debounce', `${info.dev.debounce}ms`),\n\t\t\trow('node args', info.dev.nodeArgs.join(' ') || colors.dim('none')),\n\t\t\trow('args', info.dev.args.join(' ') || colors.dim('none')),\n\t\t\trow('url', info.dev.url ?? colors.dim('unknown, set dev.url or HTTP_PORT')),\n\t\t\trow('health', info.dev.health ?? colors.dim('none')),\n\t\t\trow(\n\t\t\t\t'typecheck',\n\t\t\t\tinfo.dev.typecheck.enabled ? `${info.dev.typecheck.checker} → ${show(info.dev.typecheck.tsconfig)}` : colors.dim('disabled')\n\t\t\t),\n\t\t\trow('tunnel', describeTunnel(info.dev.tunnel, colors)),\n\t\t\trow('log file', info.dev.logFile ? show(info.dev.logFile) : colors.dim('disabled')),\n\t\t\trow('log dir', info.dev.logs.dir ? `${show(info.dev.logs.dir)} (keeps ${info.dev.logs.keep})` : colors.dim('disabled')),\n\t\t\trow('layout', info.dev.layout),\n\t\t\trow('mouse', info.dev.mouse ? 'clickable dashboard' : colors.dim('left to the terminal')),\n\t\t\trow('channels', info.dev.logs.channels?.join(', ') ?? colors.dim('all')),\n\t\t\trow('levels', info.dev.logs.levels.join(', ')),\n\t\t\trow('commands', `refresh: ${info.dev.commands.refresh}`),\n\t\t\trow('hmr', info.dev.hmr ? 'left to the bot when it hot reloads' : colors.dim('always restart'))\n\t\t]),\n\t\tsection('Codegen', [\n\t\t\trow('i18n', info.codegen.i18n ? `${show(info.codegen.i18n.locales)} → ${show(info.codegen.i18n.output)}` : colors.dim('disabled')),\n\t\t\trow('commands', info.codegen.commands ? show(info.codegen.commands.output) : colors.dim('disabled'))\n\t\t]),\n\t\tsection('Future', [\n\t\t\trow('compat', `v${info.future.compatibilityVersion} defaults`),\n\t\t\t...info.warnings.map((warning) => row('warning', colors.yellow(warning)))\n\t\t]),\n\t\tsection('Env', [row('register', info.env.enabled ? colors.green(describeEnvOptions(info.env.options)) : colors.dim('disabled'))]),\n\t\tsection('Hooks', [row('registered', info.hooks.join(', ') || colors.dim('none'))]),\n\t\tsection('Modules', [\n\t\t\trow('installed', info.modules.installed.join(', ') || colors.dim('none')),\n\t\t\t...info.modules.plugins.map((plugin) => row('plugin', plugin))\n\t\t]),\n\t\tsection('Experimental', [\n\t\t\trow('vite', flag(info.experimental.enableVite, colors)),\n\t\t\trow('nitro', flag(info.experimental.enableNitro, colors)),\n\t\t\t...(info.experimental.enableNitro ? [row('nitro preset', info.experimental.nitro.preset)] : []),\n\t\t\trow('external', flag(info.experimental.enableExternalVite, colors))\n\t\t]),\n\t\tsection('Imports', [\n\t\t\trow('auto', info.imports.enabled ? colors.green('enabled') : colors.dim('disabled')),\n\t\t\trow('dirs', info.imports.dirs.map(show).join(', ')),\n\t\t\trow('presets', info.imports.presets.join(', ') || colors.dim('none')),\n\t\t\trow('dts', show(info.imports.dts))\n\t\t])\n\t].join('\\n\\n');\n}\n\nfunction describeOptions(info: ProjectInfo, colors: ReturnType<typeof createColors>): string {\n\tconst names = info.build.tool === 'vite' ? info.options.vite : info.options.tsdown;\n\treturn names.length > 0 ? names.join(', ') : colors.dim('none');\n}\n\nfunction describeEnvOptions(options: Readonly<StarsEnvSetupOptions>): string {\n\tconst entries = Object.entries(options).map(([key, value]) => `${key} ${String(value)}`);\n\treturn entries.length > 0 ? `enabled (${entries.join(', ')})` : 'enabled';\n}\n\nfunction flag(enabled: boolean, colors: ReturnType<typeof createColors>): string {\n\treturn enabled ? colors.green('enabled') : colors.dim('disabled');\n}\n\nfunction describeTunnel(tunnel: ResolvedStarsConfig['dev']['tunnel'], colors: ReturnType<typeof createColors>): string {\n\tswitch (tunnel.mode) {\n\t\tcase 'quick':\n\t\t\treturn describeQuickTunnel(tunnel);\n\t\tcase 'url':\n\t\t\treturn tunnel.url;\n\t\tdefault:\n\t\t\treturn colors.dim('disabled');\n\t}\n}\n\nexport async function runInfo(options: InfoOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\t// What the build would use: `env:options` may change the env files.\n\tconst config = await applyEnvOptions(project.config, project.hooks);\n\tconst info = collectInfo(config);\n\tstdout.write(`${options.json ? JSON.stringify(info, null, 2) : formatInfo(info, shouldUseColor())}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'info',\n\t\tdescription: 'Print the resolved project configuration and environment'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runInfo({ config: args.config, cwd: args.cwd, json: args.json });\n\t}\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"info-DLo6tZT5.js","names":[],"sources":["../src/commands/info.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig, type StarsEnvSetupOptions } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { arch, platform } from 'node:os';\nimport { relative } from 'node:path';\nimport { describeQuickTunnel } from '../dev/tunnel.js';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\nimport { modulesPreloadWarning } from '../utils/modules.js';\nimport { resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\nimport { findInstalledVersion } from '../utils/project.js';\nimport { readOwnPackageJson } from '../utils/version.js';\n\nexport interface InfoOptions extends ProjectArgs {\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport interface ProjectInfo {\n\tcli: { version: string; node: string; platform: string; outputMode: 'tui' | 'plain' };\n\tproject: {\n\t\tcwd: string;\n\t\troot: string;\n\t\tconfigFile: string | null;\n\t\tname: string | null;\n\t\tversion: string | null;\n\t\tentry: string;\n\t\tframeworkVersion: string | null;\n\t};\n\tbuild: ResolvedStarsConfig['build'];\n\tdev: ResolvedStarsConfig['dev'];\n\tcodegen: ResolvedStarsConfig['codegen'];\n\timports: ResolvedStarsConfig['imports'];\n\texperimental: ResolvedStarsConfig['experimental'];\n\tfuture: ResolvedStarsConfig['future'];\n\tenv: ResolvedStarsConfig['env'];\n\t/** The names of the hooks registered in `stars.config`, flattened (`build:done`). */\n\thooks: string[];\n\t/** The installed modules, and the runtime plugins they registered (`module → export from package`). */\n\tmodules: { installed: string[]; plugins: string[] };\n\t/** Non-fatal configuration diagnostics, as `CODE: message`. */\n\twarnings: string[];\n\t/**\n\t * The option names set in the `tsdown`/`vite` blocks. Only the names: the values hold plugins and callbacks,\n\t * which neither serialize to JSON nor read usefully on a terminal.\n\t */\n\toptions: { tsdown: string[]; vite: string[] };\n}\n\nexport function collectInfo(config: ResolvedStarsConfig): ProjectInfo {\n\treturn {\n\t\tcli: {\n\t\t\tversion: readOwnPackageJson().version,\n\t\t\tnode: process.version,\n\t\t\tplatform: `${platform()} ${arch()}`,\n\t\t\toutputMode: resolveOutputMode()\n\t\t},\n\t\tproject: {\n\t\t\tcwd: config.cwd,\n\t\t\troot: config.root,\n\t\t\tconfigFile: config.configFile,\n\t\t\tname: config.packageJson?.name ?? null,\n\t\t\tversion: config.packageJson?.version ?? null,\n\t\t\tentry: config.entry,\n\t\t\tframeworkVersion: findInstalledVersion(config.root, '@wolfstar/http-framework')\n\t\t},\n\t\tbuild: config.build,\n\t\tdev: config.dev,\n\t\tcodegen: config.codegen,\n\t\timports: config.imports,\n\t\texperimental: config.experimental,\n\t\tfuture: config.future,\n\t\tenv: config.env,\n\t\thooks: Object.keys(config.hooks),\n\t\tmodules: {\n\t\t\tinstalled: (config.runtime?.modules ?? []).map((module) => module.name),\n\t\t\tplugins: (config.runtime?.plugins ?? []).map((plugin) => `${plugin.module} → ${plugin.export} from ${plugin.from}`)\n\t\t},\n\t\twarnings: [...config.warnings, modulesPreloadWarning(config)]\n\t\t\t.filter((warning) => warning !== null)\n\t\t\t.map((warning) => `${warning.code}: ${warning.message}`),\n\t\toptions: { tsdown: Object.keys(config.tsdown), vite: Object.keys(config.vite) }\n\t};\n}\n\nexport function formatInfo(info: ProjectInfo, useColor: boolean): string {\n\tconst colors = createColors({ useColor });\n\tconst { root } = info.project;\n\tconst show = (path: string | null) => (path === null ? colors.dim('none') : displayPath(root, path));\n\tconst row = (label: string, value: string) => ` ${colors.dim(label.padEnd(12))}${value}`;\n\tconst section = (title: string, rows: string[]) => [colors.bold(title), ...rows].join('\\n');\n\n\treturn [\n\t\tsection(`stars ${colors.green(`v${info.cli.version}`)}`, [\n\t\t\trow('node', info.cli.node),\n\t\t\trow('platform', info.cli.platform),\n\t\t\trow('output', info.cli.outputMode),\n\t\t\trow(\n\t\t\t\t'framework',\n\t\t\t\tinfo.project.frameworkVersion\n\t\t\t\t\t? `@wolfstar/http-framework v${info.project.frameworkVersion}`\n\t\t\t\t\t: colors.yellow('@wolfstar/http-framework not installed')\n\t\t\t)\n\t\t]),\n\t\tsection('Project', [\n\t\t\trow(\n\t\t\t\t'name',\n\t\t\t\tinfo.project.name\n\t\t\t\t\t? `${info.project.name}${info.project.version ? colors.dim(` v${info.project.version}`) : ''}`\n\t\t\t\t\t: colors.dim('unnamed')\n\t\t\t),\n\t\t\trow('root', root),\n\t\t\trow(\n\t\t\t\t'config',\n\t\t\t\tinfo.project.configFile ? relative(root, info.project.configFile) || info.project.configFile : colors.dim('none (defaults)')\n\t\t\t),\n\t\t\trow('entry', show(info.project.entry))\n\t\t]),\n\t\tsection('Build', [\n\t\t\trow('tool', info.build.tool),\n\t\t\t// Which file the build tool is configured from: its own, or this project's `stars.config`.\n\t\t\trow('config', info.build.configFile ? show(info.build.configFile) : colors.dim('stars.config')),\n\t\t\trow('options', describeOptions(info, colors)),\n\t\t\trow('outDir', show(info.build.outDir)),\n\t\t\trow('tsconfig', show(info.build.tsconfig)),\n\t\t\t// Everything `stars typecheck` checks: the generated app and node projects from compatibility version 6 (a `tsc`\n\t\t\t// or `none` project keeps its own tsconfig for the bot and gets the node one on top).\n\t\t\trow('typechecks', info.dev.typecheck.projects.length > 0 ? info.dev.typecheck.projects.map(show).join(', ') : colors.dim('none')),\n\t\t\trow('runs', show(info.build.output))\n\t\t]),\n\t\tsection('Dev', [\n\t\t\trow('watch', info.dev.watch.map(show).join(', ')),\n\t\t\trow('debounce', `${info.dev.debounce}ms`),\n\t\t\trow('node args', info.dev.nodeArgs.join(' ') || colors.dim('none')),\n\t\t\trow('args', info.dev.args.join(' ') || colors.dim('none')),\n\t\t\trow('url', info.dev.url ?? colors.dim('unknown, set dev.url or HTTP_PORT')),\n\t\t\trow('health', info.dev.health ?? colors.dim('none')),\n\t\t\trow(\n\t\t\t\t'typecheck',\n\t\t\t\tinfo.dev.typecheck.enabled ? `${info.dev.typecheck.checker} → ${show(info.dev.typecheck.tsconfig)}` : colors.dim('disabled')\n\t\t\t),\n\t\t\trow('tunnel', describeTunnel(info.dev.tunnel, colors)),\n\t\t\trow('log file', info.dev.logFile ? show(info.dev.logFile) : colors.dim('disabled')),\n\t\t\trow('log dir', info.dev.logs.dir ? `${show(info.dev.logs.dir)} (keeps ${info.dev.logs.keep})` : colors.dim('disabled')),\n\t\t\trow('layout', info.dev.layout),\n\t\t\trow('mouse', info.dev.mouse ? 'clickable dashboard' : colors.dim('left to the terminal')),\n\t\t\trow('channels', info.dev.logs.channels?.join(', ') ?? colors.dim('all')),\n\t\t\trow('levels', info.dev.logs.levels.join(', ')),\n\t\t\trow('commands', `refresh: ${info.dev.commands.refresh}`),\n\t\t\trow('hmr', info.dev.hmr ? 'left to the bot when it hot reloads' : colors.dim('always restart'))\n\t\t]),\n\t\tsection('Codegen', [\n\t\t\trow('i18n', info.codegen.i18n ? `${show(info.codegen.i18n.locales)} → ${show(info.codegen.i18n.output)}` : colors.dim('disabled')),\n\t\t\trow('commands', info.codegen.commands ? show(info.codegen.commands.output) : colors.dim('disabled'))\n\t\t]),\n\t\tsection('Future', [\n\t\t\trow('compat', `v${info.future.compatibilityVersion} defaults`),\n\t\t\t...info.warnings.map((warning) => row('warning', colors.yellow(warning)))\n\t\t]),\n\t\tsection('Env', [row('register', info.env.enabled ? colors.green(describeEnvOptions(info.env.options)) : colors.dim('disabled'))]),\n\t\tsection('Hooks', [row('registered', info.hooks.join(', ') || colors.dim('none'))]),\n\t\tsection('Modules', [\n\t\t\trow('installed', info.modules.installed.join(', ') || colors.dim('none')),\n\t\t\t...info.modules.plugins.map((plugin) => row('plugin', plugin))\n\t\t]),\n\t\tsection('Experimental', [\n\t\t\trow('vite', flag(info.experimental.enableVite, colors)),\n\t\t\trow('nitro', flag(info.experimental.enableNitro, colors)),\n\t\t\t...(info.experimental.enableNitro ? [row('nitro preset', info.experimental.nitro.preset)] : []),\n\t\t\trow('external', flag(info.experimental.enableExternalVite, colors))\n\t\t]),\n\t\tsection('Imports', [\n\t\t\trow('auto', info.imports.enabled ? colors.green('enabled') : colors.dim('disabled')),\n\t\t\trow('dirs', info.imports.dirs.map(show).join(', ')),\n\t\t\trow('presets', info.imports.presets.join(', ') || colors.dim('none')),\n\t\t\trow('dts', show(info.imports.dts))\n\t\t])\n\t].join('\\n\\n');\n}\n\nfunction describeOptions(info: ProjectInfo, colors: ReturnType<typeof createColors>): string {\n\tconst names = info.build.tool === 'vite' ? info.options.vite : info.options.tsdown;\n\treturn names.length > 0 ? names.join(', ') : colors.dim('none');\n}\n\nfunction describeEnvOptions(options: Readonly<StarsEnvSetupOptions>): string {\n\tconst entries = Object.entries(options).map(([key, value]) => `${key} ${String(value)}`);\n\treturn entries.length > 0 ? `enabled (${entries.join(', ')})` : 'enabled';\n}\n\nfunction flag(enabled: boolean, colors: ReturnType<typeof createColors>): string {\n\treturn enabled ? colors.green('enabled') : colors.dim('disabled');\n}\n\nfunction describeTunnel(tunnel: ResolvedStarsConfig['dev']['tunnel'], colors: ReturnType<typeof createColors>): string {\n\tswitch (tunnel.mode) {\n\t\tcase 'quick':\n\t\t\treturn describeQuickTunnel(tunnel);\n\t\tcase 'url':\n\t\t\treturn tunnel.url;\n\t\tdefault:\n\t\t\treturn colors.dim('disabled');\n\t}\n}\n\nexport async function runInfo(options: InfoOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\t// What the build would use: `env:options` may change the env files.\n\tconst config = await applyEnvOptions(project.config, project.hooks);\n\tconst info = collectInfo(config);\n\tstdout.write(`${options.json ? JSON.stringify(info, null, 2) : formatInfo(info, shouldUseColor())}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'info',\n\t\tdescription: 'Print the resolved project configuration and environment'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runInfo({ config: args.config, cwd: args.cwd, json: args.json });\n\t}\n});\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as cliDiagnostics } from "./diagnostics-BKc--u_3.js";
2
- import { c as envImportArgs, l as moduleImportArgs } from "./hooks-DqlScRZA.js";
2
+ import { c as envImportArgs, l as moduleImportArgs } from "./hooks-CzV2YRoJ.js";
3
3
  import { i as bridgeImportArgs, o as parseBridgeMessage, r as DUMP_ENV, t as BRIDGE_FRAMEWORK_VERSION } from "./bridge-DQ3dZ9pm.js";
4
4
  import { existsSync } from "node:fs";
5
5
  import { displayPath } from "@wolfstar/schema";
@@ -92,4 +92,4 @@ async function readLocalCommands(config, options = {}) {
92
92
 
93
93
  //#endregion
94
94
  export { readLocalCommands as t };
95
- //# sourceMappingURL=local-commands-DkWl97zR.js.map
95
+ //# sourceMappingURL=local-commands-DKnabUnX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-commands-DkWl97zR.js","names":[],"sources":["../src/utils/local-commands.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { displayPath } from '@wolfstar/schema';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { BRIDGE_FRAMEWORK_VERSION, bridgeImportArgs, DUMP_ENV, parseBridgeMessage, type CommandSnapshot } from '../dev/bridge.js';\nimport { cliDiagnostics } from './diagnostics.js';\nimport { envImportArgs, moduleImportArgs } from './env-import.js';\n\nexport interface ReadLocalCommandsOptions {\n\t/** Milliseconds the bot gets to load its pieces. */\n\ttimeout?: number;\n}\n\n/**\n * The application commands the project defines, as the bot itself would register them.\n *\n * Commands are declared with builders and decorators that only exist once the bot's modules ran, so nothing short of\n * running them knows the answer. This starts the built bot with the dev bridge in its \"dump\" mode: it loads its\n * pieces, reports its registry over IPC and exits before it listens or talks to Discord.\n *\n * It is a plain start of the bot, not a `stars dev` session: `STARS_DEV` is not set, so commands a project only\n * registers while developing are not part of what `stars commands deploy` deploys.\n */\nexport async function readLocalCommands(config: ResolvedStarsConfig, options: ReadLocalCommandsOptions = {}): Promise<CommandSnapshot> {\n\tif (!existsSync(config.build.output)) {\n\t\tthrow cliDiagnostics.LOCAL_COMMANDS_UNAVAILABLE({\n\t\t\treason: `${displayPath(config.root, config.build.output)} does not exist`,\n\t\t\tfix: 'Run `stars build` first: the commands are read from the built bot.'\n\t\t});\n\t}\n\n\tconst bridge = bridgeImportArgs(config);\n\tif (bridge.length === 0) {\n\t\tthrow cliDiagnostics.LOCAL_COMMANDS_UNAVAILABLE({\n\t\t\treason: `@wolfstar/http-framework ${BRIDGE_FRAMEWORK_VERSION} or later is not installed in ${config.root}`,\n\t\t\tfix: `Install @wolfstar/http-framework@^${BRIDGE_FRAMEWORK_VERSION} in the project.`\n\t\t});\n\t}\n\n\tconst child = spawn(\n\t\tprocess.execPath,\n\t\t[...envImportArgs(config), ...moduleImportArgs(config), ...bridge, ...config.dev.nodeArgs, config.build.output, ...config.dev.args],\n\t\t{\n\t\t\tcwd: config.root,\n\t\t\t// The environment the commands are read under is the caller's: `NODE_ENV=production stars commands deploy`\n\t\t\t// deploys what a production start registers. Unset, it is development, like the project's env files.\n\t\t\tenv: { ...process.env, ...config.dev.env, NODE_ENV: process.env.NODE_ENV ?? 'development', [DUMP_ENV]: '1' },\n\t\t\tstdio: ['ignore', 'ignore', 'pipe', 'ipc'],\n\t\t\twindowsHide: true\n\t\t}\n\t);\n\n\treturn new Promise<CommandSnapshot>((resolve, reject) => {\n\t\tlet stderr = '';\n\t\tlet settled = false;\n\t\tconst finish = (action: () => void) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\taction();\n\t\t};\n\t\tconst unavailable = (reason: string) =>\n\t\t\tcliDiagnostics.LOCAL_COMMANDS_UNAVAILABLE({\n\t\t\t\treason,\n\t\t\t\tfix: 'Check that the bot starts with `stars dev`: it has to construct its `Client` and call `client.load()`.'\n\t\t\t});\n\n\t\tconst timer = setTimeout(() => {\n\t\t\tchild.kill('SIGKILL');\n\t\t\tfinish(() => reject(unavailable('the bot did not load its commands in time')));\n\t\t}, options.timeout ?? 30_000);\n\n\t\tchild.stderr?.on('data', (chunk: Buffer) => (stderr = `${stderr}${chunk.toString()}`.slice(-2000)));\n\t\tlet snapshot: CommandSnapshot | null = null;\n\t\tchild.on('message', (message) => {\n\t\t\tconst parsed = parseBridgeMessage(message);\n\t\t\tif (parsed?.type !== 'commands' || snapshot !== null) return;\n\t\t\tsnapshot = { global: parsed.global, guilds: parsed.guilds };\n\t\t\t// The bot exits on its own once the message is flushed. The answer waits for that: until then the process\n\t\t\t// still holds the project directory (its working directory), which Windows refuses to let go of.\n\t\t\tsetTimeout(() => child.kill('SIGKILL'), 2000).unref();\n\t\t});\n\t\tchild.once('error', (error) => finish(() => reject(unavailable(error.message))));\n\t\tchild.once('exit', (code) => {\n\t\t\tif (snapshot !== null) {\n\t\t\t\tconst commands = snapshot;\n\t\t\t\tfinish(() => resolve(commands));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst detail = stderr.trim().split('\\n').at(-1);\n\t\t\tfinish(() => reject(unavailable(`the bot exited with code ${code} before loading its commands${detail ? ` (${detail})` : ''}`)));\n\t\t});\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,eAAsB,kBAAkB,QAA6B,UAAoC,CAAC,GAA6B;CACtI,IAAI,CAAC,WAAW,OAAO,MAAM,MAAM,GAClC,MAAM,eAAe,2BAA2B;EAC/C,QAAQ,GAAG,YAAY,OAAO,MAAM,OAAO,MAAM,MAAM,EAAE;EACzD,KAAK;CACN,CAAC;CAGF,MAAM,SAAS,iBAAiB,MAAM;CACtC,IAAI,OAAO,WAAW,GACrB,MAAM,eAAe,2BAA2B;EAC/C,QAAQ,4BAA4B,yBAAyB,gCAAgC,OAAO;EACpG,KAAK,qCAAqC,yBAAyB;CACpE,CAAC;CAGF,MAAM,QAAQ,MACb,QAAQ,UACR;EAAC,GAAG,cAAc,MAAM;EAAG,GAAG,iBAAiB,MAAM;EAAG,GAAG;EAAQ,GAAG,OAAO,IAAI;EAAU,OAAO,MAAM;EAAQ,GAAG,OAAO,IAAI;CAAI,GAClI;EACC,KAAK,OAAO;EAGZ,KAAK;GAAE,GAAG,QAAQ;GAAK,GAAG,OAAO,IAAI;GAAK,UAAU,QAAQ,IAAI,YAAY;IAAgB,WAAW;EAAI;EAC3G,OAAO;GAAC;GAAU;GAAU;GAAQ;EAAK;EACzC,aAAa;CACd,CACD;CAEA,OAAO,IAAI,SAA0B,SAAS,WAAW;EACxD,IAAI,SAAS;EACb,IAAI,UAAU;EACd,MAAM,UAAU,WAAuB;GACtC,IAAI,SAAS;GACb,UAAU;GACV,aAAa,KAAK;GAClB,OAAO;EACR;EACA,MAAM,eAAe,WACpB,eAAe,2BAA2B;GACzC;GACA,KAAK;EACN,CAAC;EAEF,MAAM,QAAQ,iBAAiB;GAC9B,MAAM,KAAK,SAAS;GACpB,aAAa,OAAO,YAAY,2CAA2C,CAAC,CAAC;EAC9E,GAAG,QAAQ,WAAW,GAAM;EAE5B,MAAM,QAAQ,GAAG,SAAS,UAAmB,SAAS,GAAG,SAAS,MAAM,SAAS,IAAI,MAAM,IAAK,CAAE;EAClG,IAAI,WAAmC;EACvC,MAAM,GAAG,YAAY,YAAY;GAChC,MAAM,SAAS,mBAAmB,OAAO;GACzC,IAAI,QAAQ,SAAS,cAAc,aAAa,MAAM;GACtD,WAAW;IAAE,QAAQ,OAAO;IAAQ,QAAQ,OAAO;GAAO;GAG1D,iBAAiB,MAAM,KAAK,SAAS,GAAG,GAAI,CAAC,CAAC,MAAM;EACrD,CAAC;EACD,MAAM,KAAK,UAAU,UAAU,aAAa,OAAO,YAAY,MAAM,OAAO,CAAC,CAAC,CAAC;EAC/E,MAAM,KAAK,SAAS,SAAS;GAC5B,IAAI,aAAa,MAAM;IACtB,MAAM,WAAW;IACjB,aAAa,QAAQ,QAAQ,CAAC;IAC9B;GACD;GAEA,MAAM,SAAS,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE;GAC9C,aAAa,OAAO,YAAY,4BAA4B,KAAK,8BAA8B,SAAS,KAAK,OAAO,KAAK,IAAI,CAAC,CAAC;EAChI,CAAC;CACF,CAAC;AACF"}
1
+ {"version":3,"file":"local-commands-DKnabUnX.js","names":[],"sources":["../src/utils/local-commands.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { displayPath } from '@wolfstar/schema';\nimport { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { BRIDGE_FRAMEWORK_VERSION, bridgeImportArgs, DUMP_ENV, parseBridgeMessage, type CommandSnapshot } from '../dev/bridge.js';\nimport { cliDiagnostics } from './diagnostics.js';\nimport { envImportArgs, moduleImportArgs } from './env-import.js';\n\nexport interface ReadLocalCommandsOptions {\n\t/** Milliseconds the bot gets to load its pieces. */\n\ttimeout?: number;\n}\n\n/**\n * The application commands the project defines, as the bot itself would register them.\n *\n * Commands are declared with builders and decorators that only exist once the bot's modules ran, so nothing short of\n * running them knows the answer. This starts the built bot with the dev bridge in its \"dump\" mode: it loads its\n * pieces, reports its registry over IPC and exits before it listens or talks to Discord.\n *\n * It is a plain start of the bot, not a `stars dev` session: `STARS_DEV` is not set, so commands a project only\n * registers while developing are not part of what `stars commands deploy` deploys.\n */\nexport async function readLocalCommands(config: ResolvedStarsConfig, options: ReadLocalCommandsOptions = {}): Promise<CommandSnapshot> {\n\tif (!existsSync(config.build.output)) {\n\t\tthrow cliDiagnostics.LOCAL_COMMANDS_UNAVAILABLE({\n\t\t\treason: `${displayPath(config.root, config.build.output)} does not exist`,\n\t\t\tfix: 'Run `stars build` first: the commands are read from the built bot.'\n\t\t});\n\t}\n\n\tconst bridge = bridgeImportArgs(config);\n\tif (bridge.length === 0) {\n\t\tthrow cliDiagnostics.LOCAL_COMMANDS_UNAVAILABLE({\n\t\t\treason: `@wolfstar/http-framework ${BRIDGE_FRAMEWORK_VERSION} or later is not installed in ${config.root}`,\n\t\t\tfix: `Install @wolfstar/http-framework@^${BRIDGE_FRAMEWORK_VERSION} in the project.`\n\t\t});\n\t}\n\n\tconst child = spawn(\n\t\tprocess.execPath,\n\t\t[...envImportArgs(config), ...moduleImportArgs(config), ...bridge, ...config.dev.nodeArgs, config.build.output, ...config.dev.args],\n\t\t{\n\t\t\tcwd: config.root,\n\t\t\t// The environment the commands are read under is the caller's: `NODE_ENV=production stars commands deploy`\n\t\t\t// deploys what a production start registers. Unset, it is development, like the project's env files.\n\t\t\tenv: { ...process.env, ...config.dev.env, NODE_ENV: process.env.NODE_ENV ?? 'development', [DUMP_ENV]: '1' },\n\t\t\tstdio: ['ignore', 'ignore', 'pipe', 'ipc'],\n\t\t\twindowsHide: true\n\t\t}\n\t);\n\n\treturn new Promise<CommandSnapshot>((resolve, reject) => {\n\t\tlet stderr = '';\n\t\tlet settled = false;\n\t\tconst finish = (action: () => void) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\taction();\n\t\t};\n\t\tconst unavailable = (reason: string) =>\n\t\t\tcliDiagnostics.LOCAL_COMMANDS_UNAVAILABLE({\n\t\t\t\treason,\n\t\t\t\tfix: 'Check that the bot starts with `stars dev`: it has to construct its `Client` and call `client.load()`.'\n\t\t\t});\n\n\t\tconst timer = setTimeout(() => {\n\t\t\tchild.kill('SIGKILL');\n\t\t\tfinish(() => reject(unavailable('the bot did not load its commands in time')));\n\t\t}, options.timeout ?? 30_000);\n\n\t\tchild.stderr?.on('data', (chunk: Buffer) => (stderr = `${stderr}${chunk.toString()}`.slice(-2000)));\n\t\tlet snapshot: CommandSnapshot | null = null;\n\t\tchild.on('message', (message) => {\n\t\t\tconst parsed = parseBridgeMessage(message);\n\t\t\tif (parsed?.type !== 'commands' || snapshot !== null) return;\n\t\t\tsnapshot = { global: parsed.global, guilds: parsed.guilds };\n\t\t\t// The bot exits on its own once the message is flushed. The answer waits for that: until then the process\n\t\t\t// still holds the project directory (its working directory), which Windows refuses to let go of.\n\t\t\tsetTimeout(() => child.kill('SIGKILL'), 2000).unref();\n\t\t});\n\t\tchild.once('error', (error) => finish(() => reject(unavailable(error.message))));\n\t\tchild.once('exit', (code) => {\n\t\t\tif (snapshot !== null) {\n\t\t\t\tconst commands = snapshot;\n\t\t\t\tfinish(() => resolve(commands));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst detail = stderr.trim().split('\\n').at(-1);\n\t\t\tfinish(() => reject(unavailable(`the bot exited with code ${code} before loading its commands${detail ? ` (${detail})` : ''}`)));\n\t\t});\n\t});\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA,eAAsB,kBAAkB,QAA6B,UAAoC,CAAC,GAA6B;CACtI,IAAI,CAAC,WAAW,OAAO,MAAM,MAAM,GAClC,MAAM,eAAe,2BAA2B;EAC/C,QAAQ,GAAG,YAAY,OAAO,MAAM,OAAO,MAAM,MAAM,EAAE;EACzD,KAAK;CACN,CAAC;CAGF,MAAM,SAAS,iBAAiB,MAAM;CACtC,IAAI,OAAO,WAAW,GACrB,MAAM,eAAe,2BAA2B;EAC/C,QAAQ,4BAA4B,yBAAyB,gCAAgC,OAAO;EACpG,KAAK,qCAAqC,yBAAyB;CACpE,CAAC;CAGF,MAAM,QAAQ,MACb,QAAQ,UACR;EAAC,GAAG,cAAc,MAAM;EAAG,GAAG,iBAAiB,MAAM;EAAG,GAAG;EAAQ,GAAG,OAAO,IAAI;EAAU,OAAO,MAAM;EAAQ,GAAG,OAAO,IAAI;CAAI,GAClI;EACC,KAAK,OAAO;EAGZ,KAAK;GAAE,GAAG,QAAQ;GAAK,GAAG,OAAO,IAAI;GAAK,UAAU,QAAQ,IAAI,YAAY;IAAgB,WAAW;EAAI;EAC3G,OAAO;GAAC;GAAU;GAAU;GAAQ;EAAK;EACzC,aAAa;CACd,CACD;CAEA,OAAO,IAAI,SAA0B,SAAS,WAAW;EACxD,IAAI,SAAS;EACb,IAAI,UAAU;EACd,MAAM,UAAU,WAAuB;GACtC,IAAI,SAAS;GACb,UAAU;GACV,aAAa,KAAK;GAClB,OAAO;EACR;EACA,MAAM,eAAe,WACpB,eAAe,2BAA2B;GACzC;GACA,KAAK;EACN,CAAC;EAEF,MAAM,QAAQ,iBAAiB;GAC9B,MAAM,KAAK,SAAS;GACpB,aAAa,OAAO,YAAY,2CAA2C,CAAC,CAAC;EAC9E,GAAG,QAAQ,WAAW,GAAM;EAE5B,MAAM,QAAQ,GAAG,SAAS,UAAmB,SAAS,GAAG,SAAS,MAAM,SAAS,IAAI,MAAM,IAAK,CAAE;EAClG,IAAI,WAAmC;EACvC,MAAM,GAAG,YAAY,YAAY;GAChC,MAAM,SAAS,mBAAmB,OAAO;GACzC,IAAI,QAAQ,SAAS,cAAc,aAAa,MAAM;GACtD,WAAW;IAAE,QAAQ,OAAO;IAAQ,QAAQ,OAAO;GAAO;GAG1D,iBAAiB,MAAM,KAAK,SAAS,GAAG,GAAI,CAAC,CAAC,MAAM;EACrD,CAAC;EACD,MAAM,KAAK,UAAU,UAAU,aAAa,OAAO,YAAY,MAAM,OAAO,CAAC,CAAC,CAAC;EAC/E,MAAM,KAAK,SAAS,SAAS;GAC5B,IAAI,aAAa,MAAM;IACtB,MAAM,WAAW;IACjB,aAAa,QAAQ,QAAQ,CAAC;IAC9B;GACD;GAEA,MAAM,SAAS,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE;GAC9C,aAAa,OAAO,YAAY,4BAA4B,KAAK,8BAA8B,SAAS,KAAK,OAAO,KAAK,IAAI,CAAC,CAAC;EAChI,CAAC;CACF,CAAC;AACF"}
@@ -1,7 +1,7 @@
1
1
  import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
2
  import { t as cliDiagnostics } from "./diagnostics-BKc--u_3.js";
3
- import { d as projectArgs, f as resolveCwd, n as loadProject } from "./hooks-DqlScRZA.js";
4
- import { n as reportWarnings, t as prepareProject } from "./_shared-Bqw7h4O0.js";
3
+ import { d as projectArgs, f as resolveCwd, n as loadProject } from "./hooks-CzV2YRoJ.js";
4
+ import { n as reportWarnings, t as prepareProject } from "./_shared-BLXTNq89.js";
5
5
  import { defineCommand } from "citty";
6
6
  import { displayPath } from "@wolfstar/schema";
7
7
  import { createColors } from "colorette";
@@ -70,4 +70,4 @@ var prepare_default = defineCommand({
70
70
 
71
71
  //#endregion
72
72
  export { prepare_default as default };
73
- //# sourceMappingURL=prepare-6abxyJeD.js.map
73
+ //# sourceMappingURL=prepare-DnNsv3TU.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare-6abxyJeD.js","names":[],"sources":["../src/commands/prepare.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { loadProject } from '../utils/hooks.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport { prepareProject } from './_shared.js';\n\nexport interface PrepareTaskOptions extends ProjectArgs {\n\tcheck?: boolean;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\n/**\n * Generates `.stars/tsconfig.app.json` and `.stars/tsconfig.node.json` (a single `.stars/tsconfig.json` below\n * compatibility version 6) and `imports.dts` (see {@link StarsImportsConfig} in `@wolfstar/schema`), the way `nuxt\n * prepare` regenerates `.nuxt/imports.d.ts`. Run automatically by `stars dev` and `stars build` before the first\n * build; `--check` fails instead of writing, for CI.\n */\nexport async function runPrepare(options: PrepareTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { config, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(config, (text) => process.stderr.write(`${text}\\n`));\n\tconst result = await prepareProject(config, hooks, Boolean(options.check));\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n\t} else {\n\t\tfor (const file of result.tsconfigs) {\n\t\t\tconst paintConfig = file.status === 'outdated' ? colors.red : colors.green;\n\t\t\tconst label = file.name === 'tsconfig' ? 'tsconfig' : `tsconfig ${file.name}`;\n\t\t\tstdout.write(`${colors.dim('stars')} ${label}: ${paintConfig(file.status)} ${displayPath(config.root, file.path)}\\n`);\n\t\t}\n\t\tif (result.modules) {\n\t\t\tconst paint = result.modules.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} modules: ${paint(result.modules.status)} ${displayPath(config.root, result.modules.path)}\\n`);\n\t\t}\n\t\tif (result.enabled) {\n\t\t\tconst paint = result.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} imports: ${paint(result.status)} ${displayPath(config.root, result.dts)}\\n`);\n\t\t}\n\t}\n\n\tif (result.status === 'outdated' || result.tsconfigs.some((file) => file.status === 'outdated') || result.modules?.status === 'outdated') {\n\t\tthrow cliDiagnostics.PREPARE_OUTDATED({});\n\t}\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'prepare',\n\t\tdescription: 'Generate TypeScript configuration and auto imports declarations'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tcheck: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Fail when the generated files are out of date instead of writing it',\n\t\t\tdefault: false\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runPrepare({ config: args.config, cwd: args.cwd, check: args.check, json: args.json });\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,eAAsB,WAAW,SAA4C;CAC5E,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,KAAK,CAAC,QAAQ,KAAK,CAAC;CAC3E,MAAM,EAAE,QAAQ,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CACpG,MAAM,eAAe,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,CAAC;CACxE,MAAM,SAAS,MAAM,eAAe,QAAQ,OAAO,QAAQ,QAAQ,KAAK,CAAC;CAEzE,IAAI,QAAQ,MACX,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,GAAG;MAC7C;EACN,KAAK,MAAM,QAAQ,OAAO,WAAW;GACpC,MAAM,cAAc,KAAK,WAAW,aAAa,OAAO,MAAM,OAAO;GACrE,MAAM,QAAQ,KAAK,SAAS,aAAa,aAAa,YAAY,KAAK;GACvE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,MAAM,IAAI,YAAY,KAAK,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,KAAK,IAAI,EAAE,GAAG;EACrH;EACA,IAAI,OAAO,SAAS;GACnB,MAAM,QAAQ,OAAO,QAAQ,WAAW,aAAa,OAAO,MAAM,OAAO;GACzE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,YAAY,MAAM,OAAO,QAAQ,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,QAAQ,IAAI,EAAE,GAAG;EAClI;EACA,IAAI,OAAO,SAAS;GACnB,MAAM,QAAQ,OAAO,WAAW,aAAa,OAAO,MAAM,OAAO;GACjE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,YAAY,MAAM,OAAO,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,GAAG,EAAE,GAAG;EACjH;CACD;CAEA,IAAI,OAAO,WAAW,cAAc,OAAO,UAAU,MAAM,SAAS,KAAK,WAAW,UAAU,KAAK,OAAO,SAAS,WAAW,YAC7H,MAAM,eAAe,iBAAiB,CAAC,CAAC;AAE1C;AAEA,sBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM;EACL,GAAG;EACH,OAAO;GACN,MAAM;GACN,aAAa;GACb,SAAS;EACV;EACA,MAAM;GACL,MAAM;GACN,aAAa;GACb,SAAS;EACV;CACD;CACA,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,WAAW;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;GAAK,OAAO,KAAK;GAAO,MAAM,KAAK;EAAK,CAAC;CAC5F;AACD,CAAC"}
1
+ {"version":3,"file":"prepare-DnNsv3TU.js","names":[],"sources":["../src/commands/prepare.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { loadProject } from '../utils/hooks.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport { prepareProject } from './_shared.js';\n\nexport interface PrepareTaskOptions extends ProjectArgs {\n\tcheck?: boolean;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\n/**\n * Generates `.stars/tsconfig.app.json` and `.stars/tsconfig.node.json` (a single `.stars/tsconfig.json` below\n * compatibility version 6) and `imports.dts` (see {@link StarsImportsConfig} in `@wolfstar/schema`), the way `nuxt\n * prepare` regenerates `.nuxt/imports.d.ts`. Run automatically by `stars dev` and `stars build` before the first\n * build; `--check` fails instead of writing, for CI.\n */\nexport async function runPrepare(options: PrepareTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { config, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(config, (text) => process.stderr.write(`${text}\\n`));\n\tconst result = await prepareProject(config, hooks, Boolean(options.check));\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n\t} else {\n\t\tfor (const file of result.tsconfigs) {\n\t\t\tconst paintConfig = file.status === 'outdated' ? colors.red : colors.green;\n\t\t\tconst label = file.name === 'tsconfig' ? 'tsconfig' : `tsconfig ${file.name}`;\n\t\t\tstdout.write(`${colors.dim('stars')} ${label}: ${paintConfig(file.status)} ${displayPath(config.root, file.path)}\\n`);\n\t\t}\n\t\tif (result.modules) {\n\t\t\tconst paint = result.modules.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} modules: ${paint(result.modules.status)} ${displayPath(config.root, result.modules.path)}\\n`);\n\t\t}\n\t\tif (result.enabled) {\n\t\t\tconst paint = result.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} imports: ${paint(result.status)} ${displayPath(config.root, result.dts)}\\n`);\n\t\t}\n\t}\n\n\tif (result.status === 'outdated' || result.tsconfigs.some((file) => file.status === 'outdated') || result.modules?.status === 'outdated') {\n\t\tthrow cliDiagnostics.PREPARE_OUTDATED({});\n\t}\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'prepare',\n\t\tdescription: 'Generate TypeScript configuration and auto imports declarations'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tcheck: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Fail when the generated files are out of date instead of writing it',\n\t\t\tdefault: false\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runPrepare({ config: args.config, cwd: args.cwd, check: args.check, json: args.json });\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;;AAuBA,eAAsB,WAAW,SAA4C;CAC5E,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,KAAK,CAAC,QAAQ,KAAK,CAAC;CAC3E,MAAM,EAAE,QAAQ,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CACpG,MAAM,eAAe,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,CAAC;CACxE,MAAM,SAAS,MAAM,eAAe,QAAQ,OAAO,QAAQ,QAAQ,KAAK,CAAC;CAEzE,IAAI,QAAQ,MACX,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,GAAG;MAC7C;EACN,KAAK,MAAM,QAAQ,OAAO,WAAW;GACpC,MAAM,cAAc,KAAK,WAAW,aAAa,OAAO,MAAM,OAAO;GACrE,MAAM,QAAQ,KAAK,SAAS,aAAa,aAAa,YAAY,KAAK;GACvE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,MAAM,IAAI,YAAY,KAAK,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,KAAK,IAAI,EAAE,GAAG;EACrH;EACA,IAAI,OAAO,SAAS;GACnB,MAAM,QAAQ,OAAO,QAAQ,WAAW,aAAa,OAAO,MAAM,OAAO;GACzE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,YAAY,MAAM,OAAO,QAAQ,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,QAAQ,IAAI,EAAE,GAAG;EAClI;EACA,IAAI,OAAO,SAAS;GACnB,MAAM,QAAQ,OAAO,WAAW,aAAa,OAAO,MAAM,OAAO;GACjE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,YAAY,MAAM,OAAO,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,GAAG,EAAE,GAAG;EACjH;CACD;CAEA,IAAI,OAAO,WAAW,cAAc,OAAO,UAAU,MAAM,SAAS,KAAK,WAAW,UAAU,KAAK,OAAO,SAAS,WAAW,YAC7H,MAAM,eAAe,iBAAiB,CAAC,CAAC;AAE1C;AAEA,sBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM;EACL,GAAG;EACH,OAAO;GACN,MAAM;GACN,aAAa;GACb,SAAS;EACV;EACA,MAAM;GACL,MAAM;GACN,aAAa;GACb,SAAS;EACV;CACD;CACA,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,WAAW;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;GAAK,OAAO,KAAK;GAAO,MAAM,KAAK;EAAK,CAAC;CAC5F;AACD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { t as commands } from "./commands-Chpk8BR8.js";
1
+ import { t as commands } from "./commands-D7SFy2_3.js";
2
2
  import { t as readOwnPackageJson } from "./version-BzclCE19.js";
3
3
  import { n as exitCodeOf, r as formatError } from "./errors-COFWKKKw.js";
4
4
  import { defineCommand, renderUsage, runCommand } from "citty";
@@ -52,4 +52,4 @@ async function runMain(argv = process.argv.slice(2)) {
52
52
 
53
53
  //#endregion
54
54
  export { runMain as t };
55
- //# sourceMappingURL=run-DlctD5rb.js.map
55
+ //# sourceMappingURL=run-BVBqR6hV.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-DlctD5rb.js","names":["_runCommand"],"sources":["../src/main.ts","../src/run.ts"],"sourcesContent":["import { defineCommand, type CommandDef } from 'citty';\nimport { commands } from './commands/index.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\nconst packageJson = readOwnPackageJson();\n\nexport const main = defineCommand({\n\tmeta: {\n\t\tname: 'stars',\n\t\tversion: packageJson.version,\n\t\tdescription: packageJson.description\n\t},\n\tsubCommands: commands\n}) as AnyCommand;\n","import { renderUsage, runCommand as _runCommand, type CommandDef } from 'citty';\nimport process from 'node:process';\nimport { commands } from './commands/index.js';\nimport { main } from './main.js';\nimport { exitCodeOf, formatError } from './utils/errors.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\n/**\n * Walks the command names of `stars <command> [<subcommand>] --help` so nested commands (`stars commands clean`)\n * render their own usage instead of their parent's.\n */\nasync function resolveHelpTarget(names: string[]): Promise<AnyCommand | null> {\n\tconst [first, ...rest] = names;\n\tif (!first || !Object.hasOwn(commands, first)) return null;\n\n\tlet command = await commands[first]!();\n\tfor (const name of rest) {\n\t\tconst resolved = typeof command.subCommands === 'function' ? await command.subCommands() : await command.subCommands;\n\t\tconst child: unknown = (resolved as Record<string, unknown> | undefined)?.[name];\n\t\tif (!child) break;\n\t\tcommand = (typeof child === 'function' ? await child() : child) as AnyCommand;\n\t}\n\n\treturn command;\n}\n\nexport async function runMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n\tif (argv.includes('--version') || argv.includes('-V')) {\n\t\tconsole.log(readOwnPackageJson().version);\n\t\tprocess.exit(0);\n\t}\n\n\tif (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {\n\t\t// citty's showUsage logs through consola, which is muted in some environments; render and print directly.\n\t\tconst command = await resolveHelpTarget(argv.filter((argument) => !argument.startsWith('-')));\n\t\tconsole.log(await (command ? renderUsage(command, main) : renderUsage(main)));\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tawait _runCommand(main, { rawArgs: argv });\n\t} catch (error) {\n\t\tconsole.error(await formatError(error));\n\t\tprocess.exit(exitCodeOf(error));\n\t}\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc,mBAAmB;AAEvC,MAAa,OAAO,cAAc;CACjC,MAAM;EACL,MAAM;EACN,SAAS,YAAY;EACrB,aAAa,YAAY;CAC1B;CACA,aAAa;AACd,CAAC;;;;;;;;ACFD,eAAe,kBAAkB,OAA6C;CAC7E,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO,UAAU,KAAK,GAAG,OAAO;CAEtD,IAAI,UAAU,MAAM,SAAS,MAAM,CAAE;CACrC,KAAK,MAAM,QAAQ,MAAM;EAExB,MAAM,SADW,OAAO,QAAQ,gBAAgB,aAAa,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,YACzE,GAA2C;EAC3E,IAAI,CAAC,OAAO;EACZ,UAAW,OAAO,UAAU,aAAa,MAAM,MAAM,IAAI;CAC1D;CAEA,OAAO;AACR;AAEA,eAAsB,QAAQ,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;CACpF,IAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI,GAAG;EACtD,QAAQ,IAAI,mBAAmB,CAAC,CAAC,OAAO;EACxC,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI,KAAK,WAAW,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;EAExE,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,aAAa,CAAC,SAAS,WAAW,GAAG,CAAC,CAAC;EAC5F,QAAQ,IAAI,OAAO,UAAU,YAAY,SAAS,IAAI,IAAI,YAAY,IAAI,EAAE;EAC5E,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI;EACH,MAAMA,WAAY,MAAM,EAAE,SAAS,KAAK,CAAC;CAC1C,SAAS,OAAO;EACf,QAAQ,MAAM,MAAM,YAAY,KAAK,CAAC;EACtC,QAAQ,KAAK,WAAW,KAAK,CAAC;CAC/B;AACD"}
1
+ {"version":3,"file":"run-BVBqR6hV.js","names":["_runCommand"],"sources":["../src/main.ts","../src/run.ts"],"sourcesContent":["import { defineCommand, type CommandDef } from 'citty';\nimport { commands } from './commands/index.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\nconst packageJson = readOwnPackageJson();\n\nexport const main = defineCommand({\n\tmeta: {\n\t\tname: 'stars',\n\t\tversion: packageJson.version,\n\t\tdescription: packageJson.description\n\t},\n\tsubCommands: commands\n}) as AnyCommand;\n","import { renderUsage, runCommand as _runCommand, type CommandDef } from 'citty';\nimport process from 'node:process';\nimport { commands } from './commands/index.js';\nimport { main } from './main.js';\nimport { exitCodeOf, formatError } from './utils/errors.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\n/**\n * Walks the command names of `stars <command> [<subcommand>] --help` so nested commands (`stars commands clean`)\n * render their own usage instead of their parent's.\n */\nasync function resolveHelpTarget(names: string[]): Promise<AnyCommand | null> {\n\tconst [first, ...rest] = names;\n\tif (!first || !Object.hasOwn(commands, first)) return null;\n\n\tlet command = await commands[first]!();\n\tfor (const name of rest) {\n\t\tconst resolved = typeof command.subCommands === 'function' ? await command.subCommands() : await command.subCommands;\n\t\tconst child: unknown = (resolved as Record<string, unknown> | undefined)?.[name];\n\t\tif (!child) break;\n\t\tcommand = (typeof child === 'function' ? await child() : child) as AnyCommand;\n\t}\n\n\treturn command;\n}\n\nexport async function runMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n\tif (argv.includes('--version') || argv.includes('-V')) {\n\t\tconsole.log(readOwnPackageJson().version);\n\t\tprocess.exit(0);\n\t}\n\n\tif (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {\n\t\t// citty's showUsage logs through consola, which is muted in some environments; render and print directly.\n\t\tconst command = await resolveHelpTarget(argv.filter((argument) => !argument.startsWith('-')));\n\t\tconsole.log(await (command ? renderUsage(command, main) : renderUsage(main)));\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tawait _runCommand(main, { rawArgs: argv });\n\t} catch (error) {\n\t\tconsole.error(await formatError(error));\n\t\tprocess.exit(exitCodeOf(error));\n\t}\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc,mBAAmB;AAEvC,MAAa,OAAO,cAAc;CACjC,MAAM;EACL,MAAM;EACN,SAAS,YAAY;EACrB,aAAa,YAAY;CAC1B;CACA,aAAa;AACd,CAAC;;;;;;;;ACFD,eAAe,kBAAkB,OAA6C;CAC7E,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO,UAAU,KAAK,GAAG,OAAO;CAEtD,IAAI,UAAU,MAAM,SAAS,MAAM,CAAE;CACrC,KAAK,MAAM,QAAQ,MAAM;EAExB,MAAM,SADW,OAAO,QAAQ,gBAAgB,aAAa,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,YACzE,GAA2C;EAC3E,IAAI,CAAC,OAAO;EACZ,UAAW,OAAO,UAAU,aAAa,MAAM,MAAM,IAAI;CAC1D;CAEA,OAAO;AACR;AAEA,eAAsB,QAAQ,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;CACpF,IAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI,GAAG;EACtD,QAAQ,IAAI,mBAAmB,CAAC,CAAC,OAAO;EACxC,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI,KAAK,WAAW,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;EAExE,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,aAAa,CAAC,SAAS,WAAW,GAAG,CAAC,CAAC;EAC5F,QAAQ,IAAI,OAAO,UAAU,YAAY,SAAS,IAAI,IAAI,YAAY,IAAI,EAAE;EAC5E,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI;EACH,MAAMA,WAAY,MAAM,EAAE,SAAS,KAAK,CAAC;CAC1C,SAAS,OAAO;EACf,QAAQ,MAAM,MAAM,YAAY,KAAK,CAAC;EACtC,QAAQ,KAAK,WAAW,KAAK,CAAC;CAC/B;AACD"}
@@ -1,6 +1,6 @@
1
1
  import { t as cliDiagnostics } from "./diagnostics-BKc--u_3.js";
2
2
  import { n as importFromProject } from "./project-EJyKro-M.js";
3
- import { a as readProjectVariable } from "./hooks-DqlScRZA.js";
3
+ import { a as readProjectVariable } from "./hooks-CzV2YRoJ.js";
4
4
  import { DEFAULT_TUNNEL_PROVIDER } from "@wolfstar/schema";
5
5
  import { Diagnostic } from "nostics";
6
6
  import { EventEmitter } from "node:events";
@@ -333,4 +333,4 @@ function describeError(error) {
333
333
 
334
334
  //#endregion
335
335
  export { NGROK_AUTHTOKEN_VARIABLE as a, readDiscordCredentials as i, describeQuickTunnel as n, NGROK_INSTALL_HINT as o, endpointUrl as r, NGROK_PACKAGE as s, Tunnel as t };
336
- //# sourceMappingURL=tunnel-D3WxypOt.js.map
336
+ //# sourceMappingURL=tunnel-DlFjqUE7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-D3WxypOt.js","names":[],"sources":["../src/dev/tunnel-providers.ts","../src/dev/tunnel.ts"],"sourcesContent":["import type { ResolvedStarsConfig, ResolvedTunnelConfig, StarsTunnelProvider } from '@wolfstar/schema';\nimport { startTunnel, type Tunnel as UntunTunnel } from 'untun';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { readProjectVariable } from '../utils/project-env.js';\nimport { importFromProject } from '../utils/project.js';\n\nexport type QuickTunnelConfig = Extract<ResolvedTunnelConfig, { mode: 'quick' }>;\n\n/** A tunnel a provider opened: where it is reachable, and how to take it down. */\nexport interface TunnelHandle {\n\tgetURL(): Promise<string>;\n\tclose(): Promise<void>;\n}\n\nexport interface TunnelOpenContext {\n\tconfig: ResolvedStarsConfig;\n\ttunnel: QuickTunnelConfig;\n\t/**\n\t * Reports that the tunnel ended without being closed. Returns whether it was handled (the tunnel was up and wanted),\n\t * so the provider knows whether it is done watching for it.\n\t */\n\tonStopped(error: Error): boolean;\n}\n\n/** A service that exposes the bot's local address publicly. */\nexport interface TunnelProvider {\n\treadonly name: StarsTunnelProvider;\n\t/**\n\t * Opens a tunnel to `target`. Resolves to `undefined` when the user cancelled the setup, and rejects when the tunnel\n\t * cannot be opened; either way nothing stays open.\n\t */\n\topen(target: string, context: TunnelOpenContext): Promise<TunnelHandle | undefined>;\n}\n\nconst SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const;\n\nfunction isCloudflaredExit(reason: unknown): reason is Error {\n\treturn reason instanceof Error && reason.message.startsWith('cloudflared exited (');\n}\n\n/**\n * The `cloudflared` quick tunnel, opened through `untun` (no account, a new hostname on every run).\n *\n * `untun` is wrapped rather than changed: it adds process signal listeners and leaves a promise unhandled whenever\n * `cloudflared` exits, both of which would end `stars dev`, so they are neutralised here.\n */\nexport class CloudflaredProvider implements TunnelProvider {\n\tpublic readonly name = 'cloudflared';\n\t#startTunnel: typeof startTunnel;\n\t#rejectionGuard: ((reason: unknown) => void) | null = null;\n\n\tpublic constructor(start: typeof startTunnel = startTunnel) {\n\t\tthis.#startTunnel = start;\n\t}\n\n\tpublic async open(target: string, context: TunnelOpenContext): Promise<TunnelHandle | undefined> {\n\t\tthis.#installRejectionGuard(context);\n\n\t\tlet tunnel: UntunTunnel | undefined;\n\t\ttry {\n\t\t\ttunnel = await this.#startWithoutSignalHandlers(target);\n\t\t} catch (error) {\n\t\t\tthis.#releaseRejectionGuard();\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (!tunnel) {\n\t\t\tthis.#releaseRejectionGuard();\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst opened = tunnel;\n\t\treturn {\n\t\t\tgetURL: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await opened.getURL();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.#releaseRejectionGuard();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t\tclose: async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait opened.close();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.#releaseRejectionGuard();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * `untun` adds its own `SIGINT`/`SIGTERM`/`SIGHUP` listeners that call `process.exit()` once cloudflared is closed,\n\t * which races `stars dev`'s graceful shutdown (it closes the tunnel through {@link TunnelHandle.close} anyway), so they\n\t * are removed.\n\t */\n\tasync #startWithoutSignalHandlers(target: string): Promise<UntunTunnel | undefined> {\n\t\tconst before = SIGNALS.map((signal) => new Set(process.listeners(signal)));\n\t\ttry {\n\t\t\treturn await this.#startTunnel({ url: target, acceptCloudflareNotice: true });\n\t\t} finally {\n\t\t\tSIGNALS.forEach((signal, index) => {\n\t\t\t\tfor (const listener of process.listeners(signal)) {\n\t\t\t\t\tif (!before[index]!.has(listener)) process.off(signal, listener);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * `untun` rejects a promise per connection when cloudflared exits and never handles it (and its location pattern\n\t * does not match lowercase codes such as `mxp03`, so that promise is never settled before), which Node reports as an\n\t * unhandled rejection that ends the process, whenever the tunnel closes. The guard swallows that one error for as\n\t * long as this tunnel exists; anything else it sees is thrown again, as if it was not installed.\n\t */\n\t#installRejectionGuard(context: TunnelOpenContext): void {\n\t\tif (this.#rejectionGuard) return;\n\n\t\tconst guard = (reason: unknown): void => {\n\t\t\tif (!isCloudflaredExit(reason)) {\n\t\t\t\t// The guard is the only listener, so without this the rejection would be ignored instead of ending the process.\n\t\t\t\tif (process.listeners('unhandledRejection').length === 1) throw reason;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (context.onStopped(reason)) this.#releaseRejectionGuard();\n\t\t};\n\n\t\tthis.#rejectionGuard = guard;\n\t\tprocess.on('unhandledRejection', guard);\n\t}\n\n\t/** Node reports an unhandled rejection after the microtasks that follow it, so the guard has to outlive them. */\n\t#releaseRejectionGuard(): void {\n\t\tconst guard = this.#rejectionGuard;\n\t\tthis.#rejectionGuard = null;\n\t\tif (guard) setImmediate(() => process.off('unhandledRejection', guard));\n\t}\n}\n\n/** What the CLI uses of `@ngrok/ngrok`, so the package itself is never a dependency of the CLI. */\nexport interface NgrokListener {\n\turl(): string | null;\n\tclose(): Promise<void>;\n}\n\nexport interface NgrokModule {\n\tforward(options: { addr: string | number; authtoken: string; domain?: string }): Promise<NgrokListener>;\n}\n\n/** Loads `@ngrok/ngrok`; replaced in tests. */\nexport type NgrokLoader = (root: string) => Promise<NgrokModule>;\n\nexport const NGROK_PACKAGE = '@ngrok/ngrok';\nexport const NGROK_AUTHTOKEN_VARIABLE = 'NGROK_AUTHTOKEN';\nexport const NGROK_INSTALL_HINT = `Install it with \\`pnpm add -D ${NGROK_PACKAGE}\\`, or remove \\`provider: 'ngrok'\\` from \\`dev.tunnel\\`.`;\n\n/** Imports `@ngrok/ngrok` from the project, where it is an optional peer of the CLI. */\nexport const loadNgrok: NgrokLoader = async (root) => {\n\tconst imported = await importFromProject<NgrokModule & { default?: NgrokModule }>(root, NGROK_PACKAGE, NGROK_INSTALL_HINT);\n\treturn typeof imported.forward === 'function' ? imported : imported.default!;\n};\n\n/**\n * ngrok through its official Node SDK. It runs in-process (no binary is downloaded), authenticates with\n * `NGROK_AUTHTOKEN` and can bind a domain reserved in the account.\n */\nexport class NgrokProvider implements TunnelProvider {\n\tpublic readonly name = 'ngrok';\n\t#load: NgrokLoader;\n\n\tpublic constructor(load: NgrokLoader = loadNgrok) {\n\t\tthis.#load = load;\n\t}\n\n\tpublic async open(target: string, { config, tunnel }: TunnelOpenContext): Promise<TunnelHandle> {\n\t\tconst ngrok = await this.#load(config.root);\n\t\tconst authtoken = readProjectVariable(config, process.env, [NGROK_AUTHTOKEN_VARIABLE], { fresh: true });\n\t\tif (!authtoken) throw cliDiagnostics.NGROK_AUTHTOKEN_MISSING({});\n\n\t\tconst listener = await ngrok.forward({ addr: ngrokAddress(target), authtoken, ...(tunnel.domain ? { domain: tunnel.domain } : {}) });\n\t\tconst url = listener.url();\n\t\tif (!url) {\n\t\t\tawait listener.close();\n\t\t\tthrow new Error('ngrok did not report a URL for the tunnel');\n\t\t}\n\n\t\treturn { getURL: () => Promise.resolve(url), close: () => listener.close() };\n\t}\n}\n\n/** ngrok forwards to `host:port`; a full `http` URL is reduced to it, anything else (`https`, a socket) is passed on. */\nexport function ngrokAddress(target: string): string {\n\ttry {\n\t\tconst url = new URL(target);\n\t\tif (url.protocol === 'http:') return `${url.hostname}:${url.port || 80}`;\n\t} catch {\n\t\t// Not a URL, so already an address.\n\t}\n\n\treturn target;\n}\n","import { DEFAULT_TUNNEL_PROVIDER, type ResolvedStarsConfig, type ResolvedTunnelConfig, type StarsTunnelProvider } from '@wolfstar/schema';\nimport { EventEmitter } from 'node:events';\nimport { Diagnostic } from 'nostics';\nimport type { startTunnel } from 'untun';\nimport type { LogLevel } from '../utils/log-buffer.js';\nimport { readProjectVariable } from '../utils/project-env.js';\nimport {\n\tCloudflaredProvider,\n\tNgrokProvider,\n\ttype NgrokLoader,\n\ttype QuickTunnelConfig,\n\ttype TunnelHandle,\n\ttype TunnelProvider\n} from './tunnel-providers.js';\n\nexport type TunnelState = 'off' | 'starting' | 'up' | 'failed';\n\nexport interface TunnelEvents {\n\tlog: [level: LogLevel, text: string];\n\tstate: [state: TunnelState, url: string | null];\n}\n\nexport interface TunnelOptions {\n\t/** Override for tests: how the `cloudflared` provider opens its tunnel. */\n\tstartTunnel?: typeof startTunnel;\n\t/** Override for tests: how the `ngrok` provider loads `@ngrok/ngrok`. */\n\tloadNgrok?: NgrokLoader;\n}\n\n/**\n * Exposes the bot's interactions endpoint publicly while `stars dev` runs.\n *\n * `dev.tunnel: true` opens a quick tunnel through the configured provider: `cloudflared` via `untun` by default (it\n * changes on every run), or `ngrok`. A configured https URL is only probed, since the user already serves it. Writing\n * the URL to the Discord application is opt-in through `dev.tunnel.updateEndpoint`, because it edits a live application.\n */\nexport class Tunnel extends EventEmitter<TunnelEvents> {\n\t#providers: Record<StarsTunnelProvider, TunnelProvider>;\n\t#tunnel: TunnelHandle | null = null;\n\t#state: TunnelState = 'off';\n\t#url: string | null = null;\n\t#wanted = false;\n\n\tpublic constructor(\n\t\tprivate readonly config: ResolvedStarsConfig,\n\t\toptions: TunnelOptions = {}\n\t) {\n\t\tsuper();\n\t\tthis.#providers = { cloudflared: new CloudflaredProvider(options.startTunnel), ngrok: new NgrokProvider(options.loadNgrok) };\n\t}\n\n\tpublic get state(): TunnelState {\n\t\treturn this.#state;\n\t}\n\n\t/** The public URL of the interactions endpoint, `null` until the tunnel is up. */\n\tpublic get url(): string | null {\n\t\treturn this.#url;\n\t}\n\n\tpublic async start(forceQuick = false): Promise<void> {\n\t\tif (this.#state === 'starting' || this.#state === 'up') return;\n\t\tconst configured = this.config.dev.tunnel;\n\t\tconst tunnel: ResolvedTunnelConfig =\n\t\t\tforceQuick && configured.mode === 'off'\n\t\t\t\t? { mode: 'quick', provider: DEFAULT_TUNNEL_PROVIDER, domain: null, path: '/', updateEndpoint: false }\n\t\t\t\t: configured;\n\t\tif (tunnel.mode === 'off') return;\n\n\t\tthis.#wanted = true;\n\t\tthis.#setState('starting', null);\n\t\tconst url = tunnel.mode === 'url' ? await this.#useConfiguredUrl(tunnel) : await this.#openQuickTunnel(tunnel);\n\t\tif (!url || !this.#wanted) return;\n\n\t\tthis.#setState('up', endpointUrl(url, tunnel.path));\n\t\tthis.emit('log', 'success', `Tunnel ready at ${this.#url}`);\n\t\tif (tunnel.updateEndpoint) await this.#updateInteractionsEndpoint(this.#url!);\n\t}\n\n\t/** Toggles the configured tunnel, opening a quick tunnel when the project did not configure one. */\n\tpublic toggle(): Promise<void> {\n\t\treturn this.#state === 'starting' || this.#state === 'up' ? this.close() : this.start(true);\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis.#wanted = false;\n\t\tconst tunnel = this.#tunnel;\n\t\tthis.#tunnel = null;\n\t\tthis.#setState('off', null);\n\t\t// Without a tunnel, `#openQuickTunnel` is still waiting for one and closes it when it arrives.\n\t\tawait tunnel?.close();\n\t}\n\n\tasync #useConfiguredUrl(tunnel: Extract<ResolvedTunnelConfig, { mode: 'url' }>): Promise<string | null> {\n\t\tconst reachable = await probe(endpointUrl(tunnel.url, tunnel.path));\n\t\tif (!reachable) {\n\t\t\tthis.emit('log', 'warn', `${tunnel.url} did not answer; make sure it forwards to ${this.config.dev.url ?? 'the bot'}`);\n\t\t}\n\n\t\treturn tunnel.url;\n\t}\n\n\tasync #openQuickTunnel(tunnel: QuickTunnelConfig): Promise<string | null> {\n\t\tconst target = this.config.dev.url;\n\t\tif (!target) {\n\t\t\tthis.emit('log', 'error', 'A quick tunnel needs `dev.url` to know what to forward to');\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst provider = this.#providers[tunnel.provider];\n\t\tthis.emit('log', 'info', `Opening a ${provider.name} quick tunnel…`);\n\n\t\ttry {\n\t\t\tconst handle = await provider.open(target, {\n\t\t\t\tconfig: this.config,\n\t\t\t\ttunnel,\n\t\t\t\tonStopped: (error) => this.#stoppedUnexpectedly(provider.name, error)\n\t\t\t});\n\t\t\tif (!this.#wanted) {\n\t\t\t\tawait handle?.close();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!handle) {\n\t\t\t\tthis.emit('log', 'error', `${provider.name} setup was cancelled`);\n\t\t\t\tthis.#setState('failed', null);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tthis.#tunnel = handle;\n\t\t\treturn await handle.getURL();\n\t\t} catch (error) {\n\t\t\t// Closing a tunnel can make its process exit, which a provider may report as a failure: that is not one.\n\t\t\tif (!this.#wanted) return null;\n\t\t\tthis.emit('log', 'error', `${provider.name} failed: ${describeError(error)}`);\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/** Whether the report was about the tunnel in use: one that is up and still wanted. */\n\t#stoppedUnexpectedly(provider: StarsTunnelProvider, error: Error): boolean {\n\t\tif (this.#state !== 'up' || !this.#wanted) return false;\n\t\tthis.#tunnel = null;\n\t\tthis.emit('log', 'error', `${provider} stopped unexpectedly: ${error.message}`);\n\t\tthis.#setState('failed', null);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Points the Discord application's interactions endpoint at the tunnel. Discord validates the endpoint with a\n\t * signed ping before accepting it, so the bot has to be up already — this runs after the first successful build.\n\t */\n\tasync #updateInteractionsEndpoint(url: string): Promise<void> {\n\t\tconst credentials = readDiscordCredentials(this.config);\n\t\tif (!credentials) {\n\t\t\tthis.emit('log', 'warn', 'Skipped the interactions endpoint update: DISCORD_TOKEN is not set');\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch('https://discord.com/api/v10/applications/@me', {\n\t\t\t\tmethod: 'PATCH',\n\t\t\t\theaders: { authorization: `Bot ${credentials.token}`, 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({ interactions_endpoint_url: url }),\n\t\t\t\tsignal: AbortSignal.timeout(10_000)\n\t\t\t});\n\n\t\t\tif (response.ok) this.emit('log', 'success', `Interactions endpoint set to ${url}`);\n\t\t\telse\n\t\t\t\tthis.emit(\n\t\t\t\t\t'log',\n\t\t\t\t\t'error',\n\t\t\t\t\t`Discord rejected the interactions endpoint (${response.status}): ${(await response.text()).slice(0, 300)}`\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.emit('log', 'error', `Failed to update the interactions endpoint: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t}\n\n\t#setState(state: TunnelState, url: string | null): void {\n\t\tthis.#state = state;\n\t\tthis.#url = url;\n\t\tthis.emit('state', state, url);\n\t}\n}\n\n/**\n * Joins the tunnel's origin with the path the interactions endpoint is served on.\n */\nexport function endpointUrl(origin: string, path: string): string {\n\treturn path === '/' ? origin : new URL(path, origin.endsWith('/') ? origin : `${origin}/`).href;\n}\n\nasync function probe(url: string): Promise<boolean> {\n\ttry {\n\t\tconst response = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) });\n\t\treturn response.status < 500;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport interface DiscordCredentials {\n\ttoken: string;\n\tapplicationId: string | null;\n}\n\n/**\n * Reads the Discord credentials the CLI needs from the environment, falling back to the project's `.env` files the\n * way the bot itself does once it starts.\n */\nexport function readDiscordCredentials(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordCredentials | null {\n\tconst token = readProjectVariable(config, env, ['DISCORD_TOKEN', 'TOKEN']);\n\tif (!token) return null;\n\n\treturn {\n\t\ttoken,\n\t\tapplicationId: readProjectVariable(config, env, ['DISCORD_APPLICATION_ID', 'APPLICATION_ID', 'DISCORD_CLIENT_ID', 'CLIENT_ID'])\n\t};\n}\n\n/** How a quick tunnel is described to the user, for `stars info` and `stars doctor`. */\nexport function describeQuickTunnel(tunnel: QuickTunnelConfig): string {\n\treturn `${tunnel.provider} quick tunnel${tunnel.domain ? ` on ${tunnel.domain}` : ''}`;\n}\n\n/** A diagnostic's own advice is part of the message, since the dev log has no place to show it separately. */\nfunction describeError(error: unknown): string {\n\tif (error instanceof Diagnostic) return error.fix ? `${error.message}. ${error.fix}` : error.message;\n\treturn error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tunnel-DlFjqUE7.js","names":[],"sources":["../src/dev/tunnel-providers.ts","../src/dev/tunnel.ts"],"sourcesContent":["import type { ResolvedStarsConfig, ResolvedTunnelConfig, StarsTunnelProvider } from '@wolfstar/schema';\nimport { startTunnel, type Tunnel as UntunTunnel } from 'untun';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { readProjectVariable } from '../utils/project-env.js';\nimport { importFromProject } from '../utils/project.js';\n\nexport type QuickTunnelConfig = Extract<ResolvedTunnelConfig, { mode: 'quick' }>;\n\n/** A tunnel a provider opened: where it is reachable, and how to take it down. */\nexport interface TunnelHandle {\n\tgetURL(): Promise<string>;\n\tclose(): Promise<void>;\n}\n\nexport interface TunnelOpenContext {\n\tconfig: ResolvedStarsConfig;\n\ttunnel: QuickTunnelConfig;\n\t/**\n\t * Reports that the tunnel ended without being closed. Returns whether it was handled (the tunnel was up and wanted),\n\t * so the provider knows whether it is done watching for it.\n\t */\n\tonStopped(error: Error): boolean;\n}\n\n/** A service that exposes the bot's local address publicly. */\nexport interface TunnelProvider {\n\treadonly name: StarsTunnelProvider;\n\t/**\n\t * Opens a tunnel to `target`. Resolves to `undefined` when the user cancelled the setup, and rejects when the tunnel\n\t * cannot be opened; either way nothing stays open.\n\t */\n\topen(target: string, context: TunnelOpenContext): Promise<TunnelHandle | undefined>;\n}\n\nconst SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const;\n\nfunction isCloudflaredExit(reason: unknown): reason is Error {\n\treturn reason instanceof Error && reason.message.startsWith('cloudflared exited (');\n}\n\n/**\n * The `cloudflared` quick tunnel, opened through `untun` (no account, a new hostname on every run).\n *\n * `untun` is wrapped rather than changed: it adds process signal listeners and leaves a promise unhandled whenever\n * `cloudflared` exits, both of which would end `stars dev`, so they are neutralised here.\n */\nexport class CloudflaredProvider implements TunnelProvider {\n\tpublic readonly name = 'cloudflared';\n\t#startTunnel: typeof startTunnel;\n\t#rejectionGuard: ((reason: unknown) => void) | null = null;\n\n\tpublic constructor(start: typeof startTunnel = startTunnel) {\n\t\tthis.#startTunnel = start;\n\t}\n\n\tpublic async open(target: string, context: TunnelOpenContext): Promise<TunnelHandle | undefined> {\n\t\tthis.#installRejectionGuard(context);\n\n\t\tlet tunnel: UntunTunnel | undefined;\n\t\ttry {\n\t\t\ttunnel = await this.#startWithoutSignalHandlers(target);\n\t\t} catch (error) {\n\t\t\tthis.#releaseRejectionGuard();\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (!tunnel) {\n\t\t\tthis.#releaseRejectionGuard();\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst opened = tunnel;\n\t\treturn {\n\t\t\tgetURL: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await opened.getURL();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.#releaseRejectionGuard();\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t},\n\t\t\tclose: async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait opened.close();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.#releaseRejectionGuard();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * `untun` adds its own `SIGINT`/`SIGTERM`/`SIGHUP` listeners that call `process.exit()` once cloudflared is closed,\n\t * which races `stars dev`'s graceful shutdown (it closes the tunnel through {@link TunnelHandle.close} anyway), so they\n\t * are removed.\n\t */\n\tasync #startWithoutSignalHandlers(target: string): Promise<UntunTunnel | undefined> {\n\t\tconst before = SIGNALS.map((signal) => new Set(process.listeners(signal)));\n\t\ttry {\n\t\t\treturn await this.#startTunnel({ url: target, acceptCloudflareNotice: true });\n\t\t} finally {\n\t\t\tSIGNALS.forEach((signal, index) => {\n\t\t\t\tfor (const listener of process.listeners(signal)) {\n\t\t\t\t\tif (!before[index]!.has(listener)) process.off(signal, listener);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * `untun` rejects a promise per connection when cloudflared exits and never handles it (and its location pattern\n\t * does not match lowercase codes such as `mxp03`, so that promise is never settled before), which Node reports as an\n\t * unhandled rejection that ends the process, whenever the tunnel closes. The guard swallows that one error for as\n\t * long as this tunnel exists; anything else it sees is thrown again, as if it was not installed.\n\t */\n\t#installRejectionGuard(context: TunnelOpenContext): void {\n\t\tif (this.#rejectionGuard) return;\n\n\t\tconst guard = (reason: unknown): void => {\n\t\t\tif (!isCloudflaredExit(reason)) {\n\t\t\t\t// The guard is the only listener, so without this the rejection would be ignored instead of ending the process.\n\t\t\t\tif (process.listeners('unhandledRejection').length === 1) throw reason;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (context.onStopped(reason)) this.#releaseRejectionGuard();\n\t\t};\n\n\t\tthis.#rejectionGuard = guard;\n\t\tprocess.on('unhandledRejection', guard);\n\t}\n\n\t/** Node reports an unhandled rejection after the microtasks that follow it, so the guard has to outlive them. */\n\t#releaseRejectionGuard(): void {\n\t\tconst guard = this.#rejectionGuard;\n\t\tthis.#rejectionGuard = null;\n\t\tif (guard) setImmediate(() => process.off('unhandledRejection', guard));\n\t}\n}\n\n/** What the CLI uses of `@ngrok/ngrok`, so the package itself is never a dependency of the CLI. */\nexport interface NgrokListener {\n\turl(): string | null;\n\tclose(): Promise<void>;\n}\n\nexport interface NgrokModule {\n\tforward(options: { addr: string | number; authtoken: string; domain?: string }): Promise<NgrokListener>;\n}\n\n/** Loads `@ngrok/ngrok`; replaced in tests. */\nexport type NgrokLoader = (root: string) => Promise<NgrokModule>;\n\nexport const NGROK_PACKAGE = '@ngrok/ngrok';\nexport const NGROK_AUTHTOKEN_VARIABLE = 'NGROK_AUTHTOKEN';\nexport const NGROK_INSTALL_HINT = `Install it with \\`pnpm add -D ${NGROK_PACKAGE}\\`, or remove \\`provider: 'ngrok'\\` from \\`dev.tunnel\\`.`;\n\n/** Imports `@ngrok/ngrok` from the project, where it is an optional peer of the CLI. */\nexport const loadNgrok: NgrokLoader = async (root) => {\n\tconst imported = await importFromProject<NgrokModule & { default?: NgrokModule }>(root, NGROK_PACKAGE, NGROK_INSTALL_HINT);\n\treturn typeof imported.forward === 'function' ? imported : imported.default!;\n};\n\n/**\n * ngrok through its official Node SDK. It runs in-process (no binary is downloaded), authenticates with\n * `NGROK_AUTHTOKEN` and can bind a domain reserved in the account.\n */\nexport class NgrokProvider implements TunnelProvider {\n\tpublic readonly name = 'ngrok';\n\t#load: NgrokLoader;\n\n\tpublic constructor(load: NgrokLoader = loadNgrok) {\n\t\tthis.#load = load;\n\t}\n\n\tpublic async open(target: string, { config, tunnel }: TunnelOpenContext): Promise<TunnelHandle> {\n\t\tconst ngrok = await this.#load(config.root);\n\t\tconst authtoken = readProjectVariable(config, process.env, [NGROK_AUTHTOKEN_VARIABLE], { fresh: true });\n\t\tif (!authtoken) throw cliDiagnostics.NGROK_AUTHTOKEN_MISSING({});\n\n\t\tconst listener = await ngrok.forward({ addr: ngrokAddress(target), authtoken, ...(tunnel.domain ? { domain: tunnel.domain } : {}) });\n\t\tconst url = listener.url();\n\t\tif (!url) {\n\t\t\tawait listener.close();\n\t\t\tthrow new Error('ngrok did not report a URL for the tunnel');\n\t\t}\n\n\t\treturn { getURL: () => Promise.resolve(url), close: () => listener.close() };\n\t}\n}\n\n/** ngrok forwards to `host:port`; a full `http` URL is reduced to it, anything else (`https`, a socket) is passed on. */\nexport function ngrokAddress(target: string): string {\n\ttry {\n\t\tconst url = new URL(target);\n\t\tif (url.protocol === 'http:') return `${url.hostname}:${url.port || 80}`;\n\t} catch {\n\t\t// Not a URL, so already an address.\n\t}\n\n\treturn target;\n}\n","import { DEFAULT_TUNNEL_PROVIDER, type ResolvedStarsConfig, type ResolvedTunnelConfig, type StarsTunnelProvider } from '@wolfstar/schema';\nimport { EventEmitter } from 'node:events';\nimport { Diagnostic } from 'nostics';\nimport type { startTunnel } from 'untun';\nimport type { LogLevel } from '../utils/log-buffer.js';\nimport { readProjectVariable } from '../utils/project-env.js';\nimport {\n\tCloudflaredProvider,\n\tNgrokProvider,\n\ttype NgrokLoader,\n\ttype QuickTunnelConfig,\n\ttype TunnelHandle,\n\ttype TunnelProvider\n} from './tunnel-providers.js';\n\nexport type TunnelState = 'off' | 'starting' | 'up' | 'failed';\n\nexport interface TunnelEvents {\n\tlog: [level: LogLevel, text: string];\n\tstate: [state: TunnelState, url: string | null];\n}\n\nexport interface TunnelOptions {\n\t/** Override for tests: how the `cloudflared` provider opens its tunnel. */\n\tstartTunnel?: typeof startTunnel;\n\t/** Override for tests: how the `ngrok` provider loads `@ngrok/ngrok`. */\n\tloadNgrok?: NgrokLoader;\n}\n\n/**\n * Exposes the bot's interactions endpoint publicly while `stars dev` runs.\n *\n * `dev.tunnel: true` opens a quick tunnel through the configured provider: `cloudflared` via `untun` by default (it\n * changes on every run), or `ngrok`. A configured https URL is only probed, since the user already serves it. Writing\n * the URL to the Discord application is opt-in through `dev.tunnel.updateEndpoint`, because it edits a live application.\n */\nexport class Tunnel extends EventEmitter<TunnelEvents> {\n\t#providers: Record<StarsTunnelProvider, TunnelProvider>;\n\t#tunnel: TunnelHandle | null = null;\n\t#state: TunnelState = 'off';\n\t#url: string | null = null;\n\t#wanted = false;\n\n\tpublic constructor(\n\t\tprivate readonly config: ResolvedStarsConfig,\n\t\toptions: TunnelOptions = {}\n\t) {\n\t\tsuper();\n\t\tthis.#providers = { cloudflared: new CloudflaredProvider(options.startTunnel), ngrok: new NgrokProvider(options.loadNgrok) };\n\t}\n\n\tpublic get state(): TunnelState {\n\t\treturn this.#state;\n\t}\n\n\t/** The public URL of the interactions endpoint, `null` until the tunnel is up. */\n\tpublic get url(): string | null {\n\t\treturn this.#url;\n\t}\n\n\tpublic async start(forceQuick = false): Promise<void> {\n\t\tif (this.#state === 'starting' || this.#state === 'up') return;\n\t\tconst configured = this.config.dev.tunnel;\n\t\tconst tunnel: ResolvedTunnelConfig =\n\t\t\tforceQuick && configured.mode === 'off'\n\t\t\t\t? { mode: 'quick', provider: DEFAULT_TUNNEL_PROVIDER, domain: null, path: '/', updateEndpoint: false }\n\t\t\t\t: configured;\n\t\tif (tunnel.mode === 'off') return;\n\n\t\tthis.#wanted = true;\n\t\tthis.#setState('starting', null);\n\t\tconst url = tunnel.mode === 'url' ? await this.#useConfiguredUrl(tunnel) : await this.#openQuickTunnel(tunnel);\n\t\tif (!url || !this.#wanted) return;\n\n\t\tthis.#setState('up', endpointUrl(url, tunnel.path));\n\t\tthis.emit('log', 'success', `Tunnel ready at ${this.#url}`);\n\t\tif (tunnel.updateEndpoint) await this.#updateInteractionsEndpoint(this.#url!);\n\t}\n\n\t/** Toggles the configured tunnel, opening a quick tunnel when the project did not configure one. */\n\tpublic toggle(): Promise<void> {\n\t\treturn this.#state === 'starting' || this.#state === 'up' ? this.close() : this.start(true);\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis.#wanted = false;\n\t\tconst tunnel = this.#tunnel;\n\t\tthis.#tunnel = null;\n\t\tthis.#setState('off', null);\n\t\t// Without a tunnel, `#openQuickTunnel` is still waiting for one and closes it when it arrives.\n\t\tawait tunnel?.close();\n\t}\n\n\tasync #useConfiguredUrl(tunnel: Extract<ResolvedTunnelConfig, { mode: 'url' }>): Promise<string | null> {\n\t\tconst reachable = await probe(endpointUrl(tunnel.url, tunnel.path));\n\t\tif (!reachable) {\n\t\t\tthis.emit('log', 'warn', `${tunnel.url} did not answer; make sure it forwards to ${this.config.dev.url ?? 'the bot'}`);\n\t\t}\n\n\t\treturn tunnel.url;\n\t}\n\n\tasync #openQuickTunnel(tunnel: QuickTunnelConfig): Promise<string | null> {\n\t\tconst target = this.config.dev.url;\n\t\tif (!target) {\n\t\t\tthis.emit('log', 'error', 'A quick tunnel needs `dev.url` to know what to forward to');\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst provider = this.#providers[tunnel.provider];\n\t\tthis.emit('log', 'info', `Opening a ${provider.name} quick tunnel…`);\n\n\t\ttry {\n\t\t\tconst handle = await provider.open(target, {\n\t\t\t\tconfig: this.config,\n\t\t\t\ttunnel,\n\t\t\t\tonStopped: (error) => this.#stoppedUnexpectedly(provider.name, error)\n\t\t\t});\n\t\t\tif (!this.#wanted) {\n\t\t\t\tawait handle?.close();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!handle) {\n\t\t\t\tthis.emit('log', 'error', `${provider.name} setup was cancelled`);\n\t\t\t\tthis.#setState('failed', null);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tthis.#tunnel = handle;\n\t\t\treturn await handle.getURL();\n\t\t} catch (error) {\n\t\t\t// Closing a tunnel can make its process exit, which a provider may report as a failure: that is not one.\n\t\t\tif (!this.#wanted) return null;\n\t\t\tthis.emit('log', 'error', `${provider.name} failed: ${describeError(error)}`);\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/** Whether the report was about the tunnel in use: one that is up and still wanted. */\n\t#stoppedUnexpectedly(provider: StarsTunnelProvider, error: Error): boolean {\n\t\tif (this.#state !== 'up' || !this.#wanted) return false;\n\t\tthis.#tunnel = null;\n\t\tthis.emit('log', 'error', `${provider} stopped unexpectedly: ${error.message}`);\n\t\tthis.#setState('failed', null);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Points the Discord application's interactions endpoint at the tunnel. Discord validates the endpoint with a\n\t * signed ping before accepting it, so the bot has to be up already — this runs after the first successful build.\n\t */\n\tasync #updateInteractionsEndpoint(url: string): Promise<void> {\n\t\tconst credentials = readDiscordCredentials(this.config);\n\t\tif (!credentials) {\n\t\t\tthis.emit('log', 'warn', 'Skipped the interactions endpoint update: DISCORD_TOKEN is not set');\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch('https://discord.com/api/v10/applications/@me', {\n\t\t\t\tmethod: 'PATCH',\n\t\t\t\theaders: { authorization: `Bot ${credentials.token}`, 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({ interactions_endpoint_url: url }),\n\t\t\t\tsignal: AbortSignal.timeout(10_000)\n\t\t\t});\n\n\t\t\tif (response.ok) this.emit('log', 'success', `Interactions endpoint set to ${url}`);\n\t\t\telse\n\t\t\t\tthis.emit(\n\t\t\t\t\t'log',\n\t\t\t\t\t'error',\n\t\t\t\t\t`Discord rejected the interactions endpoint (${response.status}): ${(await response.text()).slice(0, 300)}`\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.emit('log', 'error', `Failed to update the interactions endpoint: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t}\n\n\t#setState(state: TunnelState, url: string | null): void {\n\t\tthis.#state = state;\n\t\tthis.#url = url;\n\t\tthis.emit('state', state, url);\n\t}\n}\n\n/**\n * Joins the tunnel's origin with the path the interactions endpoint is served on.\n */\nexport function endpointUrl(origin: string, path: string): string {\n\treturn path === '/' ? origin : new URL(path, origin.endsWith('/') ? origin : `${origin}/`).href;\n}\n\nasync function probe(url: string): Promise<boolean> {\n\ttry {\n\t\tconst response = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) });\n\t\treturn response.status < 500;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport interface DiscordCredentials {\n\ttoken: string;\n\tapplicationId: string | null;\n}\n\n/**\n * Reads the Discord credentials the CLI needs from the environment, falling back to the project's `.env` files the\n * way the bot itself does once it starts.\n */\nexport function readDiscordCredentials(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordCredentials | null {\n\tconst token = readProjectVariable(config, env, ['DISCORD_TOKEN', 'TOKEN']);\n\tif (!token) return null;\n\n\treturn {\n\t\ttoken,\n\t\tapplicationId: readProjectVariable(config, env, ['DISCORD_APPLICATION_ID', 'APPLICATION_ID', 'DISCORD_CLIENT_ID', 'CLIENT_ID'])\n\t};\n}\n\n/** How a quick tunnel is described to the user, for `stars info` and `stars doctor`. */\nexport function describeQuickTunnel(tunnel: QuickTunnelConfig): string {\n\treturn `${tunnel.provider} quick tunnel${tunnel.domain ? ` on ${tunnel.domain}` : ''}`;\n}\n\n/** A diagnostic's own advice is part of the message, since the dev log has no place to show it separately. */\nfunction describeError(error: unknown): string {\n\tif (error instanceof Diagnostic) return error.fix ? `${error.message}. ${error.fix}` : error.message;\n\treturn error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
2
  import { t as cliDiagnostics } from "./diagnostics-BKc--u_3.js";
3
- import { d as projectArgs, f as resolveCwd, n as loadProject } from "./hooks-DqlScRZA.js";
4
- import { n as reportWarnings, t as prepareProject } from "./_shared-Bqw7h4O0.js";
3
+ import { d as projectArgs, f as resolveCwd, n as loadProject } from "./hooks-CzV2YRoJ.js";
4
+ import { n as reportWarnings, t as prepareProject } from "./_shared-BLXTNq89.js";
5
5
  import { n as resolveTypecheckCommand } from "./typechecker-zjnzC2L_.js";
6
6
  import { defineCommand } from "citty";
7
7
  import { displayPath } from "@wolfstar/schema";
@@ -63,4 +63,4 @@ var typecheck_default = defineCommand({
63
63
 
64
64
  //#endregion
65
65
  export { typecheck_default as default };
66
- //# sourceMappingURL=typecheck-BIscCUNQ.js.map
66
+ //# sourceMappingURL=typecheck-B2aRagKp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"typecheck-BIscCUNQ.js","names":[],"sources":["../src/commands/typecheck.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { spawn } from 'node:child_process';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { resolveTypecheckCommand } from '../dev/typechecker.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { loadProject } from '../utils/hooks.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport interface TypecheckTaskOptions extends ProjectArgs {\n\tstdout?: NodeJS.WritableStream;\n}\n\n/**\n * Type-checks the project once, the way `nuxt typecheck` does: regenerates `.stars/` first, then runs the project's own\n * checker (`dev.typecheck.checker`, `golar` or `tsc`) on every project: the generated app and node configs from\n * compatibility version 6, the single tsconfig below it. A project root `tsconfig.json` that only references them is\n * never passed to `tsc -p`, which would check nothing.\n */\nexport async function runTypecheck(options: TypecheckTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() });\n\tconst { config, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(config, (text) => process.stderr.write(`${text}\\n`), { production: false });\n\tawait prepareProject(config, hooks);\n\n\tconst { projects } = config.dev.typecheck;\n\tif (projects.length === 0) throw cliDiagnostics.TYPECHECK_NO_PROJECT({ root: config.root });\n\n\tconst failed: string[] = [];\n\tfor (const project of projects) {\n\t\tconst { command, args, node } = resolveTypecheckCommand(config, { project, once: true });\n\t\tstdout.write(`${colors.dim('stars')} typecheck ${displayPath(config.root, project)}\\n`);\n\t\tconst code = await new Promise<number | null>((resolve, reject) => {\n\t\t\tconst child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {\n\t\t\t\tcwd: config.root,\n\t\t\t\tenv: process.env,\n\t\t\t\tstdio: 'inherit',\n\t\t\t\twindowsHide: true\n\t\t\t});\n\t\t\tchild.once('error', reject);\n\t\t\tchild.once('exit', resolve);\n\t\t});\n\t\tif (code !== 0) failed.push(displayPath(config.root, project));\n\t}\n\n\tif (failed.length > 0) throw cliDiagnostics.TYPECHECK_FAILED({ projects: failed.join(', ') });\n\tstdout.write(`${colors.dim('stars')} ${colors.green('no type errors')}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'typecheck',\n\t\tdescription: 'Type-check the project, including the generated app and node TypeScript configurations'\n\t},\n\targs: { ...projectArgs },\n\tasync run({ args }) {\n\t\tawait runTypecheck({ config: args.config, cwd: args.cwd });\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,eAAsB,aAAa,SAA8C;CAChF,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,EAAE,CAAC;CAC1D,MAAM,EAAE,QAAQ,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CACpG,MAAM,eAAe,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,GAAG,EAAE,YAAY,MAAM,CAAC;CAC/F,MAAM,eAAe,QAAQ,KAAK;CAElC,MAAM,EAAE,aAAa,OAAO,IAAI;CAChC,IAAI,SAAS,WAAW,GAAG,MAAM,eAAe,qBAAqB,EAAE,MAAM,OAAO,KAAK,CAAC;CAE1F,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,WAAW,UAAU;EAC/B,MAAM,EAAE,SAAS,MAAM,SAAS,wBAAwB,QAAQ;GAAE;GAAS,MAAM;EAAK,CAAC;EACvF,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,aAAa,YAAY,OAAO,MAAM,OAAO,EAAE,GAAG;EAWtF,IAAI,MAVe,IAAI,SAAwB,SAAS,WAAW;GAClE,MAAM,QAAQ,MAAM,OAAO,QAAQ,WAAW,SAAS,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG;IAC7F,KAAK,OAAO;IACZ,KAAK,QAAQ;IACb,OAAO;IACP,aAAa;GACd,CAAC;GACD,MAAM,KAAK,SAAS,MAAM;GAC1B,MAAM,KAAK,QAAQ,OAAO;EAC3B,CAAC,MACY,GAAG,OAAO,KAAK,YAAY,OAAO,MAAM,OAAO,CAAC;CAC9D;CAEA,IAAI,OAAO,SAAS,GAAG,MAAM,eAAe,iBAAiB,EAAE,UAAU,OAAO,KAAK,IAAI,EAAE,CAAC;CAC5F,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,OAAO,MAAM,gBAAgB,EAAE,GAAG;AAC1E;AAEA,wBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM,EAAE,GAAG,YAAY;CACvB,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,aAAa;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;EAAI,CAAC;CAC1D;AACD,CAAC"}
1
+ {"version":3,"file":"typecheck-B2aRagKp.js","names":[],"sources":["../src/commands/typecheck.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { spawn } from 'node:child_process';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { resolveTypecheckCommand } from '../dev/typechecker.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { loadProject } from '../utils/hooks.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport interface TypecheckTaskOptions extends ProjectArgs {\n\tstdout?: NodeJS.WritableStream;\n}\n\n/**\n * Type-checks the project once, the way `nuxt typecheck` does: regenerates `.stars/` first, then runs the project's own\n * checker (`dev.typecheck.checker`, `golar` or `tsc`) on every project: the generated app and node configs from\n * compatibility version 6, the single tsconfig below it. A project root `tsconfig.json` that only references them is\n * never passed to `tsc -p`, which would check nothing.\n */\nexport async function runTypecheck(options: TypecheckTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() });\n\tconst { config, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(config, (text) => process.stderr.write(`${text}\\n`), { production: false });\n\tawait prepareProject(config, hooks);\n\n\tconst { projects } = config.dev.typecheck;\n\tif (projects.length === 0) throw cliDiagnostics.TYPECHECK_NO_PROJECT({ root: config.root });\n\n\tconst failed: string[] = [];\n\tfor (const project of projects) {\n\t\tconst { command, args, node } = resolveTypecheckCommand(config, { project, once: true });\n\t\tstdout.write(`${colors.dim('stars')} typecheck ${displayPath(config.root, project)}\\n`);\n\t\tconst code = await new Promise<number | null>((resolve, reject) => {\n\t\t\tconst child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {\n\t\t\t\tcwd: config.root,\n\t\t\t\tenv: process.env,\n\t\t\t\tstdio: 'inherit',\n\t\t\t\twindowsHide: true\n\t\t\t});\n\t\t\tchild.once('error', reject);\n\t\t\tchild.once('exit', resolve);\n\t\t});\n\t\tif (code !== 0) failed.push(displayPath(config.root, project));\n\t}\n\n\tif (failed.length > 0) throw cliDiagnostics.TYPECHECK_FAILED({ projects: failed.join(', ') });\n\tstdout.write(`${colors.dim('stars')} ${colors.green('no type errors')}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'typecheck',\n\t\tdescription: 'Type-check the project, including the generated app and node TypeScript configurations'\n\t},\n\targs: { ...projectArgs },\n\tasync run({ args }) {\n\t\tawait runTypecheck({ config: args.config, cwd: args.cwd });\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,eAAsB,aAAa,SAA8C;CAChF,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,EAAE,CAAC;CAC1D,MAAM,EAAE,QAAQ,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CACpG,MAAM,eAAe,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,GAAG,EAAE,YAAY,MAAM,CAAC;CAC/F,MAAM,eAAe,QAAQ,KAAK;CAElC,MAAM,EAAE,aAAa,OAAO,IAAI;CAChC,IAAI,SAAS,WAAW,GAAG,MAAM,eAAe,qBAAqB,EAAE,MAAM,OAAO,KAAK,CAAC;CAE1F,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,WAAW,UAAU;EAC/B,MAAM,EAAE,SAAS,MAAM,SAAS,wBAAwB,QAAQ;GAAE;GAAS,MAAM;EAAK,CAAC;EACvF,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,aAAa,YAAY,OAAO,MAAM,OAAO,EAAE,GAAG;EAWtF,IAAI,MAVe,IAAI,SAAwB,SAAS,WAAW;GAClE,MAAM,QAAQ,MAAM,OAAO,QAAQ,WAAW,SAAS,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG;IAC7F,KAAK,OAAO;IACZ,KAAK,QAAQ;IACb,OAAO;IACP,aAAa;GACd,CAAC;GACD,MAAM,KAAK,SAAS,MAAM;GAC1B,MAAM,KAAK,QAAQ,OAAO;EAC3B,CAAC,MACY,GAAG,OAAO,KAAK,YAAY,OAAO,MAAM,OAAO,CAAC;CAC9D;CAEA,IAAI,OAAO,SAAS,GAAG,MAAM,eAAe,iBAAiB,EAAE,UAAU,OAAO,KAAK,IAAI,EAAE,CAAC;CAC5F,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,OAAO,MAAM,gBAAgB,EAAE,GAAG;AAC1E;AAEA,wBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM,EAAE,GAAG,YAAY;CACvB,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,aAAa;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;EAAI,CAAC;CAC1D;AACD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wolfstar/cli",
3
- "version": "2.7.0-next-20261009115919",
3
+ "version": "2.7.0",
4
4
  "description": "The stars command line interface for @wolfstar/http-framework projects: typed configuration, dev server, build and project info",
5
5
  "keywords": [
6
6
  "api",
@@ -56,10 +56,10 @@
56
56
  "dependencies": {
57
57
  "@clack/prompts": "^1.8.1",
58
58
  "@sapphire/ts-config": "^5.0.3",
59
- "@wolfstar/kit": "^0.2.1-next-20261009115919",
60
- "@wolfstar/nitro-server": "^0.2.10-next-20261009115919",
61
- "@wolfstar/schema": "^0.10.0-next-20261009115919",
62
- "@wolfstar/vite-server": "^0.4.5-next-20261009115919",
59
+ "@wolfstar/kit": "^0.2.1",
60
+ "@wolfstar/nitro-server": "^0.2.10",
61
+ "@wolfstar/schema": "^0.10.0",
62
+ "@wolfstar/vite-server": "^0.4.5",
63
63
  "chokidar": "^5.0.0",
64
64
  "citty": "^0.2.2",
65
65
  "colorette": "^2.0.20",
@@ -1,16 +0,0 @@
1
- //#region src/commands/index.ts
2
- const commands = {
3
- dev: () => import("./dev-GvuLQzWu.js").then((module) => module.default),
4
- build: () => import("./build-BYlgPxAE.js").then((module) => module.default),
5
- info: () => import("./info-BX-As3qN.js").then((module) => module.default),
6
- codegen: () => import("./codegen-CiDXuBHu.js").then((module) => module.default),
7
- prepare: () => import("./prepare-6abxyJeD.js").then((module) => module.default),
8
- typecheck: () => import("./typecheck-BIscCUNQ.js").then((module) => module.default),
9
- commands: () => import("./commands-CURkZI0f.js").then((module) => module.default),
10
- doctor: () => import("./doctor-C_lTMEjG.js").then((module) => module.default),
11
- completions: () => import("./completions-DBipETDu.js").then((module) => module.default)
12
- };
13
-
14
- //#endregion
15
- export { commands as t };
16
- //# sourceMappingURL=commands-Chpk8BR8.js.map
@@ -1,3 +0,0 @@
1
- import { t as commands } from "./commands-Chpk8BR8.js";
2
-
3
- export { commands };
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks-DqlScRZA.js","names":["resolveModule"],"sources":["../src/utils/args.ts","../src/utils/env-import.ts","../src/utils/modules.ts","../src/utils/project-env.ts","../src/utils/hooks.ts"],"sourcesContent":["import type { ArgsDef } from 'citty';\nimport { resolve } from 'node:path';\n\n/**\n * Arguments shared by every command that reads the project configuration.\n */\nexport const projectArgs = {\n\tconfig: {\n\t\ttype: 'string',\n\t\talias: 'c',\n\t\tdescription: 'Path to the configuration file (defaults to stars.config.* in the working directory)'\n\t},\n\tcwd: {\n\t\ttype: 'string',\n\t\tdescription: 'Working directory to run from (defaults to the current directory)'\n\t}\n} as const satisfies ArgsDef;\n\nexport interface ProjectArgs {\n\tconfig?: string;\n\tcwd?: string;\n}\n\n/**\n * Every value of a flag given more than once (`--channel a --channel=b`). citty keeps only the last one of a\n * repeated string flag, so a repeatable flag reads the raw arguments.\n */\nexport function collectFlag(rawArgs: readonly string[], name: string): string[] {\n\tconst values: string[] = [];\n\tfor (const [index, argument] of rawArgs.entries()) {\n\t\tif (argument === '--') break;\n\t\tif (argument.startsWith(`--${name}=`)) values.push(argument.slice(name.length + 3));\n\t\telse if (argument === `--${name}`) {\n\t\t\tconst next = rawArgs[index + 1];\n\t\t\tif (next !== undefined && !next.startsWith('-')) values.push(next);\n\t\t}\n\t}\n\n\treturn values;\n}\n\nexport function resolveCwd(args: ProjectArgs): string {\n\treturn args.cwd ? resolve(process.cwd(), args.cwd) : process.cwd();\n}\n","import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { envModuleSource, modulesModuleSource } from '@wolfstar/vite-server/internal';\nimport { resolveSync } from 'mlly';\nimport { isAbsolute } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { cliDiagnostics } from './diagnostics.js';\nimport { resolveFromProject } from './project.js';\n\n/** Build tools whose output never passes through the entry transform that registers `env`. */\nexport const UNTRANSFORMED_TOOLS = new Set<string>(['none', 'tsc']);\n\n/**\n * `node` arguments that register `env` before the entry runs, for the build tools the entry transform cannot reach.\n * The preload is a `data:` URL, so `.stars/` gets no generated runtime file; a `data:` URL cannot resolve bare\n * specifiers, so `@wolfstar/env-utilities` is resolved from the project first. When it cannot be resolved nothing is\n * preloaded, and the bot's own import of it reports the missing install.\n */\nexport function envImportArgs(config: ResolvedStarsConfig): string[] {\n\tif (!config.env.enabled || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];\n\n\tconst resolved = resolveFromProject(config.root, '@wolfstar/env-utilities');\n\tif (resolved === null) return [];\n\n\tconst source = envModuleSource(config.env.options, pathToFileURL(resolved).href);\n\treturn ['--import', `data:text/javascript,${encodeURIComponent(source)}`];\n}\n\n/**\n * `node` arguments that register the runtime plugins of the installed modules (`ctx.addPlugin`) before the entry\n * runs, for the build tools the entry transform cannot reach. `@wolfstar/http-framework` and every plugin are resolved\n * from the project first, with the `import` condition (both are ESM), because a `data:` URL cannot resolve bare\n * specifiers; the framework is the bot's own copy, so `Client.use` reaches the `Client` the bot constructs. When the\n * framework is not installed nothing is preloaded, and the bot's own import of it reports the missing install.\n */\nexport function moduleImportArgs(config: ResolvedStarsConfig): string[] {\n\tconst plugins = config.runtime?.plugins ?? [];\n\tif (plugins.length === 0 || !UNTRANSFORMED_TOOLS.has(config.build.tool)) return [];\n\n\tconst url = pathToFileURL(`${config.root}/package.json`).href;\n\tlet framework: string;\n\ttry {\n\t\tframework = resolveSync('@wolfstar/http-framework', { url });\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst source = modulesModuleSource(plugins, {\n\t\tframework,\n\t\tresolve: (from) => {\n\t\t\tif (from.startsWith('file:')) return from;\n\t\t\tif (isAbsolute(from)) return pathToFileURL(from).href;\n\t\t\ttry {\n\t\t\t\treturn resolveSync(from, { url });\n\t\t\t} catch {\n\t\t\t\tthrow cliDiagnostics.DEPENDENCY_MISSING({\n\t\t\t\t\tname: from,\n\t\t\t\t\troot: config.root,\n\t\t\t\t\thint: 'Install the package of the module that registers this plugin.'\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t});\n\treturn ['--import', `data:text/javascript,${encodeURIComponent(source)}`];\n}\n","import { ModuleError, setupModules } from '@wolfstar/kit';\nimport { assertModuleOptionsClaimed, type ResolvedStarsConfig } from '@wolfstar/schema';\nimport { envModuleSource, modulesModuleSource } from '@wolfstar/vite-server/internal';\nimport { resolve as resolveModule } from 'mlly';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport type { Diagnostic } from 'nostics';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { cliDiagnostics } from './diagnostics.js';\nimport { UNTRANSFORMED_TOOLS } from './env-import.js';\nimport type { StarsHookable } from './hooks.js';\nimport { findInstalledVersion } from './project.js';\nimport { readOwnPackageJson } from './version.js';\n\n/**\n * Where a module specifier is imported from: a relative or absolute path is a file of the project, a `file:` URL is\n * itself, anything else is a package resolved from the project root — with `mlly`, honouring the `import` condition,\n * because installed modules are ESM-only packages a CommonJS `require.resolve` cannot see.\n */\nasync function resolveSpecifier(root: string, specifier: string): Promise<string> {\n\tif (specifier.startsWith('file:')) return specifier;\n\tif (specifier.startsWith('.') || isAbsolute(specifier)) return pathToFileURL(resolve(root, specifier)).href;\n\treturn resolveModule(specifier, { url: pathToFileURL(`${root}/package.json`).href });\n}\n\n/**\n * Runs `setup` of every module in `modules` (see `@wolfstar/kit`) and returns the configuration carrying what they\n * contributed: `runtime`, and `imports.presets` extended by `ctx.addImports`. Without modules the configuration is\n * returned as it is.\n *\n * Afterwards, a top-level `stars.config` key that is not built in and that no installed module claimed with\n * `meta.configKey` is an `UNKNOWN_OPTION` error: the schema keeps such keys aside (`moduleOptions`) because only the\n * modules know which ones are theirs. That check runs without modules too, where every extra key is unknown.\n */\nexport async function installModules(config: ResolvedStarsConfig, hooks: StarsHookable): Promise<ResolvedStarsConfig> {\n\tif (config.modules.length === 0) {\n\t\tassertModuleOptionsClaimed(config, []);\n\t\treturn config;\n\t}\n\n\ttry {\n\t\tconst runtime = await setupModules({\n\t\t\tconfig,\n\t\t\thooks,\n\t\t\tversions: { framework: findInstalledVersion(config.root, '@wolfstar/http-framework'), stars: readOwnPackageJson().version },\n\t\t\tload: async (specifier) => import(await resolveSpecifier(config.root, specifier))\n\t\t});\n\n\t\tassertModuleOptionsClaimed(config, runtime.configKeys);\n\n\t\tconst presets = [...config.imports.presets, ...runtime.imports.filter((preset) => !config.imports.presets.includes(preset))];\n\t\treturn { ...config, runtime, imports: { ...config.imports, presets } };\n\t} catch (error) {\n\t\tif (error instanceof ModuleError) {\n\t\t\tthrow cliDiagnostics.MODULE_FAILED({ module: error.moduleName, reason: error.code, message: error.message, cause: error });\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n\n/**\n * The warning for a project whose runtime plugins reach production only through a `node --import` preload, `null`\n * otherwise. It is not one of `config.warnings`: `stars dev` preloads the plugins itself, so there it would be noise\n * on every start. `stars build` and `stars prepare` report it.\n */\nexport function modulesPreloadWarning(config: ResolvedStarsConfig): Diagnostic | null {\n\tif (!needsPreload(config)) return null;\n\treturn cliDiagnostics.MODULES_PRELOAD_REQUIRED({\n\t\ttool: config.build.tool,\n\t\tplugins: [...new Set(config.runtime.plugins.map((plugin) => plugin.module))].join(', ')\n\t});\n}\n\n/** A build tool the entry transform cannot reach, with runtime plugins to register: they need a `node --import` preload. */\nfunction needsPreload(config: ResolvedStarsConfig): boolean {\n\treturn UNTRANSFORMED_TOOLS.has(config.build.tool) && (config.runtime?.plugins.length ?? 0) > 0;\n}\n\nexport interface ModulesPreloadResult {\n\t/** Absolute path of the preload file. */\n\tpath: string;\n\tstatus: 'written' | 'up-to-date' | 'outdated';\n}\n\n/**\n * Writes `.stars/modules.mjs`, the production counterpart of the preload `stars dev` passes to `node`: `node --import\n * ./.stars/modules.mjs <entry>` registers the runtime plugins of the installed modules for the build tools whose entry\n * cannot be transformed (`tsc`, `none`). Its specifiers are bare, so they resolve from the project's `node_modules`\n * like the bot's own imports. `null` when there is nothing to register.\n *\n * With `env` enabled it is preceded by `.stars/env.mjs`, a separate module imported first: imports of one module are\n * all evaluated before its body runs, so the environment could not be loaded ahead of the plugins from the same file,\n * and a plugin reading `process.env` while it is imported would see nothing.\n */\nexport async function prepareModulesPreload(config: ResolvedStarsConfig, check = false): Promise<ModulesPreloadResult | null> {\n\tif (!needsPreload(config)) return null;\n\n\tconst directory = join(config.root, '.stars');\n\tconst path = join(directory, 'modules.mjs');\n\tconst withEnv = config.env?.enabled === true;\n\t// An absolute path is a `file:` URL in the import, like in `moduleImportArgs`: Node rejects a Windows path there.\n\tconst plugins = modulesModuleSource(config.runtime.plugins, { resolve: (from) => (isAbsolute(from) ? pathToFileURL(from).href : from) });\n\tconst files = [\n\t\t{ path, content: withEnv ? `import \"./env.mjs\";\\n${plugins}` : plugins },\n\t\t...(withEnv ? [{ path: join(directory, 'env.mjs'), content: envModuleSource(config.env.options) }] : [])\n\t];\n\n\tif (check) {\n\t\tconst current = await Promise.all(files.map(async (file) => (await readFile(file.path, 'utf-8').catch(() => null)) === file.content));\n\t\treturn { path, status: current.every(Boolean) ? 'up-to-date' : 'outdated' };\n\t}\n\n\tawait mkdir(directory, { recursive: true });\n\tawait Promise.all(files.map((file) => writeFile(file.path, file.content)));\n\treturn { path, status: 'written' };\n}\n","import { readProjectEnvFiles, type ResolvedStarsConfig } from '@wolfstar/schema';\nimport { execFileSync } from 'node:child_process';\nimport { resolveBinary } from './project.js';\n\n/**\n * The variables the bot will load, for the CLI's own lookups (Discord credentials for the tunnel). With the default\n * loader these are the project's env files, read from `env.path`/`env.env`. With `loader: 'varlock'` they are what\n * `varlock load` resolves from the project's `.env.schema` — a dotenv file may be stale or absent there — and nothing\n * when varlock cannot be run, rather than values the bot never sees.\n */\nexport function readProjectEnv(config: ResolvedStarsConfig): Record<string, string> {\n\tconst { path, env = 'development', loader } = config.env.options;\n\tif (loader !== 'varlock') return readProjectEnvFiles(config.root, env, { path });\n\n\tconst binary = resolveBinary(config.root, 'varlock', 'varlock');\n\tif (binary === null) return {};\n\n\ttry {\n\t\t// The way the bot loads it: `@wolfstar/env-utilities` runs `varlock/auto-load` with no `--env` (it ignores\n\t\t// `env.env` with varlock), in the environment `stars dev` gives the bot.\n\t\tconst output = execFileSync(process.execPath, [binary, 'load', '--format', 'json'], {\n\t\t\tcwd: config.root,\n\t\t\t// Same order as `createSupervisor`: `NODE_ENV` is forced to development after `dev.env`, so it can't differ.\n\t\t\tenv: { ...process.env, ...config.dev.env, NODE_ENV: 'development' },\n\t\t\tencoding: 'utf8',\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t\ttimeout: 30_000\n\t\t});\n\t\tconst values = JSON.parse(output) as Record<string, unknown>;\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(values)\n\t\t\t\t.filter(([, value]) => value !== undefined && value !== null)\n\t\t\t\t.map(([key, value]) => [key, String(value)])\n\t\t);\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nlet envFileCache: { key: string; values: Record<string, string> } | null = null;\n\n/** The variables the bot loads (see {@link readProjectEnv}), once per project and `env` options. */\nfunction readProjectEnvCached(config: ResolvedStarsConfig, fresh: boolean): Record<string, string> {\n\tconst key = JSON.stringify([config.root, config.env.options]);\n\tif (fresh || envFileCache?.key !== key) envFileCache = { key, values: readProjectEnv(config) };\n\treturn envFileCache.values;\n}\n\n/**\n * The first of `keys` that is set, looking at `dev.env`, then the environment, then the project's env files the way the\n * bot itself does once it starts. `null` when none is.\n *\n * The env files are read once per project; `fresh` reads them again, for a lookup that follows the user editing them\n * (pressing `t` after adding a token), which would otherwise keep failing until `stars dev` restarts.\n */\nexport function readProjectVariable(\n\tconfig: ResolvedStarsConfig,\n\tenv: NodeJS.ProcessEnv,\n\tkeys: readonly string[],\n\t{ fresh = false }: { fresh?: boolean } = {}\n): string | null {\n\tconst fromFiles = readProjectEnvCached(config, fresh);\n\tfor (const key of keys) {\n\t\tconst value = config.dev.env[key] ?? env[key] ?? fromFiles[key];\n\t\tif (value) return value;\n\t}\n\n\treturn null;\n}\n","import {\n\tloadConfigFile,\n\tresolveStarsConfig,\n\ttype LoadStarsConfigOptions,\n\ttype ResolveConfigOptions,\n\ttype ResolvedStarsConfig,\n\ttype StarsHookName,\n\ttype StarsHooks\n} from '@wolfstar/schema';\nimport { createHooks, type Hookable } from 'hookable';\nimport { installModules } from './modules.js';\nimport { readProjectEnv } from './project-env.js';\n\nexport type StarsHookable = Hookable<StarsHooks>;\n\n/** What each configuration loaded by {@link loadProject} was resolved from, so `env:options` can re-resolve it. */\nconst sources = new WeakMap<ResolvedStarsConfig, ResolveConfigOptions>();\n\n/** Registers the `hooks` of `stars.config` on a fresh `hookable` instance. */\nexport function createStarsHooks(config: ResolvedStarsConfig): StarsHookable {\n\tconst hooks = createHooks<StarsHooks>();\n\tfor (const [name, callbacks] of Object.entries(config.hooks) as [StarsHookName, readonly StarsHooks[StarsHookName][]][]) {\n\t\tfor (const callback of callbacks) hooks.hook(name, callback);\n\t}\n\n\treturn hooks;\n}\n\n/** Loads `stars.config`, registers its hooks and runs `config:resolved`. */\nexport async function loadProject(options: LoadStarsConfigOptions): Promise<{ config: ResolvedStarsConfig; hooks: StarsHookable }> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst loaded = await loadConfigFile({ cwd, configFile: options.configFile });\n\tconst source: ResolveConfigOptions = { cwd, configFile: loaded.configFile, config: loaded.config, env: options.env };\n\tconst resolved = resolveStarsConfig(source);\n\tconst hooks = createStarsHooks(resolved);\n\t// Modules install before `config:resolved`, so that hook already sees what they contributed.\n\tconst config = await installModules(resolved, hooks);\n\tsources.set(config, source);\n\n\tawait hooks.callHook('config:resolved', config);\n\treturn { config, hooks };\n}\n\n/**\n * Runs `env:options` on a copy of the resolved `env` options and returns a configuration carrying the result, which\n * is what the builders write into the entry. The resolved configuration itself is left untouched.\n *\n * When the hook changes the options, the configuration is resolved again with them, so everything read from the env\n * files — the default `dev.url` port above all — matches what the bot will load.\n */\nexport async function applyEnvOptions(config: ResolvedStarsConfig, hooks: StarsHookable): Promise<ResolvedStarsConfig> {\n\tif (!config.env.enabled) return config;\n\n\tconst options = { ...config.env.options };\n\tawait hooks.callHook('env:options', options, config);\n\n\tconst source = sources.get(config);\n\tif (source === undefined || JSON.stringify(options) === JSON.stringify(config.env.options)) {\n\t\treturn { ...config, env: { ...config.env, options } };\n\t}\n\n\treturn reresolve(config, source, { config: { ...source.config, env: { ...options, enabled: true } } });\n}\n\n/**\n * With `loader: 'varlock'`, resolves the configuration again with the variables `varlock load` returns, so the\n * defaults `stars.config` derives from the environment — the `dev.url` port — match what the bot loads. Every other\n * configuration is returned as-is: the schema reads its env files directly.\n */\nexport function withProjectEnv(config: ResolvedStarsConfig): ResolvedStarsConfig {\n\tconst source = sources.get(config);\n\tif (source === undefined || !config.env.enabled || config.env.options.loader !== 'varlock') return config;\n\treturn reresolve(config, source, { projectEnv: readProjectEnv(config) });\n}\n\nfunction reresolve(previous: ResolvedStarsConfig, source: ResolveConfigOptions, change: Partial<ResolveConfigOptions>): ResolvedStarsConfig {\n\tconst next = { ...source, ...change };\n\tconst resolved = resolveStarsConfig(next);\n\t// Modules ran once, against the first resolution: what they contributed carries over to the new one.\n\tconst config = { ...resolved, runtime: previous.runtime, imports: { ...resolved.imports, presets: previous.imports.presets } };\n\tsources.set(config, next);\n\treturn config;\n}\n"],"mappings":"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"}