@wolfstar/cli 2.3.1 → 2.6.0-next-20261007120201

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +83 -13
  2. package/dist/{_shared-BIQK0Bhm.js → _shared-CyzTojMA.js} +95 -20
  3. package/dist/_shared-CyzTojMA.js.map +1 -0
  4. package/dist/{bridge-BegCt_n2.js → bridge-Cbm0jX9h.js} +3 -236
  5. package/dist/bridge-Cbm0jX9h.js.map +1 -0
  6. package/dist/{build-DJcc95Yq.js → build-BbIEbOu3.js} +5 -5
  7. package/dist/{build-DJcc95Yq.js.map → build-BbIEbOu3.js.map} +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/codegen-C2PY7RXA.js +262 -0
  10. package/dist/codegen-C2PY7RXA.js.map +1 -0
  11. package/dist/commands-3Tgwy6cj.js +16 -0
  12. package/dist/commands-3Tgwy6cj.js.map +1 -0
  13. package/dist/commands-3qXbxhXx.js +3 -0
  14. package/dist/{commands-Bh0K9iWX.js → commands-C-i3qYOz.js} +5 -93
  15. package/dist/commands-C-i3qYOz.js.map +1 -0
  16. package/dist/{completions-DMPlZ0S1.js → completions-Cs6YbuXO.js} +3 -3
  17. package/dist/{completions-DMPlZ0S1.js.map → completions-Cs6YbuXO.js.map} +1 -1
  18. package/dist/{dev-Owu3e3AO.js → dev-9YvzhtkU.js} +22 -215
  19. package/dist/dev-9YvzhtkU.js.map +1 -0
  20. package/dist/{diagnostics-BysbNnPD.js → diagnostics-Dn3CXa8J.js} +11 -2
  21. package/dist/diagnostics-Dn3CXa8J.js.map +1 -0
  22. package/dist/{doctor-DEtAAknK.js → doctor-CMGfbXS5.js} +15 -7
  23. package/dist/doctor-CMGfbXS5.js.map +1 -0
  24. package/dist/{hooks-Cy6F2bhH.js → hooks-D_RVS0ba.js} +13 -5
  25. package/dist/hooks-D_RVS0ba.js.map +1 -0
  26. package/dist/index.d.ts +21 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -2
  29. package/dist/{info-CKJVMWIT.js → info-eXsx1AfE.js} +5 -4
  30. package/dist/info-eXsx1AfE.js.map +1 -0
  31. package/dist/local-commands-CGBjc8KJ.js +95 -0
  32. package/dist/local-commands-CGBjc8KJ.js.map +1 -0
  33. package/dist/{locales-BJAP4HYf.js → locales-BzyEMQnX.js} +5 -5
  34. package/dist/{locales-BJAP4HYf.js.map → locales-BzyEMQnX.js.map} +1 -1
  35. package/dist/{nitro-B8u1iVgf.js → nitro-DufOgx8s.js} +2 -2
  36. package/dist/{nitro-B8u1iVgf.js.map → nitro-DufOgx8s.js.map} +1 -1
  37. package/dist/{prepare-BM93i3Rm.js → prepare-DKH0UIYA.js} +12 -8
  38. package/dist/prepare-DKH0UIYA.js.map +1 -0
  39. package/dist/{project-zlQStwsf.js → project-DBqQMFCk.js} +14 -3
  40. package/dist/project-DBqQMFCk.js.map +1 -0
  41. package/dist/{run-CHqwvZXf.js → run-DlNY1QM1.js} +2 -2
  42. package/dist/{run-CHqwvZXf.js.map → run-DlNY1QM1.js.map} +1 -1
  43. package/dist/tsc-9yHyx0L6.js +3 -0
  44. package/dist/{tsc-puVAcwmo.js → tsc-BArammxe.js} +3 -3
  45. package/dist/{tsc-puVAcwmo.js.map → tsc-BArammxe.js.map} +1 -1
  46. package/dist/{tsdown-Dwt3JhPw.js → tsdown-2i5h88vT.js} +2 -2
  47. package/dist/{tsdown-Dwt3JhPw.js.map → tsdown-2i5h88vT.js.map} +1 -1
  48. package/dist/{tui-nldGSD4c.js → tui-CB_qk2Z1.js} +2 -2
  49. package/dist/{tui-nldGSD4c.js.map → tui-CB_qk2Z1.js.map} +1 -1
  50. package/dist/tunnel-BNV5cuJz.js +236 -0
  51. package/dist/tunnel-BNV5cuJz.js.map +1 -0
  52. package/dist/typecheck-p_2rj9lL.js +66 -0
  53. package/dist/typecheck-p_2rj9lL.js.map +1 -0
  54. package/dist/typechecker-C3UOI2LF.js +213 -0
  55. package/dist/typechecker-C3UOI2LF.js.map +1 -0
  56. package/dist/{vite-YZUtv2Hk.js → vite-C5CN3xUu.js} +2 -2
  57. package/dist/{vite-YZUtv2Hk.js.map → vite-C5CN3xUu.js.map} +1 -1
  58. package/package.json +9 -9
  59. package/dist/_shared-BIQK0Bhm.js.map +0 -1
  60. package/dist/bridge-BegCt_n2.js.map +0 -1
  61. package/dist/codegen-aJSyPz-J.js +0 -124
  62. package/dist/codegen-aJSyPz-J.js.map +0 -1
  63. package/dist/commands-Bh0K9iWX.js.map +0 -1
  64. package/dist/commands-BlDTDvFO.js +0 -3
  65. package/dist/commands-CSB-pjgs.js +0 -15
  66. package/dist/commands-CSB-pjgs.js.map +0 -1
  67. package/dist/dev-Owu3e3AO.js.map +0 -1
  68. package/dist/diagnostics-BysbNnPD.js.map +0 -1
  69. package/dist/doctor-DEtAAknK.js.map +0 -1
  70. package/dist/hooks-Cy6F2bhH.js.map +0 -1
  71. package/dist/info-CKJVMWIT.js.map +0 -1
  72. package/dist/prepare-BM93i3Rm.js.map +0 -1
  73. package/dist/project-zlQStwsf.js.map +0 -1
  74. package/dist/tsc-C5l5TQGC.js +0 -3
@@ -1,4 +1,4 @@
1
- import { t as cliDiagnostics } from "./diagnostics-BysbNnPD.js";
1
+ import { t as cliDiagnostics } from "./diagnostics-Dn3CXa8J.js";
2
2
  import { defineCommand } from "citty";
3
3
 
4
4
  //#region src/commands/completions.ts
@@ -138,7 +138,7 @@ function generateCompletions(shell, commands) {
138
138
  return GENERATORS[shell](commands);
139
139
  }
140
140
  async function runCompletions(options) {
141
- const { commands } = await import("./commands-BlDTDvFO.js");
141
+ const { commands } = await import("./commands-3qXbxhXx.js");
142
142
  (options.stdout ?? process.stdout).write(generateCompletions(options.shell, await describeCommands(commands)));
143
143
  }
144
144
  var completions_default = defineCommand({
@@ -158,4 +158,4 @@ var completions_default = defineCommand({
158
158
 
159
159
  //#endregion
160
160
  export { completions_default as default };
161
- //# sourceMappingURL=completions-DMPlZ0S1.js.map
161
+ //# sourceMappingURL=completions-Cs6YbuXO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"completions-DMPlZ0S1.js","names":[],"sources":["../src/commands/completions.ts"],"sourcesContent":["import { defineCommand, type ArgsDef, type CommandDef } from 'citty';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\n\n// citty types each command by its own arguments; the tree only needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\nexport interface CompletionFlag {\n\tname: string;\n\tdescription: string;\n\t/** Short forms, without the dash (`c` for `-c`). */\n\taliases: string[];\n\t/** A boolean that is on by default also has a `--no-<name>` form. */\n\tnegatable: boolean;\n}\n\nexport interface CompletionCommand {\n\tname: string;\n\tdescription: string;\n\tflags: CompletionFlag[];\n\tsubcommands: CompletionCommand[];\n}\n\nexport const SHELLS = ['bash', 'zsh', 'fish'] as const;\nexport type Shell = (typeof SHELLS)[number];\n\nasync function resolve<T>(value: T | Promise<T> | (() => T | Promise<T>) | undefined): Promise<T | undefined> {\n\treturn typeof value === 'function' ? (value as () => T | Promise<T>)() : value;\n}\n\n/** Walks the commands the CLI registers, so the completions never drift from what `--help` prints. */\nexport async function describeCommands(commands: Record<string, () => Promise<AnyCommand>>): Promise<CompletionCommand[]> {\n\tconst describe = async (name: string, command: AnyCommand): Promise<CompletionCommand> => {\n\t\tconst meta = (await resolve(command.meta)) ?? {};\n\t\tconst args = ((await resolve(command.args)) ?? {}) as ArgsDef;\n\t\tconst children = ((await resolve(command.subCommands)) ?? {}) as Record<string, AnyCommand | (() => Promise<AnyCommand>)>;\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription: meta.description ?? '',\n\t\t\tflags: Object.entries(args)\n\t\t\t\t.filter(([, arg]) => arg.type !== 'positional')\n\t\t\t\t.map(([flag, arg]) => ({\n\t\t\t\t\tname: flag,\n\t\t\t\t\tdescription: arg.description ?? '',\n\t\t\t\t\taliases: [(arg as { alias?: string | string[] }).alias ?? []].flat(),\n\t\t\t\t\tnegatable: arg.type === 'boolean' && arg.default === true\n\t\t\t\t})),\n\t\t\tsubcommands: await Promise.all(Object.entries(children).map(async ([child, value]) => describe(child, (await resolve(value))!)))\n\t\t};\n\t};\n\n\treturn Promise.all(Object.entries(commands).map(async ([name, load]) => describe(name, await load())));\n}\n\n/** Every spelling of a flag: `--name`, `--no-name` when it can be switched off, and its short forms. */\nconst spellings = (flag: CompletionFlag) => [\n\t`--${flag.name}`,\n\t...(flag.negatable ? [`--no-${flag.name}`] : []),\n\t...flag.aliases.map((alias) => (alias.length === 1 ? `-${alias}` : `--${alias}`))\n];\n\nconst flagsOf = (command: CompletionCommand) => [...command.flags.flatMap(spellings), '--help'].join(' ');\n\nfunction bash(commands: readonly CompletionCommand[]): string {\n\tconst cases = commands.map((command) => {\n\t\tif (command.subcommands.length === 0) return `\\t\\t${command.name}) words=\"${flagsOf(command)}\" ;;`;\n\t\tconst nested = command.subcommands.map((child) => `\\t\\t\\t\\t${child.name}) words=\"${flagsOf(child)}\" ;;`).join('\\n');\n\t\treturn [\n\t\t\t`\\t\\t${command.name})`,\n\t\t\t// The subcommand is the first of its names after the command: options of the parent may come before it.\n\t\t\t'\\t\\t\\tsub=\"\"',\n\t\t\t'\\t\\t\\tfor ((i = 2; i < COMP_CWORD; i++)); do',\n\t\t\t`\\t\\t\\t\\tcase \"\\${COMP_WORDS[i]}\" in ${command.subcommands.map((child) => child.name).join('|')}) sub=\"\\${COMP_WORDS[i]}\"; break ;; esac`,\n\t\t\t'\\t\\t\\tdone',\n\t\t\t'\\t\\t\\tcase \"$sub\" in',\n\t\t\tnested,\n\t\t\t`\\t\\t\\t\\t*) words=\"${command.subcommands.map((child) => child.name).join(' ')} ${flagsOf(command)}\" ;;`,\n\t\t\t'\\t\\t\\tesac ;;'\n\t\t].join('\\n');\n\t});\n\n\treturn `# stars completions for bash. Load them with: eval \"$(stars completions bash)\"\n_stars() {\n\tlocal cur words sub i\n\tcur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n\tif [ \"$COMP_CWORD\" -eq 1 ]; then\n\t\twords=\"${commands.map((command) => command.name).join(' ')} --help --version\"\n\telse\n\t\tcase \"\\${COMP_WORDS[1]}\" in\n${cases.join('\\n')}\n\t\t\t*) words=\"\" ;;\n\t\tesac\n\tfi\n\tCOMPREPLY=($(compgen -W \"$words\" -- \"$cur\"))\n}\ncomplete -o default -F _stars stars\n`;\n}\n\nconst quote = (text: string) => `'${text.replaceAll(\"'\", \"'\\\\''\")}'`;\n/** A zsh `_describe` entry: the colon separates the value from its description, so one in the text is escaped. */\nconst described = (name: string, description: string) => quote(`${name}:${description.replaceAll(':', '\\\\:')}`);\n\nfunction zsh(commands: readonly CompletionCommand[]): string {\n\tconst flags = (command: CompletionCommand) =>\n\t\t[\n\t\t\t...command.flags.flatMap((flag) => spellings(flag).map((spelling) => described(spelling, flag.description))),\n\t\t\tdescribed('--help', 'Show the usage')\n\t\t].join(' ');\n\tconst cases = commands.map((command) => {\n\t\tif (command.subcommands.length === 0) return `\\t\\t${command.name}) items=(${flags(command)}) ;;`;\n\t\tconst nested = command.subcommands.map((child) => `\\t\\t\\t\\t${child.name}) items=(${flags(child)}) ;;`).join('\\n');\n\t\tconst children = command.subcommands.map((child) => described(child.name, child.description)).join(' ');\n\t\treturn [\n\t\t\t`\\t\\t${command.name})`,\n\t\t\t'\\t\\t\\tsub=\"\"',\n\t\t\t'\\t\\t\\tfor word in ${words[3,CURRENT-1]}; do',\n\t\t\t`\\t\\t\\t\\tcase \"$word\" in ${command.subcommands.map((child) => child.name).join('|')}) sub=\"$word\"; break ;; esac`,\n\t\t\t'\\t\\t\\tdone',\n\t\t\t'\\t\\t\\tcase \"$sub\" in',\n\t\t\tnested,\n\t\t\t`\\t\\t\\t\\t*) items=(${children} ${flags(command)}) ;;`,\n\t\t\t'\\t\\t\\tesac ;;'\n\t\t].join('\\n');\n\t});\n\n\treturn `#compdef stars\n# stars completions for zsh. Load them with: eval \"$(stars completions zsh)\"\n_stars() {\n\tlocal -a items\n\tlocal sub word\n\tif (( CURRENT == 2 )); then\n\t\titems=(${commands.map((command) => described(command.name, command.description)).join(' ')})\n\telse\n\t\tcase \"$words[2]\" in\n${cases.join('\\n')}\n\t\tesac\n\tfi\n\t_describe 'stars' items\n}\ncompdef _stars stars\n`;\n}\n\nfunction fishFlag(condition: string, flag: CompletionFlag): string[] {\n\tconst short = flag.aliases\n\t\t.filter((alias) => alias.length === 1)\n\t\t.map((alias) => ` -s ${alias}`)\n\t\t.join('');\n\tconst line = (name: string) => `complete -c stars -n \"${condition}\" -l ${name}${name === flag.name ? short : ''} -d ${quote(flag.description)}`;\n\treturn [line(flag.name), ...(flag.negatable ? [line(`no-${flag.name}`)] : [])];\n}\n\nfunction fish(commands: readonly CompletionCommand[]): string {\n\tconst lines = ['# stars completions for fish. Load them with: stars completions fish | source', 'complete -c stars -f'];\n\tconst names = commands.map((command) => command.name).join(' ');\n\tfor (const command of commands) {\n\t\tlines.push(`complete -c stars -n \"not __fish_seen_subcommand_from ${names}\" -a ${command.name} -d ${quote(command.description)}`);\n\t\tconst children = command.subcommands.map((child) => child.name).join(' ');\n\t\tfor (const flag of command.flags) lines.push(...fishFlag(`__fish_seen_subcommand_from ${command.name}`, flag));\n\n\t\tfor (const child of command.subcommands) {\n\t\t\tlines.push(\n\t\t\t\t`complete -c stars -n \"__fish_seen_subcommand_from ${command.name}; and not __fish_seen_subcommand_from ${children}\" -a ${child.name} -d ${quote(child.description)}`\n\t\t\t);\n\t\t\tfor (const flag of child.flags.filter((candidate) => !command.flags.some((own) => own.name === candidate.name))) {\n\t\t\t\tlines.push(...fishFlag(`__fish_seen_subcommand_from ${command.name}; and __fish_seen_subcommand_from ${child.name}`, flag));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn `${lines.join('\\n')}\\n`;\n}\n\nconst GENERATORS: Record<Shell, (commands: readonly CompletionCommand[]) => string> = { bash, zsh, fish };\n\n/** The completion script of a shell, for the given commands. */\nexport function generateCompletions(shell: string, commands: readonly CompletionCommand[]): string {\n\tif (!(SHELLS as readonly string[]).includes(shell)) throw cliDiagnostics.UNKNOWN_SHELL({ shell });\n\treturn GENERATORS[shell as Shell](commands);\n}\n\nexport interface CompletionsOptions {\n\tshell: string;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport async function runCompletions(options: CompletionsOptions): Promise<void> {\n\t// Imported here: the registry imports this module, as it does every command.\n\tconst { commands } = await import('./index.js');\n\t(options.stdout ?? process.stdout).write(generateCompletions(options.shell, await describeCommands(commands)));\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'completions',\n\t\tdescription: 'Print the shell completion script for bash, zsh or fish'\n\t},\n\targs: {\n\t\tshell: {\n\t\t\ttype: 'positional',\n\t\t\tdescription: `The shell to print completions for: ${SHELLS.join(', ')}`,\n\t\t\trequired: true\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runCompletions({ shell: args.shell });\n\t}\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"completions-Cs6YbuXO.js","names":[],"sources":["../src/commands/completions.ts"],"sourcesContent":["import { defineCommand, type ArgsDef, type CommandDef } from 'citty';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\n\n// citty types each command by its own arguments; the tree only needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\nexport interface CompletionFlag {\n\tname: string;\n\tdescription: string;\n\t/** Short forms, without the dash (`c` for `-c`). */\n\taliases: string[];\n\t/** A boolean that is on by default also has a `--no-<name>` form. */\n\tnegatable: boolean;\n}\n\nexport interface CompletionCommand {\n\tname: string;\n\tdescription: string;\n\tflags: CompletionFlag[];\n\tsubcommands: CompletionCommand[];\n}\n\nexport const SHELLS = ['bash', 'zsh', 'fish'] as const;\nexport type Shell = (typeof SHELLS)[number];\n\nasync function resolve<T>(value: T | Promise<T> | (() => T | Promise<T>) | undefined): Promise<T | undefined> {\n\treturn typeof value === 'function' ? (value as () => T | Promise<T>)() : value;\n}\n\n/** Walks the commands the CLI registers, so the completions never drift from what `--help` prints. */\nexport async function describeCommands(commands: Record<string, () => Promise<AnyCommand>>): Promise<CompletionCommand[]> {\n\tconst describe = async (name: string, command: AnyCommand): Promise<CompletionCommand> => {\n\t\tconst meta = (await resolve(command.meta)) ?? {};\n\t\tconst args = ((await resolve(command.args)) ?? {}) as ArgsDef;\n\t\tconst children = ((await resolve(command.subCommands)) ?? {}) as Record<string, AnyCommand | (() => Promise<AnyCommand>)>;\n\t\treturn {\n\t\t\tname,\n\t\t\tdescription: meta.description ?? '',\n\t\t\tflags: Object.entries(args)\n\t\t\t\t.filter(([, arg]) => arg.type !== 'positional')\n\t\t\t\t.map(([flag, arg]) => ({\n\t\t\t\t\tname: flag,\n\t\t\t\t\tdescription: arg.description ?? '',\n\t\t\t\t\taliases: [(arg as { alias?: string | string[] }).alias ?? []].flat(),\n\t\t\t\t\tnegatable: arg.type === 'boolean' && arg.default === true\n\t\t\t\t})),\n\t\t\tsubcommands: await Promise.all(Object.entries(children).map(async ([child, value]) => describe(child, (await resolve(value))!)))\n\t\t};\n\t};\n\n\treturn Promise.all(Object.entries(commands).map(async ([name, load]) => describe(name, await load())));\n}\n\n/** Every spelling of a flag: `--name`, `--no-name` when it can be switched off, and its short forms. */\nconst spellings = (flag: CompletionFlag) => [\n\t`--${flag.name}`,\n\t...(flag.negatable ? [`--no-${flag.name}`] : []),\n\t...flag.aliases.map((alias) => (alias.length === 1 ? `-${alias}` : `--${alias}`))\n];\n\nconst flagsOf = (command: CompletionCommand) => [...command.flags.flatMap(spellings), '--help'].join(' ');\n\nfunction bash(commands: readonly CompletionCommand[]): string {\n\tconst cases = commands.map((command) => {\n\t\tif (command.subcommands.length === 0) return `\\t\\t${command.name}) words=\"${flagsOf(command)}\" ;;`;\n\t\tconst nested = command.subcommands.map((child) => `\\t\\t\\t\\t${child.name}) words=\"${flagsOf(child)}\" ;;`).join('\\n');\n\t\treturn [\n\t\t\t`\\t\\t${command.name})`,\n\t\t\t// The subcommand is the first of its names after the command: options of the parent may come before it.\n\t\t\t'\\t\\t\\tsub=\"\"',\n\t\t\t'\\t\\t\\tfor ((i = 2; i < COMP_CWORD; i++)); do',\n\t\t\t`\\t\\t\\t\\tcase \"\\${COMP_WORDS[i]}\" in ${command.subcommands.map((child) => child.name).join('|')}) sub=\"\\${COMP_WORDS[i]}\"; break ;; esac`,\n\t\t\t'\\t\\t\\tdone',\n\t\t\t'\\t\\t\\tcase \"$sub\" in',\n\t\t\tnested,\n\t\t\t`\\t\\t\\t\\t*) words=\"${command.subcommands.map((child) => child.name).join(' ')} ${flagsOf(command)}\" ;;`,\n\t\t\t'\\t\\t\\tesac ;;'\n\t\t].join('\\n');\n\t});\n\n\treturn `# stars completions for bash. Load them with: eval \"$(stars completions bash)\"\n_stars() {\n\tlocal cur words sub i\n\tcur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n\tif [ \"$COMP_CWORD\" -eq 1 ]; then\n\t\twords=\"${commands.map((command) => command.name).join(' ')} --help --version\"\n\telse\n\t\tcase \"\\${COMP_WORDS[1]}\" in\n${cases.join('\\n')}\n\t\t\t*) words=\"\" ;;\n\t\tesac\n\tfi\n\tCOMPREPLY=($(compgen -W \"$words\" -- \"$cur\"))\n}\ncomplete -o default -F _stars stars\n`;\n}\n\nconst quote = (text: string) => `'${text.replaceAll(\"'\", \"'\\\\''\")}'`;\n/** A zsh `_describe` entry: the colon separates the value from its description, so one in the text is escaped. */\nconst described = (name: string, description: string) => quote(`${name}:${description.replaceAll(':', '\\\\:')}`);\n\nfunction zsh(commands: readonly CompletionCommand[]): string {\n\tconst flags = (command: CompletionCommand) =>\n\t\t[\n\t\t\t...command.flags.flatMap((flag) => spellings(flag).map((spelling) => described(spelling, flag.description))),\n\t\t\tdescribed('--help', 'Show the usage')\n\t\t].join(' ');\n\tconst cases = commands.map((command) => {\n\t\tif (command.subcommands.length === 0) return `\\t\\t${command.name}) items=(${flags(command)}) ;;`;\n\t\tconst nested = command.subcommands.map((child) => `\\t\\t\\t\\t${child.name}) items=(${flags(child)}) ;;`).join('\\n');\n\t\tconst children = command.subcommands.map((child) => described(child.name, child.description)).join(' ');\n\t\treturn [\n\t\t\t`\\t\\t${command.name})`,\n\t\t\t'\\t\\t\\tsub=\"\"',\n\t\t\t'\\t\\t\\tfor word in ${words[3,CURRENT-1]}; do',\n\t\t\t`\\t\\t\\t\\tcase \"$word\" in ${command.subcommands.map((child) => child.name).join('|')}) sub=\"$word\"; break ;; esac`,\n\t\t\t'\\t\\t\\tdone',\n\t\t\t'\\t\\t\\tcase \"$sub\" in',\n\t\t\tnested,\n\t\t\t`\\t\\t\\t\\t*) items=(${children} ${flags(command)}) ;;`,\n\t\t\t'\\t\\t\\tesac ;;'\n\t\t].join('\\n');\n\t});\n\n\treturn `#compdef stars\n# stars completions for zsh. Load them with: eval \"$(stars completions zsh)\"\n_stars() {\n\tlocal -a items\n\tlocal sub word\n\tif (( CURRENT == 2 )); then\n\t\titems=(${commands.map((command) => described(command.name, command.description)).join(' ')})\n\telse\n\t\tcase \"$words[2]\" in\n${cases.join('\\n')}\n\t\tesac\n\tfi\n\t_describe 'stars' items\n}\ncompdef _stars stars\n`;\n}\n\nfunction fishFlag(condition: string, flag: CompletionFlag): string[] {\n\tconst short = flag.aliases\n\t\t.filter((alias) => alias.length === 1)\n\t\t.map((alias) => ` -s ${alias}`)\n\t\t.join('');\n\tconst line = (name: string) => `complete -c stars -n \"${condition}\" -l ${name}${name === flag.name ? short : ''} -d ${quote(flag.description)}`;\n\treturn [line(flag.name), ...(flag.negatable ? [line(`no-${flag.name}`)] : [])];\n}\n\nfunction fish(commands: readonly CompletionCommand[]): string {\n\tconst lines = ['# stars completions for fish. Load them with: stars completions fish | source', 'complete -c stars -f'];\n\tconst names = commands.map((command) => command.name).join(' ');\n\tfor (const command of commands) {\n\t\tlines.push(`complete -c stars -n \"not __fish_seen_subcommand_from ${names}\" -a ${command.name} -d ${quote(command.description)}`);\n\t\tconst children = command.subcommands.map((child) => child.name).join(' ');\n\t\tfor (const flag of command.flags) lines.push(...fishFlag(`__fish_seen_subcommand_from ${command.name}`, flag));\n\n\t\tfor (const child of command.subcommands) {\n\t\t\tlines.push(\n\t\t\t\t`complete -c stars -n \"__fish_seen_subcommand_from ${command.name}; and not __fish_seen_subcommand_from ${children}\" -a ${child.name} -d ${quote(child.description)}`\n\t\t\t);\n\t\t\tfor (const flag of child.flags.filter((candidate) => !command.flags.some((own) => own.name === candidate.name))) {\n\t\t\t\tlines.push(...fishFlag(`__fish_seen_subcommand_from ${command.name}; and __fish_seen_subcommand_from ${child.name}`, flag));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn `${lines.join('\\n')}\\n`;\n}\n\nconst GENERATORS: Record<Shell, (commands: readonly CompletionCommand[]) => string> = { bash, zsh, fish };\n\n/** The completion script of a shell, for the given commands. */\nexport function generateCompletions(shell: string, commands: readonly CompletionCommand[]): string {\n\tif (!(SHELLS as readonly string[]).includes(shell)) throw cliDiagnostics.UNKNOWN_SHELL({ shell });\n\treturn GENERATORS[shell as Shell](commands);\n}\n\nexport interface CompletionsOptions {\n\tshell: string;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport async function runCompletions(options: CompletionsOptions): Promise<void> {\n\t// Imported here: the registry imports this module, as it does every command.\n\tconst { commands } = await import('./index.js');\n\t(options.stdout ?? process.stdout).write(generateCompletions(options.shell, await describeCommands(commands)));\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'completions',\n\t\tdescription: 'Print the shell completion script for bash, zsh or fish'\n\t},\n\targs: {\n\t\tshell: {\n\t\t\ttype: 'positional',\n\t\t\tdescription: `The shell to print completions for: ${SHELLS.join(', ')}`,\n\t\t\trequired: true\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runCompletions({ shell: args.shell });\n\t}\n});\n"],"mappings":"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"}
@@ -1,21 +1,21 @@
1
1
  import { i as shouldUseColor, n as prefersReducedMotion, r as resolveOutputMode } from "./output-mode-Bp7Da8vJ.js";
2
2
  import { i as renderCrashReport, t as ExitCode } from "./errors-COFWKKKw.js";
3
- import { t as cliDiagnostics } from "./diagnostics-BysbNnPD.js";
3
+ import { t as cliDiagnostics } from "./diagnostics-Dn3CXa8J.js";
4
4
  import { a as readSavedTheme, c as saveTheme, i as isThemeSetting, n as THEME_SETTINGS, s as resolveThemeSetting } from "./theme-yS2h5dd_.js";
5
- import { r as resolveBinary } from "./project-zlQStwsf.js";
6
- import { i as createLineSplitter, n as resolveTscBinary, r as ProcessSupervisor } from "./tsc-puVAcwmo.js";
7
- import { n as createBuilder, t as Locales } from "./locales-BJAP4HYf.js";
8
- import { c as moduleImportArgs, d as resolveCwd, l as collectFlag, n as loadProject, r as withProjectEnv, s as envImportArgs, t as applyEnvOptions, u as projectArgs } from "./hooks-Cy6F2bhH.js";
9
- import { n as reportWarnings, t as prepareProject } from "./_shared-BIQK0Bhm.js";
5
+ import { r as ProcessSupervisor } from "./tsc-BArammxe.js";
6
+ import { n as createBuilder, t as Locales } from "./locales-BzyEMQnX.js";
7
+ import { c as moduleImportArgs, d as resolveCwd, l as collectFlag, n as loadProject, r as withProjectEnv, s as envImportArgs, t as applyEnvOptions, u as projectArgs } from "./hooks-D_RVS0ba.js";
8
+ import { n as reportWarnings, t as prepareProject } from "./_shared-CyzTojMA.js";
9
+ import { i as bridgeImportArgs, n as CLI_SOURCE, o as parseBridgeMessage } from "./bridge-Cbm0jX9h.js";
10
10
  import { r as diffSnapshots, t as describeCommand } from "./command-diff-BK912Hjc.js";
11
- import { i as bridgeImportArgs, n as CLI_SOURCE, o as parseBridgeMessage, s as Tunnel } from "./bridge-BegCt_n2.js";
11
+ import { t as Tunnel } from "./tunnel-BNV5cuJz.js";
12
12
  import { a as initialLogView, s as isLogLevel, x as classifyAppLine, y as LogBuffer } from "./log-view-B7uJEnMR.js";
13
+ import { t as Typechecker } from "./typechecker-C3UOI2LF.js";
13
14
  import { defineCommand } from "citty";
14
15
  import { createWriteStream, mkdirSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
15
16
  import { basename, dirname, extname, join, sep } from "node:path";
16
17
  import { displayPath } from "@wolfstar/schema";
17
18
  import { EventEmitter } from "node:events";
18
- import { spawn } from "node:child_process";
19
19
  import { stripVTControlCharacters } from "node:util";
20
20
  import { createHash } from "node:crypto";
21
21
  import { lookup } from "node:dns/promises";
@@ -91,208 +91,6 @@ function isInside(path, directory) {
91
91
  return path === directory || path.startsWith(directory.endsWith(sep) ? directory : `${directory}${sep}`);
92
92
  }
93
93
 
94
- //#endregion
95
- //#region src/dev/typechecker.ts
96
- const WATCH_START = /Starting (incremental )?compilation/;
97
- const WATCH_DONE = /Found (\d+) errors?\. Watching for file changes/;
98
- const ONE_SHOT_DONE = /Found (\d+) errors?/;
99
- const ERROR_LINE = /error TS\d+:/;
100
- /**
101
- * Runs a type checker next to the bot and reports type errors on their own channel, without ever blocking builds or
102
- * restarts: `stars dev` keeps running whatever the build tool produced, the way Seedcord's `hmr.typecheck` and
103
- * Vite's `checker` plugin do.
104
- *
105
- * `tsc` and `golar` (which forwards to TypeScript) watch the project themselves; `tsz` has no watch mode, so
106
- * {@link Typechecker.check} re-runs it after every build instead.
107
- */
108
- var Typechecker = class extends EventEmitter {
109
- config;
110
- #child = null;
111
- #state = "idle";
112
- #errors = 0;
113
- #pending = false;
114
- constructor(config) {
115
- super();
116
- this.config = config;
117
- }
118
- get state() {
119
- return this.#state;
120
- }
121
- get errors() {
122
- return this.#errors;
123
- }
124
- /** Whether the checker re-runs per build instead of watching on its own. */
125
- get oneShot() {
126
- return this.config.dev.typecheck.enabled && !resolveTypecheckCommand(this.config).watch;
127
- }
128
- start() {
129
- if (!this.config.dev.typecheck.enabled) return;
130
- this.#run();
131
- }
132
- /**
133
- * Re-runs a checker that cannot watch. Called after every successful build; a run already in flight is replaced,
134
- * so a fast series of builds only leaves the last check standing.
135
- */
136
- check() {
137
- if (!this.oneShot) return;
138
- if (this.#child) {
139
- this.#pending = true;
140
- this.#child.kill();
141
- return;
142
- }
143
- this.#run();
144
- }
145
- close() {
146
- const child = this.#child;
147
- this.#child = null;
148
- this.#pending = false;
149
- if (!child || child.exitCode !== null) return Promise.resolve();
150
- return new Promise((resolve) => {
151
- child.once("exit", () => resolve());
152
- child.kill();
153
- });
154
- }
155
- #run() {
156
- const { command, args, node, watch } = resolveTypecheckCommand(this.config);
157
- const child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {
158
- cwd: this.config.root,
159
- env: process.env,
160
- stdio: [
161
- "ignore",
162
- "pipe",
163
- "pipe"
164
- ],
165
- windowsHide: true
166
- });
167
- this.#child = child;
168
- this.#setState("checking", 0);
169
- let errors = 0;
170
- const handleLine = (line) => {
171
- if (ERROR_LINE.test(line)) errors++;
172
- this.#handleLine(line);
173
- };
174
- const stdout = createLineSplitter(handleLine);
175
- const stderr = createLineSplitter(handleLine);
176
- child.stdout?.on("data", stdout.push);
177
- child.stderr?.on("data", stderr.push);
178
- child.once("exit", (code) => {
179
- stdout.flush();
180
- stderr.flush();
181
- this.#child = null;
182
- if (!watch && this.#state === "checking") this.#setState(code === 0 && errors === 0 ? "ok" : "failed", errors);
183
- if (this.#pending) {
184
- this.#pending = false;
185
- this.#run();
186
- }
187
- });
188
- child.once("error", (error) => {
189
- this.#child = null;
190
- this.emit("log", "error", error.code === "ENOENT" ? `${command} is not installed` : error.message);
191
- this.#setState("failed", this.#errors);
192
- });
193
- }
194
- #handleLine(line) {
195
- const text = line.trim();
196
- if (text.length === 0) return;
197
- if (WATCH_START.test(text)) {
198
- this.#setState("checking", 0);
199
- return;
200
- }
201
- if (ERROR_LINE.test(text)) {
202
- this.emit("log", "error", text);
203
- return;
204
- }
205
- const done = WATCH_DONE.exec(text) ?? ONE_SHOT_DONE.exec(text);
206
- if (done) {
207
- const errors = Number(done[1]);
208
- this.#setState(errors === 0 ? "ok" : "failed", errors);
209
- this.emit("log", errors === 0 ? "success" : "error", errors === 0 ? "No type errors" : `${errors} type error${errors === 1 ? "" : "s"}`);
210
- return;
211
- }
212
- this.emit("log", "info", text);
213
- }
214
- #setState(state, errors) {
215
- this.#state = state;
216
- this.#errors = errors;
217
- this.emit("state", state, errors);
218
- }
219
- };
220
- /**
221
- * Builds the command line of the configured type checker, resolved from the project's own `node_modules`.
222
- *
223
- * @throws {Diagnostic} when the checker is not installed in the project.
224
- */
225
- function resolveTypecheckCommand(config) {
226
- const { checker, tsconfig } = config.dev.typecheck;
227
- const project = tsconfig;
228
- switch (checker) {
229
- case "golar": {
230
- const golar = resolveBinary(config.root, "golar", "golar");
231
- if (!golar) throw missing(config, "golar", "Install it with `pnpm add -D golar`");
232
- return {
233
- command: golar,
234
- args: [
235
- "tsc",
236
- ...WATCH_ARGS,
237
- "-p",
238
- project
239
- ],
240
- node: true,
241
- watch: true
242
- };
243
- }
244
- case "tsz": {
245
- const tsz = resolveBinary(config.root, "@mohsen-azimi/tsz-dev", "tsz");
246
- if (tsz) return {
247
- command: tsz,
248
- args: [
249
- "--noEmit",
250
- "-p",
251
- project
252
- ],
253
- node: true,
254
- watch: false
255
- };
256
- const tryTsz = resolveBinary(config.root, "try-tsz", "try-tsz");
257
- if (tryTsz) return {
258
- command: tryTsz,
259
- args: ["-p", project],
260
- node: true,
261
- watch: false
262
- };
263
- throw missing(config, "tsz", "Install it with `pnpm add -D @mohsen-azimi/tsz-dev` (or `try-tsz`)");
264
- }
265
- default: {
266
- const tsc = resolveTscBinary(config.root);
267
- if (!tsc) throw missing(config, "typescript", "Install it with `pnpm add -D typescript`");
268
- return {
269
- command: tsc,
270
- args: [
271
- ...WATCH_ARGS,
272
- "-p",
273
- project
274
- ],
275
- node: true,
276
- watch: true
277
- };
278
- }
279
- }
280
- }
281
- const WATCH_ARGS = [
282
- "--noEmit",
283
- "--watch",
284
- "--preserveWatchOutput",
285
- "--pretty",
286
- "false"
287
- ];
288
- function missing(config, name, install) {
289
- return cliDiagnostics.DEPENDENCY_MISSING({
290
- name,
291
- root: config.root,
292
- hint: `${install}, pick another \`dev.typecheck.checker\`, or set \`dev.typecheck\` to false.`
293
- });
294
- }
295
-
296
94
  //#endregion
297
95
  //#region src/dev/dev-service.ts
298
96
  /**
@@ -310,6 +108,7 @@ var DevService = class extends EventEmitter {
310
108
  /** Whether something can answer a {@link DevPrompt}: the interactive UI sets it, the plain renderer cannot. */
311
109
  promptable = false;
312
110
  #hooks;
111
+ #openTunnel;
313
112
  /** Runs hooks one at a time, so an async `build:done` settles before the next build's hooks or a restart. */
314
113
  #hookChain = Promise.resolve();
315
114
  #build = "idle";
@@ -356,6 +155,7 @@ var DevService = class extends EventEmitter {
356
155
  this.tunnel = options.tunnel ?? new Tunnel(config);
357
156
  this.locales = new Locales(config);
358
157
  this.#hooks = options.hooks ?? null;
158
+ this.#openTunnel = options.openTunnel;
359
159
  this.builder.on("start", () => {
360
160
  this.#progress = {
361
161
  fraction: 0,
@@ -452,7 +252,7 @@ var DevService = class extends EventEmitter {
452
252
  this.log("stars", "info", this.config.build.tool === "none" ? `Watching ${entry}` : `Watching ${entry} with ${this.config.build.tool}`);
453
253
  if (this.config.dev.typecheck.enabled) this.typechecker.start();
454
254
  await this.locales.watch();
455
- this.tunnel.start();
255
+ if (this.#openTunnel !== false) this.tunnel.start(this.#openTunnel === true);
456
256
  await this.builder.watch();
457
257
  }
458
258
  /**
@@ -1046,7 +846,8 @@ async function runDev(options) {
1046
846
  await hooks.callHook("builder:created", builder, config);
1047
847
  const service = new DevService(config, {
1048
848
  builder,
1049
- hooks
849
+ hooks,
850
+ openTunnel: options.tunnel
1050
851
  });
1051
852
  await reportWarnings(config, (text) => service.log("stars", "warn", text), { production: false });
1052
853
  const logFiles = [...config.dev.logFile ? [config.dev.logFile] : [], ...config.dev.logs?.dir ? [runLogFile(config.dev.logs.dir, config.dev.logs.keep)] : []].map((file) => new LogFileWriter(file, service.logs));
@@ -1055,7 +856,7 @@ async function runDev(options) {
1055
856
  channels: options.channel,
1056
857
  level: options.level
1057
858
  });
1058
- const renderer = mode === "tui" ? (await import("./tui-nldGSD4c.js")).createTuiRenderer(service, {
859
+ const renderer = mode === "tui" ? (await import("./tui-CB_qk2Z1.js")).createTuiRenderer(service, {
1059
860
  color,
1060
861
  theme,
1061
862
  layout,
@@ -1148,6 +949,11 @@ var dev_default = defineCommand({
1148
949
  level: {
1149
950
  type: "string",
1150
951
  description: `Only show this log level and the more severe ones at start: ${LEVELS.join(", ")} (defaults to dev.logs.levels)`
952
+ },
953
+ tunnel: {
954
+ type: "boolean",
955
+ description: "Open the public tunnel at start, whatever dev.tunnel says",
956
+ negativeDescription: "Keep the public tunnel closed at start even when dev.tunnel enables it"
1151
957
  }
1152
958
  },
1153
959
  async run({ args, rawArgs }) {
@@ -1159,11 +965,12 @@ var dev_default = defineCommand({
1159
965
  theme: args.theme,
1160
966
  layout: args.layout,
1161
967
  channel: channel.length > 0 ? channel : void 0,
1162
- level: args.level
968
+ level: args.level,
969
+ tunnel: args.tunnel
1163
970
  });
1164
971
  }
1165
972
  });
1166
973
 
1167
974
  //#endregion
1168
975
  export { dev_default as default };
1169
- //# sourceMappingURL=dev-Owu3e3AO.js.map
976
+ //# sourceMappingURL=dev-9YvzhtkU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-9YvzhtkU.js","names":[],"sources":["../src/dev/changed-files.ts","../src/dev/dev-service.ts","../src/dev/host.ts","../src/dev/log-file.ts","../src/commands/dev.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { readdirSync, readFileSync, statSync } from 'node:fs';\nimport { basename, extname, join, sep } from 'node:path';\n\nconst SKIPPED_DIRECTORIES = new Set(['node_modules', '.git']);\n/**\n * `tsc -b` rewrites its build info on every build, whatever changed; a source map only ever changes with the file it\n * maps, and is most of what there would be to read.\n */\nconst SKIPPED_FILES = /\\.(?:tsbuildinfo|map)$/;\n\n/** The content hash of every file under the roots, by absolute path. */\nexport type FileSnapshot = ReadonlyMap<string, string>;\n\n/** What was last read of each file, so one that was not touched since is not read again. */\nexport type HashCache = Map<string, { size: number; mtimeMs: number; hash: string }>;\n\n/**\n * Hashes every file under `roots`, skipping `node_modules`, `.git` and everything under `exclude`.\n *\n * The builders only report that a build finished, and a bundler rewrites files it did not change (`tsdown` writes\n * its whole output on every rebuild), so neither an event nor a modification time says what a build changed: two\n * snapshots do (see {@link changedFiles}).\n */\nexport function snapshotFiles(roots: readonly string[], exclude: readonly string[] = [], cache: HashCache = new Map()): FileSnapshot {\n\tconst snapshot = new Map<string, string>();\n\tconst visit = (directory: string) => {\n\t\tlet entries;\n\t\ttry {\n\t\t\tentries = readdirSync(directory, { withFileTypes: true });\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const entry of entries) {\n\t\t\tconst path = join(directory, entry.name);\n\t\t\tif (exclude.some((excluded) => isInside(path, excluded))) continue;\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tif (!SKIPPED_DIRECTORIES.has(entry.name)) visit(path);\n\t\t\t} else if (entry.isFile() && !SKIPPED_FILES.test(entry.name)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst { size, mtimeMs } = statSync(path);\n\t\t\t\t\tconst known = cache.get(path);\n\t\t\t\t\tconst hash =\n\t\t\t\t\t\tknown?.size === size && known.mtimeMs === mtimeMs\n\t\t\t\t\t\t\t? known.hash\n\t\t\t\t\t\t\t: createHash('sha1').update(readFileSync(path)).digest('base64');\n\t\t\t\t\tcache.set(path, { size, mtimeMs, hash });\n\t\t\t\t\tsnapshot.set(path, hash);\n\t\t\t\t} catch {\n\t\t\t\t\t// Removed between the listing and the read: the next build reports it.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tfor (const root of new Set(roots)) visit(root);\n\treturn snapshot;\n}\n\n/** The files that were added, removed, or whose content differs between two snapshots. */\nexport function changedFiles(previous: FileSnapshot, next: FileSnapshot): string[] {\n\tconst changed = [...next].filter(([path, hash]) => previous.get(path) !== hash).map(([path]) => path);\n\tfor (const path of previous.keys()) {\n\t\tif (!next.has(path)) changed.push(path);\n\t}\n\n\treturn changed;\n}\n\nconst PIECE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts']);\n\n/**\n * Whether a file a store has not loaded yet could be a piece, by the rule the stores filter files with: a script\n * that is not a declaration file and whose name does not start with `_`.\n */\nexport function couldBePiece(path: string): boolean {\n\tconst extension = extname(path);\n\treturn PIECE_EXTENSIONS.has(extension) && !path.endsWith('.d.ts') && !basename(path, extension).startsWith('_');\n}\n\n/** Whether `path` is `directory` itself or lies under it. */\nexport function isInside(path: string, directory: string): boolean {\n\treturn path === directory || path.startsWith(directory.endsWith(sep) ? directory : `${directory}${sep}`);\n}\n","import { EventEmitter } from 'node:events';\nimport type { Builder, BuildOutcome } from '../builders/types.js';\nimport { displayPath, type ResolvedStarsConfig, type StarsHooks, type StarsRestartReason } from '@wolfstar/schema';\nimport { describeCommand, diffSnapshots, type CommandChange } from '../utils/command-diff.js';\nimport { envImportArgs, moduleImportArgs } from '../utils/env-import.js';\nimport type { StarsHookable } from '../utils/hooks.js';\nimport { classifyAppLine, LogBuffer, type LogLevel, type LogSource } from '../utils/log-buffer.js';\nimport { Locales } from '../utils/locales.js';\nimport { ProcessSupervisor, type ProcessExit, type ProcessState } from '../utils/process-supervisor.js';\nimport { bridgeImportArgs, CLI_SOURCE, parseBridgeMessage, type BridgeMessage, type CommandSnapshot, type RefreshRequest } from './bridge.js';\nimport { changedFiles, couldBePiece, isInside, snapshotFiles, type FileSnapshot, type HashCache } from './changed-files.js';\nimport { Tunnel, type TunnelState } from './tunnel.js';\nimport { Typechecker, type TypecheckState } from './typechecker.js';\n\nexport type BuildState = 'idle' | 'building' | 'ok' | 'failed';\nexport type HealthState = 'unknown' | 'ok' | 'down';\nexport type RestartReason = StarsRestartReason;\n\n/** A question the dev UI asks the user; {@link DevService.answerPrompt} settles it. */\nexport interface DevPrompt {\n\treadonly kind: 'commands';\n\treadonly changes: readonly CommandChange[];\n}\n\nexport interface LogExtra {\n\t/** The channel to log on instead of the source's own. */\n\tchannel?: string;\n\tdetail?: readonly string[];\n}\n\nexport interface DevStatus {\n\treadonly progress: { readonly fraction: number; readonly message: string; readonly startedAt: number; readonly readyMs: number | null };\n\treadonly process: ProcessState;\n\treadonly build: BuildState;\n\treadonly health: HealthState;\n\treadonly pid: number | null;\n\treadonly startedAt: number | null;\n\treadonly restarts: number;\n\treadonly lastRestartReason: RestartReason | null;\n\treadonly lastBuild: BuildOutcome | null;\n\treadonly lastExit: ProcessExit | null;\n\treadonly url: string | null;\n\treadonly typecheck: TypecheckState;\n\treadonly typeErrors: number;\n\treadonly tunnel: TunnelState;\n\treadonly tunnelUrl: string | null;\n\t/** Whether the running bot reported that it is listening (see the bridge); always `false` without the bridge. */\n\treadonly ready: boolean;\n\t/** The port the bot reported it listens on. */\n\treadonly port: number | null;\n\t/** Whether the running bot reported that it hot reloads its pieces. */\n\treadonly hmr: boolean;\n\t/** Whether the bot was stopped on purpose (the `d` key) and waits for a restart. */\n\treadonly paused: boolean;\n\treadonly prompt: DevPrompt | null;\n}\n\nexport interface DevServiceEvents {\n\tstatus: [status: DevStatus];\n}\n\nexport interface DevServiceOptions {\n\tbuilder: Builder;\n\t/** The `stars.config` hooks; `build:*` and `dev:restart` run from here. */\n\thooks?: StarsHookable;\n\tlogs?: LogBuffer;\n\t/** Overrides for tests. */\n\tsupervisor?: ProcessSupervisor;\n\ttypechecker?: Typechecker;\n\ttunnel?: Tunnel;\n\thealthInterval?: number;\n\t/**\n\t * Whether the tunnel opens at start: `true` opens it whatever `dev.tunnel` says (a quick tunnel when it is off),\n\t * `false` keeps it closed, and `undefined` leaves it to `dev.tunnel`. The `--tunnel`/`--no-tunnel` flags.\n\t */\n\topenTunnel?: boolean;\n}\n\n/**\n * The headless heart of `stars dev`: builds, (re)starts the bot and exposes state and logs.\n * Renderers (plain or TUI) only subscribe to it, they never own behaviour.\n */\nexport class DevService extends EventEmitter<DevServiceEvents> {\n\tpublic readonly logs: LogBuffer;\n\tpublic readonly builder: Builder;\n\tpublic readonly supervisor: ProcessSupervisor;\n\tpublic readonly typechecker: Typechecker;\n\tpublic readonly tunnel: Tunnel;\n\tpublic readonly locales: Locales;\n\t/** Whether something can answer a {@link DevPrompt}: the interactive UI sets it, the plain renderer cannot. */\n\tpublic promptable = false;\n\treadonly #hooks: StarsHookable | null;\n\treadonly #openTunnel: boolean | undefined;\n\t/** Runs hooks one at a time, so an async `build:done` settles before the next build's hooks or a restart. */\n\t#hookChain: Promise<void> = Promise.resolve();\n\n\t#build: BuildState = 'idle';\n\t#health: HealthState = 'unknown';\n\t#restarts = 0;\n\t#lastRestartReason: RestartReason | null = null;\n\t#lastBuild: BuildOutcome | null = null;\n\t#lastExit: ProcessExit | null = null;\n\t#restartTimer: NodeJS.Timeout | null = null;\n\t#healthTimer: NodeJS.Timeout | null = null;\n\t#pendingReason: RestartReason | null = null;\n\t#stopped = false;\n\t#queue: Promise<void> = Promise.resolve();\n\t#progress = { fraction: 0, message: 'preparing your app', startedAt: Date.now(), readyMs: null as number | null };\n\t#ready = false;\n\t#port: number | null = null;\n\t/** The store paths the running bot watches for hot reloads, empty when it does not. */\n\t#hmrPaths: string[] = [];\n\t#paused = false;\n\t#prompt: DevPrompt | null = null;\n\t/** The commands the bot last reported, kept across restarts: a restart is how most changes arrive. */\n\t#commands: CommandSnapshot | null = null;\n\t/** What the build output held after the previous build, `null` before the first one. */\n\t#files: FileSnapshot | null = null;\n\treadonly #hashes: HashCache = new Map();\n\t/** The files the running bot loaded pieces from: what its hot reload can replace. */\n\t#pieces = new Set<string>();\n\t/** The commands Discord is assumed to have: the first report of the session, then whatever was last deployed. */\n\t#deployed: CommandSnapshot | null = null;\n\t/** A refresh of the commands asked for while the bot was not listening; sent once it is. */\n\t#refreshPending = false;\n\n\tpublic constructor(\n\t\tpublic readonly config: ResolvedStarsConfig,\n\t\toptions: DevServiceOptions\n\t) {\n\t\tsuper();\n\t\tthis.logs = options.logs ?? new LogBuffer();\n\t\tthis.builder = options.builder;\n\t\tthis.supervisor = options.supervisor ?? createSupervisor(config);\n\t\tthis.typechecker = options.typechecker ?? new Typechecker(config);\n\t\tthis.tunnel = options.tunnel ?? new Tunnel(config);\n\t\tthis.locales = new Locales(config);\n\t\tthis.#hooks = options.hooks ?? null;\n\t\tthis.#openTunnel = options.openTunnel;\n\n\t\tthis.builder.on('start', () => {\n\t\t\tthis.#progress = { fraction: 0, message: 'preparing build', startedAt: Date.now(), readyMs: null };\n\t\t\tthis.#setBuild('building');\n\t\t\tvoid this.#startHook('build:before', this.config);\n\t\t});\n\t\tthis.builder.on('progress', (fraction, message) => {\n\t\t\tthis.#progress = { ...this.#progress, fraction: Math.max(this.#progress.fraction, Math.min(0.75, fraction)), message };\n\t\t\tthis.#emitStatus();\n\t\t});\n\t\tthis.builder.on('success', (outcome) => this.#onBuildSuccess(outcome));\n\t\tthis.builder.on('failure', (outcome) => this.#onBuildFailure(outcome));\n\t\tthis.builder.on('log', (level, text) => this.log('build', level, text));\n\n\t\tthis.supervisor.on('state', () => {\n\t\t\tif (this.supervisor.state === 'running') {\n\t\t\t\tthis.#settleProgress();\n\t\t\t\tvoid this.#checkHealth();\n\t\t\t}\n\t\t\tthis.#emitStatus();\n\t\t});\n\t\tthis.supervisor.on('stdout', (line) => this.log('app', classifyAppLine(line, 'info'), line));\n\t\tthis.supervisor.on('stderr', (line) => this.log('app', classifyAppLine(line, 'error'), line));\n\t\tthis.supervisor.on('message', (message) => {\n\t\t\tconst parsed = parseBridgeMessage(message);\n\t\t\tif (parsed === null) return;\n\t\t\ttry {\n\t\t\t\tthis.#onBridge(parsed);\n\t\t\t} catch (error) {\n\t\t\t\t// Whatever the bot sends, it must not take the session down.\n\t\t\t\tthis.log('stars', 'warn', `Ignored a ${parsed.type} message from the bot: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t}\n\t\t});\n\t\tthis.supervisor.on('error', (error) => this.log('stars', 'error', `Failed to start the bot: ${error.message}`));\n\t\tthis.supervisor.on('exit', (exit) => this.#onExit(exit));\n\n\t\tthis.typechecker.on('log', (level, text) => this.log('tsc', level, text));\n\t\tthis.typechecker.on('state', () => this.#emitStatus());\n\t\tthis.tunnel.on('log', (level, text) => this.log('tunnel', level, text));\n\t\tthis.tunnel.on('state', () => this.#emitStatus());\n\t\tthis.locales.on('log', (level, text) => this.log('build', level, text));\n\t\tthis.locales.on('change', () => {\n\t\t\tif (this.#build === 'ok') this.#scheduleRestart('build');\n\t\t});\n\n\t\tif (config.dev.url && config.dev.health) {\n\t\t\tconst interval = options.healthInterval ?? 5000;\n\t\t\tthis.#healthTimer = setInterval(() => void this.#checkHealth(), interval);\n\t\t\tthis.#healthTimer.unref();\n\t\t}\n\t}\n\n\tpublic get status(): DevStatus {\n\t\treturn {\n\t\t\tprogress: this.#progress,\n\t\t\tprocess: this.supervisor.state,\n\t\t\tbuild: this.#build,\n\t\t\thealth: this.#health,\n\t\t\tpid: this.supervisor.pid,\n\t\t\tstartedAt: this.supervisor.startedAt,\n\t\t\trestarts: this.#restarts,\n\t\t\tlastRestartReason: this.#lastRestartReason,\n\t\t\tlastBuild: this.#lastBuild,\n\t\t\tlastExit: this.#lastExit,\n\t\t\turl: this.config.dev.url,\n\t\t\ttypecheck: this.typechecker.state,\n\t\t\ttypeErrors: this.typechecker.errors,\n\t\t\ttunnel: this.tunnel.state,\n\t\t\ttunnelUrl: this.tunnel.url,\n\t\t\tready: this.#ready,\n\t\t\tport: this.#port,\n\t\t\thmr: this.#hmrPaths.length > 0,\n\t\t\tpaused: this.#paused,\n\t\t\tprompt: this.#prompt\n\t\t};\n\t}\n\n\tpublic log(source: LogSource, level: LogLevel, text: string, extra: LogExtra = {}): void {\n\t\tthis.logs.push({ source, level, text, ...extra });\n\t}\n\n\t/**\n\t * Starts watching; the bot starts after the first successful build.\n\t */\n\tpublic async start(): Promise<void> {\n\t\tthis.#stopped = false;\n\t\tconst entry = displayPath(this.config.root, this.config.entry);\n\t\tthis.log('stars', 'info', this.config.build.tool === 'none' ? `Watching ${entry}` : `Watching ${entry} with ${this.config.build.tool}`);\n\t\tif (this.config.dev.typecheck.enabled) this.typechecker.start();\n\t\tawait this.locales.watch();\n\t\t// The tunnel comes up next to the build: neither waits for the other, and a failed tunnel never stops the bot.\n\t\t// `--no-tunnel` only keeps it closed at start: the `t` key still opens one.\n\t\tif (this.#openTunnel !== false) void this.tunnel.start(this.#openTunnel === true);\n\t\tawait this.builder.watch();\n\t}\n\n\t/**\n\t * Restarts the bot immediately (used by the `r` key and by `SIGUSR2`).\n\t */\n\tpublic restart(reason: RestartReason = 'manual'): Promise<void> {\n\t\tthis.#clearRestartTimer();\n\t\treturn this.#enqueue(async () => {\n\t\t\tif (this.#stopped) return;\n\t\t\tawait this.#queueHook('dev:restart', reason, this.config);\n\t\t\tif (this.#stopped) return;\n\t\t\tif (reason === 'manual' || reason === 'crash') {\n\t\t\t\tthis.#progress = { fraction: 0, message: 'restarting the bot', startedAt: Date.now(), readyMs: null };\n\t\t\t}\n\t\t\tthis.#lastRestartReason = reason;\n\t\t\tif (this.supervisor.running) {\n\t\t\t\tthis.#restarts++;\n\t\t\t\tthis.log('stars', 'info', `Restarting (${describeReason(reason)})`);\n\t\t\t\tawait this.supervisor.stop();\n\t\t\t} else {\n\t\t\t\tthis.log('stars', 'info', `Starting (${describeReason(reason)})`);\n\t\t\t}\n\n\t\t\tif (this.#stopped) return;\n\t\t\tthis.#progress = { ...this.#progress, fraction: 0.75, message: 'starting the bot' };\n\t\t\tthis.#health = 'unknown';\n\t\t\tthis.#paused = false;\n\t\t\tthis.supervisor.start();\n\t\t\tthis.#emitStatus();\n\t\t});\n\t}\n\n\t/**\n\t * Stops the bot and leaves it stopped (the `d` key): builds keep running, but nothing starts the bot again until\n\t * {@link restart}. For when the bot must be off without ending the session.\n\t */\n\tpublic disconnect(): Promise<void> {\n\t\tthis.#clearRestartTimer();\n\t\treturn this.#enqueue(async () => {\n\t\t\tif (this.#stopped || this.#paused) return;\n\t\t\tthis.#paused = true;\n\t\t\tthis.log('stars', 'info', 'Stopped the bot, press r to start it again');\n\t\t\tawait this.supervisor.stop();\n\t\t\tthis.#emitStatus();\n\t\t});\n\t}\n\n\t/** Settles the pending {@link DevPrompt}: `true` does what it asks, `false` dismisses it. */\n\tpublic answerPrompt(accept: boolean): void {\n\t\tconst prompt = this.#prompt;\n\t\tif (prompt === null) return;\n\t\tthis.#prompt = null;\n\t\tif (accept) this.refreshCommands();\n\t\telse this.log('stars', 'info', 'Kept the deployed commands as they are', { channel: 'commands' });\n\t\tthis.#emitStatus();\n\t}\n\n\t/** Asks the bot to register its commands with Discord again. The bot answers on the `commands` channel. */\n\tpublic refreshCommands(): void {\n\t\t// A bot that is stopped or restarting has no client to register anything with: the refresh waits for it to listen.\n\t\tif (!this.#ready) {\n\t\t\tthis.#refreshPending = true;\n\t\t\tconst when = this.supervisor.running ? 'once the bot is ready' : 'when the bot starts again';\n\t\t\tthis.log('stars', 'info', `Refreshing commands ${when}…`, { channel: 'commands' });\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#refreshPending = false;\n\t\tconst current = this.#commands?.guilds ?? {};\n\t\tconst request: RefreshRequest = {\n\t\t\tsource: CLI_SOURCE,\n\t\t\ttype: 'commands:refresh',\n\t\t\tclearGuilds: Object.keys(this.#deployed?.guilds ?? {}).filter((guild) => !Object.hasOwn(current, guild))\n\t\t};\n\t\tif (this.supervisor.send(request)) {\n\t\t\tthis.log('stars', 'info', 'Refreshing commands…', { channel: 'commands' });\n\t\t} else {\n\t\t\tthis.log('stars', 'warn', 'Could not reach the bot to refresh its commands', { channel: 'commands' });\n\t\t}\n\t}\n\n\t/** Opens or closes the public tunnel (used by the `t` key). */\n\tpublic toggleTunnel(): Promise<void> {\n\t\treturn this.tunnel.toggle();\n\t}\n\n\t/**\n\t * Stops the watcher and the bot. Safe to call more than once.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tthis.#stopped = true;\n\t\tthis.#clearRestartTimer();\n\t\tif (this.#healthTimer) clearInterval(this.#healthTimer);\n\t\tthis.#healthTimer = null;\n\t\tawait this.#enqueue(async () => {\n\t\t\tawait Promise.allSettled([\n\t\t\t\tthis.builder.close(),\n\t\t\t\tthis.supervisor.stop(),\n\t\t\t\tthis.typechecker.close(),\n\t\t\t\tthis.tunnel.close(),\n\t\t\t\tthis.locales.close()\n\t\t\t]);\n\t\t});\n\t}\n\n\t/**\n\t * Kills the bot and the helper processes without waiting for them. Only for a forced shutdown, {@link stop} is the graceful path.\n\t */\n\tpublic kill(): void {\n\t\tthis.#stopped = true;\n\t\tthis.#clearRestartTimer();\n\t\tthis.supervisor.kill();\n\t\tvoid this.typechecker.close();\n\t\tvoid this.tunnel.close();\n\t}\n\n\tpublic clearLogs(): void {\n\t\tthis.logs.clear();\n\t}\n\n\t#onBuildSuccess(outcome: BuildOutcome): void {\n\t\t// Before the locales are copied: the copy rewrites every file, which is not what the build changed.\n\t\tconst hot = this.#hotReloadable();\n\t\ttry {\n\t\t\tthis.locales.copy();\n\t\t} catch (error) {\n\t\t\tthis.#onBuildFailure({\n\t\t\t\t...outcome,\n\t\t\t\tok: false,\n\t\t\t\tmessage: `Failed to copy locales: ${error instanceof Error ? error.message : String(error)}`\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.#lastBuild = outcome;\n\t\tthis.#progress = { ...this.#progress, fraction: 0.75, message: 'starting the bot' };\n\t\tthis.#setBuild('ok');\n\t\t// Only once locales are copied: until then the build is not done, and may still fail.\n\t\tvoid this.#queueHook('build:done', outcome, this.config);\n\t\tif (this.#stopped) return;\n\t\t// A checker without a watch mode (`tsz`) only knows about the change once the build is through.\n\t\tthis.typechecker.check();\n\t\tthis.log('stars', 'success', this.builder.tool === 'none' ? 'Sources changed' : `Build succeeded in ${outcome.durationMs}ms`);\n\t\tif (this.#paused) return;\n\t\tif (hot !== null) {\n\t\t\tfor (const file of hot) this.log('stars', 'trace', `UPDATE ${displayPath(this.config.root, file)}`, { channel: 'hmr' });\n\t\t\tthis.#settleProgress();\n\t\t\tthis.#emitStatus();\n\t\t\treturn;\n\t\t}\n\t\tthis.#scheduleRestart(this.supervisor.state === 'idle' ? 'initial' : 'build');\n\t}\n\n\t/**\n\t * The files the build rewrote when all of them are pieces the running bot hot reloads, `null` when the bot has to\n\t * be restarted instead: it is not running, it does not hot reload, `dev.hmr` is off, nothing changed (a rebuild for\n\t * a reason that cannot be seen from the output), or a file changed that the bot cannot replace. What a build changed\n\t * is the difference in content with the previous output, since a bundler rewrites files it did not change.\n\t *\n\t * The bot replaces the files it loaded pieces from, and loads a new file that could be one. A helper module next to\n\t * the pieces (`_shared.js`, or any file no piece came from) is imported once and stays as it was: changing it\n\t * needs a restart, even though it lies in a store path.\n\t */\n\t#hotReloadable(): string[] | null {\n\t\tif (this.config.dev.hmr === false) return null;\n\n\t\tconst roots = this.config.build.tool === 'none' ? this.config.dev.watch : [this.config.build.outDir];\n\t\tconst previous = this.#files;\n\t\tthis.#files = snapshotFiles(roots, [this.locales.destination], this.#hashes);\n\t\tif (previous === null || this.#hmrPaths.length === 0 || this.supervisor.state !== 'running') return null;\n\n\t\tconst changed = changedFiles(previous, this.#files);\n\t\tconst replaceable = (file: string) =>\n\t\t\tthis.#hmrPaths.some((path) => isInside(file, path)) && (this.#pieces.has(file) || (!previous.has(file) && couldBePiece(file)));\n\t\treturn changed.length > 0 && changed.every(replaceable) ? changed : null;\n\t}\n\n\t#onBuildFailure(outcome: BuildOutcome): void {\n\t\tthis.#lastBuild = outcome;\n\t\tvoid this.#queueHook('build:done', outcome, this.config);\n\t\tthis.#setBuild('failed');\n\t\tthis.#clearRestartTimer();\n\t\tthis.log('stars', 'error', `Build failed${outcome.message ? `: ${outcome.message}` : ''}, waiting for changes`);\n\t}\n\n\t#onExit(exit: ProcessExit): void {\n\t\tthis.#lastExit = exit;\n\t\tthis.#health = 'unknown';\n\t\tthis.#ready = false;\n\t\tthis.#port = null;\n\t\tthis.#hmrPaths = [];\n\t\tthis.#pieces.clear();\n\t\t// A pending prompt stays: the commands still differ from what Discord has, and the next process can deploy them.\n\t\tif (!exit.requested) {\n\t\t\tconst how = exit.signal ? `signal ${exit.signal}` : `code ${exit.code}`;\n\t\t\tthis.log('stars', exit.code === 0 ? 'warn' : 'error', `The bot exited with ${how}, waiting for changes (press r to restart)`);\n\t\t}\n\t\tthis.#emitStatus();\n\t}\n\n\t#scheduleRestart(reason: RestartReason): void {\n\t\tif (this.#paused) return;\n\t\tthis.#pendingReason = reason;\n\t\tthis.#clearRestartTimer();\n\t\tthis.#restartTimer = setTimeout(() => {\n\t\t\tthis.#restartTimer = null;\n\t\t\tconst pending = this.#pendingReason ?? reason;\n\t\t\tthis.#pendingReason = null;\n\t\t\tvoid this.restart(pending);\n\t\t}, this.config.dev.debounce);\n\t}\n\n\t#clearRestartTimer(): void {\n\t\tif (this.#restartTimer) clearTimeout(this.#restartTimer);\n\t\tthis.#restartTimer = null;\n\t}\n\n\t#enqueue(task: () => Promise<void>): Promise<void> {\n\t\tthis.#queue = this.#queue.then(task, task);\n\t\treturn this.#queue;\n\t}\n\n\t#setBuild(state: BuildState): void {\n\t\tif (this.#build === state) return;\n\t\tthis.#build = state;\n\t\tthis.#emitStatus();\n\t}\n\n\tasync #checkHealth(): Promise<void> {\n\t\tif (!this.supervisor.running || !this.config.dev.url || !this.config.dev.health) return;\n\t\tconst pid = this.supervisor.pid;\n\n\t\tlet next: HealthState;\n\t\ttry {\n\t\t\tconst response = await fetch(new URL(this.config.dev.health, this.config.dev.url), { signal: AbortSignal.timeout(2000) });\n\t\t\tnext = response.status < 500 ? 'ok' : 'down';\n\t\t} catch {\n\t\t\tnext = 'down';\n\t\t}\n\n\t\tif (this.#stopped || pid !== this.supervisor.pid) return;\n\t\tif (next !== this.#health) {\n\t\t\tthis.#health = next;\n\t\t\tif (next === 'ok') this.#settleProgress();\n\t\t\tthis.#emitStatus();\n\t\t}\n\t}\n\n\t#settleProgress(): void {\n\t\tif (this.config.dev.health && this.#health !== 'ok') return;\n\t\tif (this.#build !== 'ok') return;\n\t\tthis.#progress = {\n\t\t\t...this.#progress,\n\t\t\tfraction: 1,\n\t\t\tmessage: 'watching for changes',\n\t\t\treadyMs: this.#progress.readyMs ?? Date.now() - this.#progress.startedAt\n\t\t};\n\t}\n\n\t/** Turns what the bot reports over the bridge into log entries and status. */\n\t#onBridge(message: BridgeMessage): void {\n\t\tconst relative = (path: string) => displayPath(this.config.root, path);\n\t\tswitch (message.type) {\n\t\t\tcase 'ready':\n\t\t\t\tthis.#ready = true;\n\t\t\t\tthis.#port = message.port;\n\t\t\t\tthis.log('stars', 'success', message.port === null ? 'The bot is ready' : `Listening on port ${message.port}`, {\n\t\t\t\t\tchannel: 'lifecycle'\n\t\t\t\t});\n\t\t\t\tif (this.#refreshPending) this.refreshCommands();\n\t\t\t\tthis.#emitStatus();\n\t\t\t\treturn;\n\t\t\tcase 'pieces':\n\t\t\t\tfor (const piece of message.pieces) this.#pieces.add(piece.path);\n\t\t\t\tif (message.pieces.length === 0) return;\n\t\t\t\tthis.log('stars', 'debug', `Loaded ${message.store}: ${message.pieces.length} ${message.pieces.length === 1 ? 'piece' : 'pieces'}`, {\n\t\t\t\t\tchannel: message.store === 'commands' ? 'commands' : 'lifecycle',\n\t\t\t\t\tdetail: message.pieces.map((piece) => `${piece.name} ${relative(piece.path)}`)\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase 'hmr':\n\t\t\t\tthis.#onHmr(message);\n\t\t\t\treturn;\n\t\t\tcase 'commands':\n\t\t\t\tthis.#onCommands({ global: message.global, guilds: message.guilds });\n\t\t\t\treturn;\n\t\t\tcase 'dispatch':\n\t\t\t\tif (message.phase === 'run') {\n\t\t\t\t\tthis.log('stars', 'debug', `Processing ${message.route} with ${message.piece}`, { channel: 'interactions' });\n\t\t\t\t} else if (message.phase === 'success') {\n\t\t\t\t\tthis.log('stars', 'trace', `${message.route} handled${formatMs(message.ms)}`, { channel: 'interactions' });\n\t\t\t\t} else {\n\t\t\t\t\tthis.log('stars', 'error', `${message.route} failed${formatMs(message.ms)}: ${message.error.message}`, {\n\t\t\t\t\t\tchannel: 'interactions',\n\t\t\t\t\t\tdetail: message.error.stack\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase 'request':\n\t\t\t\tthis.log('stars', message.status >= 500 ? 'error' : message.status >= 400 ? 'warn' : 'trace', formatRequest(message), {\n\t\t\t\t\tchannel: 'http'\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\tcase 'refreshed':\n\t\t\t\tif (message.ok) {\n\t\t\t\t\tthis.#deployed = this.#commands;\n\t\t\t\t\tconst guilds =\n\t\t\t\t\t\t(message.guilds > 0 ? `, ${message.guilds} guild ${message.guilds === 1 ? 'group' : 'groups'}` : '') +\n\t\t\t\t\t\t(message.cleared > 0 ? `, cleared ${message.cleared} ${message.cleared === 1 ? 'guild' : 'guilds'}` : '');\n\t\t\t\t\tthis.log('stars', 'success', `Deployed ${message.global} global ${message.global === 1 ? 'command' : 'commands'}${guilds}`, {\n\t\t\t\t\t\tchannel: 'commands'\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthis.log('stars', 'error', `Could not refresh the commands: ${message.message}`, { channel: 'commands', detail: message.stack });\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase 'log':\n\t\t\t\tthis.log('app', toLogLevel(message.level), message.text, { channel: message.channel, detail: message.detail });\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\t#onHmr(message: Extract<BridgeMessage, { type: 'hmr' }>): void {\n\t\tconst relative = (path: string) => displayPath(this.config.root, path);\n\t\tif (message.event === 'start') {\n\t\t\tthis.#hmrPaths = message.paths;\n\t\t\tthis.log('stars', 'debug', `Hot reload on, watching ${message.paths.length} ${message.paths.length === 1 ? 'path' : 'paths'}`, {\n\t\t\t\tchannel: 'hmr',\n\t\t\t\tdetail: message.paths.map(relative)\n\t\t\t});\n\t\t\tthis.#emitStatus();\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.event === 'stop') {\n\t\t\t// Nothing in the bot watches any more: the next change needs a restart again.\n\t\t\tthis.#hmrPaths = [];\n\t\t\tthis.log('stars', 'debug', 'Hot reload off', { channel: 'hmr' });\n\t\t\tthis.#emitStatus();\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.event === 'error') {\n\t\t\tthis.log('stars', 'error', `Could not reload ${relative(message.path)}: ${message.message}`, { channel: 'hmr', detail: message.stack });\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.event === 'unloaded') this.#pieces.delete(message.path);\n\t\telse this.#pieces.add(message.path);\n\t\tconst verb = message.event === 'reloaded' ? 'Reloaded' : message.event === 'loaded' ? 'Loaded' : 'Unloaded';\n\t\tthis.log('stars', 'debug', `${verb} ${message.names.join(', ')} from ${relative(message.path)}`, { channel: 'hmr' });\n\t}\n\n\t/**\n\t * Compares the commands the bot registers with the ones it reported before. The first report of a session is the\n\t * baseline; a later one that differs is acted on as `dev.commands.refresh` says.\n\t */\n\t#onCommands(snapshot: CommandSnapshot): void {\n\t\tconst previous = this.#commands;\n\t\tthis.#commands = snapshot;\n\t\tif (previous === null) {\n\t\t\tthis.#deployed = snapshot;\n\t\t\tconst guilds = Object.keys(snapshot.guilds).length;\n\t\t\tthis.log('stars', 'debug', `Loaded commands: ${snapshot.global.length} global, ${guilds} guild ${guilds === 1 ? 'group' : 'groups'}`, {\n\t\t\t\tchannel: 'commands',\n\t\t\t\tdetail: snapshot.global.map((command) => describeCommand({ name: command.name, type: command.type ?? 1, guild: null }))\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst changes = diffSnapshots(previous, snapshot);\n\t\tif (changes.length === 0) return;\n\n\t\tconst detail = changes.map((change) => `${change.kind} ${describeCommand(change)}`);\n\t\tconst mode = this.config.dev.commands?.refresh ?? 'prompt';\n\t\tif (mode === 'auto') {\n\t\t\tthis.log('stars', 'info', 'Commands updated', { channel: 'commands', detail });\n\t\t\tthis.refreshCommands();\n\t\t\treturn;\n\t\t}\n\n\t\tif (mode === 'off' || !this.promptable) {\n\t\t\tthis.log('stars', 'warn', 'Commands updated, Discord still has the previous ones', {\n\t\t\t\tchannel: 'commands',\n\t\t\t\tdetail: [...detail, mode === 'off' ? 'dev.commands.refresh is off' : 'Set dev.commands.refresh to \"auto\" to redeploy without asking']\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\t// A second change before the first was answered asks once, about all of it.\n\t\tthis.#prompt = { kind: 'commands', changes: mergeChanges(this.#prompt?.changes ?? [], changes) };\n\t\tthis.log('stars', 'info', 'Commands updated', { channel: 'commands', detail });\n\t\tthis.#emitStatus();\n\t}\n\n\t/**\n\t * Runs a hook behind the ones already running (see {@link DevService.#hookChain}), e.g. `dev:close` so shutdown\n\t * waits for an unfinished `build:done`.\n\t */\n\tpublic runHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\n\t\treturn this.#queueHook(name, ...args);\n\t}\n\n\t/** Queues a hook behind the ones already running; see {@link DevService.#hookChain}. */\n\t#queueHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\n\t\tthis.#hookChain = this.#hookChain.then(() => this.#callHook(name, ...args));\n\t\treturn this.#hookChain;\n\t}\n\n\t/**\n\t * Starts a hook right away, at the moment it describes, instead of queueing it: `build:before` belongs to the\n\t * builder's `start` boundary, and a builder such as `none` finishes in the same call stack. Its synchronous part\n\t * runs here; later hooks still wait for the rest.\n\t */\n\t#startHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\n\t\tconst running = this.#callHook(name, ...args);\n\t\tthis.#hookChain = Promise.all([this.#hookChain, running]).then(() => undefined);\n\t\treturn running;\n\t}\n\n\t/**\n\t * Runs a `stars.config` hook. A failing hook is logged rather than thrown: a broken hook must never stop the\n\t * watcher or keep the bot from restarting.\n\t */\n\tasync #callHook<Name extends keyof StarsHooks>(name: Name, ...args: Parameters<StarsHooks[Name]>): Promise<void> {\n\t\tif (this.#hooks === null) return;\n\t\ttry {\n\t\t\tawait this.#hooks.callHook(name, ...args);\n\t\t} catch (error) {\n\t\t\tthis.log('stars', 'error', `Hook ${name} failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t}\n\n\t#emitStatus(): void {\n\t\tthis.emit('status', this.status);\n\t}\n}\n\nexport function createSupervisor(config: ResolvedStarsConfig): ProcessSupervisor {\n\treturn new ProcessSupervisor({\n\t\tcommand: process.execPath,\n\t\targs: [\n\t\t\t...envImportArgs(config),\n\t\t\t...moduleImportArgs(config),\n\t\t\t...bridgeImportArgs(config),\n\t\t\t...config.dev.nodeArgs,\n\t\t\tconfig.build.output,\n\t\t\t...config.dev.args\n\t\t],\n\t\tcwd: config.root,\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\t...config.dev.env,\n\t\t\tSTARS_DEV: '1',\n\t\t\tNODE_ENV: 'development',\n\t\t\tFORCE_COLOR: process.env.NO_COLOR !== undefined ? undefined : (process.env.FORCE_COLOR ?? (process.stdout.isTTY ? '1' : undefined))\n\t\t},\n\t\tkillTimeout: config.dev.killTimeout,\n\t\tipc: true\n\t});\n}\n\nfunction formatMs(ms: number | null): string {\n\treturn ms === null ? '' : ` in ${ms}ms`;\n}\n\nfunction formatRequest(message: Extract<BridgeMessage, { type: 'request' }>): string {\n\treturn `${message.method} ${message.path} ${message.status} in ${message.ms}ms`;\n}\n\nconst BRIDGE_LEVELS = new Set<string>(['trace', 'debug', 'info', 'success', 'warn', 'error']);\n\nfunction toLogLevel(level: string): LogLevel {\n\treturn BRIDGE_LEVELS.has(level) ? (level as LogLevel) : 'info';\n}\n\n/** The latest change of each command wins: `added` then `changed` is still one line of the prompt. */\nfunction mergeChanges(previous: readonly CommandChange[], next: readonly CommandChange[]): CommandChange[] {\n\tconst key = (change: CommandChange) => `${change.guild ?? ''}:${change.type}:${change.name}`;\n\tconst merged = new Map(previous.map((change) => [key(change), change]));\n\tfor (const change of next) merged.set(key(change), change);\n\treturn [...merged.values()];\n}\n\nexport function describeReason(reason: RestartReason): string {\n\tswitch (reason) {\n\t\tcase 'initial':\n\t\t\treturn 'first build';\n\t\tcase 'build':\n\t\t\treturn 'sources changed';\n\t\tcase 'manual':\n\t\t\treturn 'manual restart';\n\t\tcase 'crash':\n\t\t\treturn 'after crash';\n\t}\n}\n","import { lookup } from 'node:dns/promises';\n\n/**\n * Resolves `localhost` the way Vite's dev server does: Node's default DNS result order (`dns.lookup('localhost')`)\n * can disagree with the OS's own, \"verbatim\" resolution order — a well known source of a dev URL that prints fine\n * but is not the address the bot actually bound to (e.g. an IPv6-first system where the server listens on IPv4\n * only). When the two disagree this returns the OS's own address instead of the literal `localhost` hostname.\n */\nexport async function resolveLocalhost(): Promise<string> {\n\ttry {\n\t\tconst [ordered, verbatim] = await Promise.all([lookup('localhost'), lookup('localhost', { verbatim: true })]);\n\t\treturn ordered.family === verbatim.family && ordered.address === verbatim.address ? 'localhost' : verbatim.address;\n\t} catch {\n\t\treturn 'localhost';\n\t}\n}\n\n/**\n * Replaces a `localhost` hostname in `url` with {@link resolveLocalhost}'s result. Any other hostname (an explicit\n * `dev.url` override, a LAN address, …) is returned untouched.\n */\nexport async function withResolvedLocalhost(url: string): Promise<string> {\n\tconst parsed = new URL(url);\n\tif (parsed.hostname !== 'localhost') return url;\n\n\tconst host = await resolveLocalhost();\n\tif (host === 'localhost') return url;\n\n\tparsed.hostname = host.includes(':') ? `[${host}]` : host;\n\treturn parsed.href;\n}\n","import { createWriteStream, mkdirSync, readdirSync, rmSync, type WriteStream } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { stripVTControlCharacters } from 'node:util';\nimport type { LogBuffer, LogEntry } from '../utils/log-buffer.js';\n\n/**\n * Mirrors a dev session's logs into a file, so a run can be read back after the terminal UI is gone (the TUI takes\n * over the alternate screen and its scrollback disappears on exit). `dev.logFile` is a single file truncated on every\n * run; `dev.logs.dir` adds one file per run (see {@link runLogFile}).\n */\nexport class LogFileWriter {\n\t#stream: WriteStream | null = null;\n\n\tpublic constructor(\n\t\tpublic readonly file: string,\n\t\tprivate readonly logs: LogBuffer\n\t) {}\n\n\tpublic open(): void {\n\t\tif (this.#stream) return;\n\n\t\tmkdirSync(dirname(this.file), { recursive: true });\n\t\tthis.#stream = createWriteStream(this.file, { flags: 'w' });\n\t\t// A broken pipe or a read-only directory must never take the dev session down with it.\n\t\tthis.#stream.on('error', () => this.close());\n\n\t\tfor (const entry of this.logs.entries()) this.#write(entry);\n\t\tthis.logs.on('entry', this.#write);\n\t}\n\n\tpublic close(): void {\n\t\tconst stream = this.#stream;\n\t\tthis.#stream = null;\n\t\tif (!stream) return;\n\n\t\tthis.logs.off('entry', this.#write);\n\t\tstream.end();\n\t}\n\n\t#write = (entry: LogEntry): void => {\n\t\tthis.#stream?.write(`${formatLogLine(entry)}\\n`);\n\t};\n}\n\n/** One line per entry, then its detail lines indented under it. Never filtered: the file is the whole session. */\nexport function formatLogLine(entry: LogEntry): string {\n\tconst head = `${new Date(entry.time).toISOString()} ${entry.level.padEnd(7)} ${entry.channel.padEnd(12)} ${stripVTControlCharacters(entry.text)}`;\n\treturn [head, ...(entry.detail ?? []).map((line) => ` ${stripVTControlCharacters(line)}`)].join('\\n');\n}\n\nconst RUN_FILE = /^dev-.+\\.log$/;\n\n/**\n * The file of this run inside `dev.logs.dir` (`dev-<timestamp>.log`), after deleting the oldest ones so the directory\n * holds at most `keep` files with the new one. The names sort by time, so no file needs to be opened to order them.\n */\nexport function runLogFile(directory: string, keep: number, now: Date = new Date()): string {\n\tlet existing: string[] = [];\n\ttry {\n\t\texisting = readdirSync(directory)\n\t\t\t.filter((name) => RUN_FILE.test(name))\n\t\t\t.sort();\n\t} catch {\n\t\t// The directory does not exist yet: nothing to prune.\n\t}\n\n\tfor (const name of existing.slice(0, Math.max(0, existing.length - Math.max(0, keep - 1)))) {\n\t\trmSync(join(directory, name), { force: true });\n\t}\n\n\treturn join(directory, `dev-${now.toISOString().replaceAll(':', '-')}.log`);\n}\n","import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createBuilder } from '../builders/index.js';\nimport { DevService } from '../dev/dev-service.js';\nimport { withResolvedLocalhost } from '../dev/host.js';\nimport { LogFileWriter, runLogFile } from '../dev/log-file.js';\nimport { initialLogView, isLogLevel } from '../dev/tui/log-view.js';\nimport { collectFlag, projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { ExitCode, renderCrashReport } from '../utils/errors.js';\nimport { applyEnvOptions, loadProject, withProjectEnv } from '../utils/hooks.js';\nimport { prefersReducedMotion, resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\nimport { THEME_SETTINGS, isThemeSetting, readSavedTheme, resolveThemeSetting, saveTheme } from '../utils/theme.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport interface DevTaskOptions extends ProjectArgs {\n\ttui?: boolean;\n\t/** `--theme`. */\n\ttheme?: string;\n\t/** `--layout`. */\n\tlayout?: string;\n\t/** `--channel`, each value possibly a comma-separated list. */\n\tchannel?: string[];\n\t/** `--level`. */\n\tlevel?: string;\n\t/** `--tunnel` opens the tunnel at start whatever `dev.tunnel` says, `--no-tunnel` keeps it closed. */\n\ttunnel?: boolean;\n}\n\nconst LAYOUTS = ['auto', 'dashboard', 'panel'] as const;\nconst LEVELS = ['trace', 'debug', 'info', 'warn', 'error'] as const;\n\nexport async function runDev(options: DevTaskOptions): Promise<void> {\n\tif (options.theme !== undefined && !isThemeSetting(options.theme)) {\n\t\tthrow cliDiagnostics.INVALID_THEME({ theme: options.theme, themes: THEME_SETTINGS.join(', ') });\n\t}\n\n\tconst layout = options.layout as (typeof LAYOUTS)[number] | undefined;\n\tif (layout !== undefined && !LAYOUTS.includes(layout)) {\n\t\tthrow cliDiagnostics.INVALID_OPTION({ option: '--layout', value: options.layout!, allowed: LAYOUTS.join(', ') });\n\t}\n\n\tif (options.level !== undefined && !isLogLevel(options.level)) {\n\t\tthrow cliDiagnostics.INVALID_OPTION({ option: '--level', value: options.level, allowed: LEVELS.join(', ') });\n\t}\n\n\t// Dev mode applies to config evaluation, build plugins, and the supervised application — not only the child.\n\tprocess.env.NODE_ENV = 'development';\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config, env: { ...process.env, NODE_ENV: 'development' } });\n\tconst hooks = project.hooks;\n\t// `env:options` first: it may pick env files with another `HTTP_PORT`, which `dev.url` is derived from.\n\tconst config = await resolveDevConfig(withProjectEnv(await applyEnvOptions(project.config, hooks)));\n\tconst mode = resolveOutputMode({ tui: options.tui });\n\tconst color = shouldUseColor();\n\tconst theme = resolveThemeSetting({ flag: options.theme, saved: readSavedTheme() });\n\n\tconst builder = await createBuilder(config, hooks);\n\tawait hooks.callHook('builder:created', builder, config);\n\tconst service = new DevService(config, { builder, hooks, openTunnel: options.tunnel });\n\tawait reportWarnings(config, (text) => service.log('stars', 'warn', text), { production: false });\n\t// The files receive every entry: the filter below only decides what the terminal shows.\n\tconst logFiles = [\n\t\t...(config.dev.logFile ? [config.dev.logFile] : []),\n\t\t...(config.dev.logs?.dir ? [runLogFile(config.dev.logs.dir, config.dev.logs.keep)] : [])\n\t].map((file) => new LogFileWriter(file, service.logs));\n\tfor (const file of logFiles) file.open();\n\tconst filter = initialLogView(config, { channels: options.channel, level: options.level });\n\tconst renderer =\n\t\tmode === 'tui'\n\t\t\t? (await import('../dev/tui/tui.js')).createTuiRenderer(service, {\n\t\t\t\t\tcolor,\n\t\t\t\t\ttheme,\n\t\t\t\t\tlayout,\n\t\t\t\t\tfilter,\n\t\t\t\t\treducedMotion: prefersReducedMotion(),\n\t\t\t\t\tonThemeSave: (setting) => {\n\t\t\t\t\t\tif (!saveTheme(setting)) service.log('stars', 'warn', 'Could not save the theme preference.');\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t: (await import('../dev/tui/plain.js')).createPlainRenderer(service, { color, filter });\n\n\tlet exiting: Promise<never> | null = null;\n\tconst shutdown = (code: ExitCode): Promise<never> => {\n\t\texiting ??= (async () => {\n\t\t\trenderer.stop();\n\t\t\t// A failing hook must not keep the bot running.\n\t\t\t// Behind any hook still running (an async `build:done`), and logged rather than thrown if it fails.\n\t\t\tawait service.runHook('dev:close', config);\n\t\t\tawait service.stop();\n\t\t\tfor (const file of logFiles) file.close();\n\t\t\tprocess.exit(code);\n\t\t})();\n\t\treturn exiting;\n\t};\n\n\t// Like Turborepo: the first signal shuts down gracefully, a second one gives up waiting and kills everything.\n\tlet signalled = false;\n\tconst onSignal = (code: ExitCode) => () => {\n\t\tif (signalled) {\n\t\t\tprocess.stderr.write('\\nForcing shutdown.\\n');\n\t\t\tservice.kill();\n\t\t\tprocess.exit(code);\n\t\t}\n\n\t\tsignalled = true;\n\t\tvoid shutdown(code);\n\t\tprocess.stderr.write('\\nShutting down gracefully, press Ctrl+C again to force quit.\\n');\n\t};\n\n\tprocess.on('SIGINT', onSignal(ExitCode.Interrupted));\n\tprocess.on('SIGTERM', onSignal(ExitCode.Terminated));\n\tprocess.on('SIGHUP', onSignal(ExitCode.Terminated));\n\tif (process.platform !== 'win32') process.on('SIGUSR2', () => void service.restart('manual'));\n\n\tconst finished = renderer.start().then(() => shutdown(ExitCode.Ok));\n\ttry {\n\t\tawait prepareProject(config, hooks);\n\t\tawait service.start();\n\t\tawait hooks.callHook('dev:start', config);\n\t} catch (error) {\n\t\tservice.log('stars', 'error', error instanceof Error ? await renderCrashReport(error, config.root) : String(error));\n\t\tawait shutdown(ExitCode.Error);\n\t}\n\tawait finished;\n}\n\n/**\n * Resolves `dev.url`'s `localhost` to the address that is actually reachable (see {@link withResolvedLocalhost}),\n * the way Vite's dev server does when it starts. Only `stars dev` pays this DNS lookup; `stars info`/`stars build`\n * show or use the unresolved config as-is, since they never talk to the bot.\n */\nasync function resolveDevConfig(config: ResolvedStarsConfig): Promise<ResolvedStarsConfig> {\n\tif (!config.dev.url) return config;\n\n\tconst url = await withResolvedLocalhost(config.dev.url);\n\treturn url === config.dev.url ? config : { ...config, dev: { ...config.dev, url } };\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'dev',\n\t\tdescription: 'Build, run and restart the bot on changes'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\ttui: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Interactive terminal UI; use --no-tui (or STARS_TUI=plain) for plain line output',\n\t\t\tdefault: true\n\t\t},\n\t\ttheme: {\n\t\t\ttype: 'string',\n\t\t\tdescription: `Colour theme of the interactive UI: ${THEME_SETTINGS.join(', ')} (or STARS_THEME; press T in the UI to pick one)`\n\t\t},\n\t\tlayout: {\n\t\t\ttype: 'string',\n\t\t\tdescription: `Layout of the interactive UI: ${LAYOUTS.join(', ')} (defaults to dev.layout; press v in the UI to switch)`\n\t\t},\n\t\tchannel: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Only show these log channels at start (repeatable, or comma-separated; defaults to dev.logs.channels)'\n\t\t},\n\t\tlevel: {\n\t\t\ttype: 'string',\n\t\t\tdescription: `Only show this log level and the more severe ones at start: ${LEVELS.join(', ')} (defaults to dev.logs.levels)`\n\t\t},\n\t\t// No default: left out, `dev.tunnel` decides.\n\t\ttunnel: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Open the public tunnel at start, whatever dev.tunnel says',\n\t\t\tnegativeDescription: 'Keep the public tunnel closed at start even when dev.tunnel enables it'\n\t\t}\n\t},\n\tasync run({ args, rawArgs }) {\n\t\tconst channel = collectFlag(rawArgs, 'channel');\n\t\tawait runDev({\n\t\t\tconfig: args.config,\n\t\t\tcwd: args.cwd,\n\t\t\ttui: args.tui ? undefined : false,\n\t\t\ttheme: args.theme,\n\t\t\tlayout: args.layout,\n\t\t\tchannel: channel.length > 0 ? channel : undefined,\n\t\t\tlevel: args.level,\n\t\t\ttunnel: args.tunnel\n\t\t});\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIA,MAAM,sCAAsB,IAAI,IAAI,CAAC,gBAAgB,MAAM,CAAC;;;;;AAK5D,MAAM,gBAAgB;;;;;;;;AAetB,SAAgB,cAAc,OAA0B,UAA6B,CAAC,GAAG,wBAAmB,IAAI,IAAI,GAAiB;CACpI,MAAM,2BAAW,IAAI,IAAoB;CACzC,MAAM,SAAS,cAAsB;EACpC,IAAI;EACJ,IAAI;GACH,UAAU,YAAY,WAAW,EAAE,eAAe,KAAK,CAAC;EACzD,QAAQ;GACP;EACD;EAEA,KAAK,MAAM,SAAS,SAAS;GAC5B,MAAM,OAAO,KAAK,WAAW,MAAM,IAAI;GACvC,IAAI,QAAQ,MAAM,aAAa,SAAS,MAAM,QAAQ,CAAC,GAAG;GAC1D,IAAI,MAAM,YAAY,GACrB;QAAI,CAAC,oBAAoB,IAAI,MAAM,IAAI,GAAG,MAAM,IAAI;GAAC,OAC/C,IAAI,MAAM,OAAO,KAAK,CAAC,cAAc,KAAK,MAAM,IAAI,GAC1D,IAAI;IACH,MAAM,EAAE,MAAM,YAAY,SAAS,IAAI;IACvC,MAAM,QAAQ,MAAM,IAAI,IAAI;IAC5B,MAAM,OACL,OAAO,SAAS,QAAQ,MAAM,YAAY,UACvC,MAAM,OACN,WAAW,MAAM,CAAC,CAAC,OAAO,aAAa,IAAI,CAAC,CAAC,CAAC,OAAO,QAAQ;IACjE,MAAM,IAAI,MAAM;KAAE;KAAM;KAAS;IAAK,CAAC;IACvC,SAAS,IAAI,MAAM,IAAI;GACxB,QAAQ,CAER;EAEF;CACD;CAEA,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK,GAAG,MAAM,IAAI;CAC7C,OAAO;AACR;;AAGA,SAAgB,aAAa,UAAwB,MAA8B;CAClF,MAAM,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,UAAU,SAAS,IAAI,IAAI,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,UAAU,IAAI;CACpG,KAAK,MAAM,QAAQ,SAAS,KAAK,GAChC,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,QAAQ,KAAK,IAAI;CAGvC,OAAO;AACR;AAEA,MAAM,mCAAmB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAQ;CAAO;CAAQ;AAAM,CAAC;;;;;AAM/E,SAAgB,aAAa,MAAuB;CACnD,MAAM,YAAY,QAAQ,IAAI;CAC9B,OAAO,iBAAiB,IAAI,SAAS,KAAK,CAAC,KAAK,SAAS,OAAO,KAAK,CAAC,SAAS,MAAM,SAAS,CAAC,CAAC,WAAW,GAAG;AAC/G;;AAGA,SAAgB,SAAS,MAAc,WAA4B;CAClE,OAAO,SAAS,aAAa,KAAK,WAAW,UAAU,SAAS,GAAG,IAAI,YAAY,GAAG,YAAY,KAAK;AACxG;;;;;;;;ACFA,IAAa,aAAb,cAAgC,aAA+B;CA6C7C;CA5CjB,AAAgB;CAChB,AAAgB;CAChB,AAAgB;CAChB,AAAgB;CAChB,AAAgB;CAChB,AAAgB;;CAEhB,AAAO,aAAa;CACpB,AAAS;CACT,AAAS;;CAET,aAA4B,QAAQ,QAAQ;CAE5C,SAAqB;CACrB,UAAuB;CACvB,YAAY;CACZ,qBAA2C;CAC3C,aAAkC;CAClC,YAAgC;CAChC,gBAAuC;CACvC,eAAsC;CACtC,iBAAuC;CACvC,WAAW;CACX,SAAwB,QAAQ,QAAQ;CACxC,YAAY;EAAE,UAAU;EAAG,SAAS;EAAsB,WAAW,KAAK,IAAI;EAAG,SAAS;CAAsB;CAChH,SAAS;CACT,QAAuB;;CAEvB,YAAsB,CAAC;CACvB,UAAU;CACV,UAA4B;;CAE5B,YAAoC;;CAEpC,SAA8B;CAC9B,AAAS,0BAAqB,IAAI,IAAI;;CAEtC,0BAAU,IAAI,IAAY;;CAE1B,YAAoC;;CAEpC,kBAAkB;CAElB,AAAO,YACN,AAAgB,QAChB,SACC;EACD,MAAM;EAHU;EAIhB,KAAK,OAAO,QAAQ,QAAQ,IAAI,UAAU;EAC1C,KAAK,UAAU,QAAQ;EACvB,KAAK,aAAa,QAAQ,cAAc,iBAAiB,MAAM;EAC/D,KAAK,cAAc,QAAQ,eAAe,IAAI,YAAY,MAAM;EAChE,KAAK,SAAS,QAAQ,UAAU,IAAI,OAAO,MAAM;EACjD,KAAK,UAAU,IAAI,QAAQ,MAAM;EACjC,KAAK,SAAS,QAAQ,SAAS;EAC/B,KAAK,cAAc,QAAQ;EAE3B,KAAK,QAAQ,GAAG,eAAe;GAC9B,KAAK,YAAY;IAAE,UAAU;IAAG,SAAS;IAAmB,WAAW,KAAK,IAAI;IAAG,SAAS;GAAK;GACjG,KAAK,UAAU,UAAU;GACzB,AAAK,KAAK,WAAW,gBAAgB,KAAK,MAAM;EACjD,CAAC;EACD,KAAK,QAAQ,GAAG,aAAa,UAAU,YAAY;GAClD,KAAK,YAAY;IAAE,GAAG,KAAK;IAAW,UAAU,KAAK,IAAI,KAAK,UAAU,UAAU,KAAK,IAAI,KAAM,QAAQ,CAAC;IAAG;GAAQ;GACrH,KAAK,YAAY;EAClB,CAAC;EACD,KAAK,QAAQ,GAAG,YAAY,YAAY,KAAK,gBAAgB,OAAO,CAAC;EACrE,KAAK,QAAQ,GAAG,YAAY,YAAY,KAAK,gBAAgB,OAAO,CAAC;EACrE,KAAK,QAAQ,GAAG,QAAQ,OAAO,SAAS,KAAK,IAAI,SAAS,OAAO,IAAI,CAAC;EAEtE,KAAK,WAAW,GAAG,eAAe;GACjC,IAAI,KAAK,WAAW,UAAU,WAAW;IACxC,KAAK,gBAAgB;IACrB,AAAK,KAAK,aAAa;GACxB;GACA,KAAK,YAAY;EAClB,CAAC;EACD,KAAK,WAAW,GAAG,WAAW,SAAS,KAAK,IAAI,OAAO,gBAAgB,MAAM,MAAM,GAAG,IAAI,CAAC;EAC3F,KAAK,WAAW,GAAG,WAAW,SAAS,KAAK,IAAI,OAAO,gBAAgB,MAAM,OAAO,GAAG,IAAI,CAAC;EAC5F,KAAK,WAAW,GAAG,YAAY,YAAY;GAC1C,MAAM,SAAS,mBAAmB,OAAO;GACzC,IAAI,WAAW,MAAM;GACrB,IAAI;IACH,KAAK,UAAU,MAAM;GACtB,SAAS,OAAO;IAEf,KAAK,IAAI,SAAS,QAAQ,aAAa,OAAO,KAAK,yBAAyB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GACrI;EACD,CAAC;EACD,KAAK,WAAW,GAAG,UAAU,UAAU,KAAK,IAAI,SAAS,SAAS,4BAA4B,MAAM,SAAS,CAAC;EAC9G,KAAK,WAAW,GAAG,SAAS,SAAS,KAAK,QAAQ,IAAI,CAAC;EAEvD,KAAK,YAAY,GAAG,QAAQ,OAAO,SAAS,KAAK,IAAI,OAAO,OAAO,IAAI,CAAC;EACxE,KAAK,YAAY,GAAG,eAAe,KAAK,YAAY,CAAC;EACrD,KAAK,OAAO,GAAG,QAAQ,OAAO,SAAS,KAAK,IAAI,UAAU,OAAO,IAAI,CAAC;EACtE,KAAK,OAAO,GAAG,eAAe,KAAK,YAAY,CAAC;EAChD,KAAK,QAAQ,GAAG,QAAQ,OAAO,SAAS,KAAK,IAAI,SAAS,OAAO,IAAI,CAAC;EACtE,KAAK,QAAQ,GAAG,gBAAgB;GAC/B,IAAI,KAAK,WAAW,MAAM,KAAK,iBAAiB,OAAO;EACxD,CAAC;EAED,IAAI,OAAO,IAAI,OAAO,OAAO,IAAI,QAAQ;GACxC,MAAM,WAAW,QAAQ,kBAAkB;GAC3C,KAAK,eAAe,kBAAkB,KAAK,KAAK,aAAa,GAAG,QAAQ;GACxE,KAAK,aAAa,MAAM;EACzB;CACD;CAEA,IAAW,SAAoB;EAC9B,OAAO;GACN,UAAU,KAAK;GACf,SAAS,KAAK,WAAW;GACzB,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,KAAK,KAAK,WAAW;GACrB,WAAW,KAAK,WAAW;GAC3B,UAAU,KAAK;GACf,mBAAmB,KAAK;GACxB,WAAW,KAAK;GAChB,UAAU,KAAK;GACf,KAAK,KAAK,OAAO,IAAI;GACrB,WAAW,KAAK,YAAY;GAC5B,YAAY,KAAK,YAAY;GAC7B,QAAQ,KAAK,OAAO;GACpB,WAAW,KAAK,OAAO;GACvB,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,KAAK,KAAK,UAAU,SAAS;GAC7B,QAAQ,KAAK;GACb,QAAQ,KAAK;EACd;CACD;CAEA,AAAO,IAAI,QAAmB,OAAiB,MAAc,QAAkB,CAAC,GAAS;EACxF,KAAK,KAAK,KAAK;GAAE;GAAQ;GAAO;GAAM,GAAG;EAAM,CAAC;CACjD;;;;CAKA,MAAa,QAAuB;EACnC,KAAK,WAAW;EAChB,MAAM,QAAQ,YAAY,KAAK,OAAO,MAAM,KAAK,OAAO,KAAK;EAC7D,KAAK,IAAI,SAAS,QAAQ,KAAK,OAAO,MAAM,SAAS,SAAS,YAAY,UAAU,YAAY,MAAM,QAAQ,KAAK,OAAO,MAAM,MAAM;EACtI,IAAI,KAAK,OAAO,IAAI,UAAU,SAAS,KAAK,YAAY,MAAM;EAC9D,MAAM,KAAK,QAAQ,MAAM;EAGzB,IAAI,KAAK,gBAAgB,OAAO,AAAK,KAAK,OAAO,MAAM,KAAK,gBAAgB,IAAI;EAChF,MAAM,KAAK,QAAQ,MAAM;CAC1B;;;;CAKA,AAAO,QAAQ,SAAwB,UAAyB;EAC/D,KAAK,mBAAmB;EACxB,OAAO,KAAK,SAAS,YAAY;GAChC,IAAI,KAAK,UAAU;GACnB,MAAM,KAAK,WAAW,eAAe,QAAQ,KAAK,MAAM;GACxD,IAAI,KAAK,UAAU;GACnB,IAAI,WAAW,YAAY,WAAW,SACrC,KAAK,YAAY;IAAE,UAAU;IAAG,SAAS;IAAsB,WAAW,KAAK,IAAI;IAAG,SAAS;GAAK;GAErG,KAAK,qBAAqB;GAC1B,IAAI,KAAK,WAAW,SAAS;IAC5B,KAAK;IACL,KAAK,IAAI,SAAS,QAAQ,eAAe,eAAe,MAAM,EAAE,EAAE;IAClE,MAAM,KAAK,WAAW,KAAK;GAC5B,OACC,KAAK,IAAI,SAAS,QAAQ,aAAa,eAAe,MAAM,EAAE,EAAE;GAGjE,IAAI,KAAK,UAAU;GACnB,KAAK,YAAY;IAAE,GAAG,KAAK;IAAW,UAAU;IAAM,SAAS;GAAmB;GAClF,KAAK,UAAU;GACf,KAAK,UAAU;GACf,KAAK,WAAW,MAAM;GACtB,KAAK,YAAY;EAClB,CAAC;CACF;;;;;CAMA,AAAO,aAA4B;EAClC,KAAK,mBAAmB;EACxB,OAAO,KAAK,SAAS,YAAY;GAChC,IAAI,KAAK,YAAY,KAAK,SAAS;GACnC,KAAK,UAAU;GACf,KAAK,IAAI,SAAS,QAAQ,4CAA4C;GACtE,MAAM,KAAK,WAAW,KAAK;GAC3B,KAAK,YAAY;EAClB,CAAC;CACF;;CAGA,AAAO,aAAa,QAAuB;EAE1C,IADe,KAAK,YACL,MAAM;EACrB,KAAK,UAAU;EACf,IAAI,QAAQ,KAAK,gBAAgB;OAC5B,KAAK,IAAI,SAAS,QAAQ,0CAA0C,EAAE,SAAS,WAAW,CAAC;EAChG,KAAK,YAAY;CAClB;;CAGA,AAAO,kBAAwB;EAE9B,IAAI,CAAC,KAAK,QAAQ;GACjB,KAAK,kBAAkB;GACvB,MAAM,OAAO,KAAK,WAAW,UAAU,0BAA0B;GACjE,KAAK,IAAI,SAAS,QAAQ,uBAAuB,KAAK,IAAI,EAAE,SAAS,WAAW,CAAC;GACjF;EACD;EAEA,KAAK,kBAAkB;EACvB,MAAM,UAAU,KAAK,WAAW,UAAU,CAAC;EAC3C,MAAM,UAA0B;GAC/B,QAAQ;GACR,MAAM;GACN,aAAa,OAAO,KAAK,KAAK,WAAW,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,UAAU,CAAC,OAAO,OAAO,SAAS,KAAK,CAAC;EACxG;EACA,IAAI,KAAK,WAAW,KAAK,OAAO,GAC/B,KAAK,IAAI,SAAS,QAAQ,wBAAwB,EAAE,SAAS,WAAW,CAAC;OAEzE,KAAK,IAAI,SAAS,QAAQ,mDAAmD,EAAE,SAAS,WAAW,CAAC;CAEtG;;CAGA,AAAO,eAA8B;EACpC,OAAO,KAAK,OAAO,OAAO;CAC3B;;;;CAKA,MAAa,OAAsB;EAClC,KAAK,WAAW;EAChB,KAAK,mBAAmB;EACxB,IAAI,KAAK,cAAc,cAAc,KAAK,YAAY;EACtD,KAAK,eAAe;EACpB,MAAM,KAAK,SAAS,YAAY;GAC/B,MAAM,QAAQ,WAAW;IACxB,KAAK,QAAQ,MAAM;IACnB,KAAK,WAAW,KAAK;IACrB,KAAK,YAAY,MAAM;IACvB,KAAK,OAAO,MAAM;IAClB,KAAK,QAAQ,MAAM;GACpB,CAAC;EACF,CAAC;CACF;;;;CAKA,AAAO,OAAa;EACnB,KAAK,WAAW;EAChB,KAAK,mBAAmB;EACxB,KAAK,WAAW,KAAK;EACrB,AAAK,KAAK,YAAY,MAAM;EAC5B,AAAK,KAAK,OAAO,MAAM;CACxB;CAEA,AAAO,YAAkB;EACxB,KAAK,KAAK,MAAM;CACjB;CAEA,gBAAgB,SAA6B;EAE5C,MAAM,MAAM,KAAK,eAAe;EAChC,IAAI;GACH,KAAK,QAAQ,KAAK;EACnB,SAAS,OAAO;GACf,KAAK,gBAAgB;IACpB,GAAG;IACH,IAAI;IACJ,SAAS,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAC1F,CAAC;GACD;EACD;EACA,KAAK,aAAa;EAClB,KAAK,YAAY;GAAE,GAAG,KAAK;GAAW,UAAU;GAAM,SAAS;EAAmB;EAClF,KAAK,UAAU,IAAI;EAEnB,AAAK,KAAK,WAAW,cAAc,SAAS,KAAK,MAAM;EACvD,IAAI,KAAK,UAAU;EAEnB,KAAK,YAAY,MAAM;EACvB,KAAK,IAAI,SAAS,WAAW,KAAK,QAAQ,SAAS,SAAS,oBAAoB,sBAAsB,QAAQ,WAAW,GAAG;EAC5H,IAAI,KAAK,SAAS;EAClB,IAAI,QAAQ,MAAM;GACjB,KAAK,MAAM,QAAQ,KAAK,KAAK,IAAI,SAAS,SAAS,UAAU,YAAY,KAAK,OAAO,MAAM,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC;GACtH,KAAK,gBAAgB;GACrB,KAAK,YAAY;GACjB;EACD;EACA,KAAK,iBAAiB,KAAK,WAAW,UAAU,SAAS,YAAY,OAAO;CAC7E;;;;;;;;;;;CAYA,iBAAkC;EACjC,IAAI,KAAK,OAAO,IAAI,QAAQ,OAAO,OAAO;EAE1C,MAAM,QAAQ,KAAK,OAAO,MAAM,SAAS,SAAS,KAAK,OAAO,IAAI,QAAQ,CAAC,KAAK,OAAO,MAAM,MAAM;EACnG,MAAM,WAAW,KAAK;EACtB,KAAK,SAAS,cAAc,OAAO,CAAC,KAAK,QAAQ,WAAW,GAAG,KAAK,OAAO;EAC3E,IAAI,aAAa,QAAQ,KAAK,UAAU,WAAW,KAAK,KAAK,WAAW,UAAU,WAAW,OAAO;EAEpG,MAAM,UAAU,aAAa,UAAU,KAAK,MAAM;EAClD,MAAM,eAAe,SACpB,KAAK,UAAU,MAAM,SAAS,SAAS,MAAM,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,KAAM,CAAC,SAAS,IAAI,IAAI,KAAK,aAAa,IAAI;EAC5H,OAAO,QAAQ,SAAS,KAAK,QAAQ,MAAM,WAAW,IAAI,UAAU;CACrE;CAEA,gBAAgB,SAA6B;EAC5C,KAAK,aAAa;EAClB,AAAK,KAAK,WAAW,cAAc,SAAS,KAAK,MAAM;EACvD,KAAK,UAAU,QAAQ;EACvB,KAAK,mBAAmB;EACxB,KAAK,IAAI,SAAS,SAAS,eAAe,QAAQ,UAAU,KAAK,QAAQ,YAAY,GAAG,sBAAsB;CAC/G;CAEA,QAAQ,MAAyB;EAChC,KAAK,YAAY;EACjB,KAAK,UAAU;EACf,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,KAAK,YAAY,CAAC;EAClB,KAAK,QAAQ,MAAM;EAEnB,IAAI,CAAC,KAAK,WAAW;GACpB,MAAM,MAAM,KAAK,SAAS,UAAU,KAAK,WAAW,QAAQ,KAAK;GACjE,KAAK,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,SAAS,uBAAuB,IAAI,2CAA2C;EAC7H;EACA,KAAK,YAAY;CAClB;CAEA,iBAAiB,QAA6B;EAC7C,IAAI,KAAK,SAAS;EAClB,KAAK,iBAAiB;EACtB,KAAK,mBAAmB;EACxB,KAAK,gBAAgB,iBAAiB;GACrC,KAAK,gBAAgB;GACrB,MAAM,UAAU,KAAK,kBAAkB;GACvC,KAAK,iBAAiB;GACtB,AAAK,KAAK,QAAQ,OAAO;EAC1B,GAAG,KAAK,OAAO,IAAI,QAAQ;CAC5B;CAEA,qBAA2B;EAC1B,IAAI,KAAK,eAAe,aAAa,KAAK,aAAa;EACvD,KAAK,gBAAgB;CACtB;CAEA,SAAS,MAA0C;EAClD,KAAK,SAAS,KAAK,OAAO,KAAK,MAAM,IAAI;EACzC,OAAO,KAAK;CACb;CAEA,UAAU,OAAyB;EAClC,IAAI,KAAK,WAAW,OAAO;EAC3B,KAAK,SAAS;EACd,KAAK,YAAY;CAClB;CAEA,MAAM,eAA8B;EACnC,IAAI,CAAC,KAAK,WAAW,WAAW,CAAC,KAAK,OAAO,IAAI,OAAO,CAAC,KAAK,OAAO,IAAI,QAAQ;EACjF,MAAM,MAAM,KAAK,WAAW;EAE5B,IAAI;EACJ,IAAI;GAEH,QAAO,MADgB,MAAM,IAAI,IAAI,KAAK,OAAO,IAAI,QAAQ,KAAK,OAAO,IAAI,GAAG,GAAG,EAAE,QAAQ,YAAY,QAAQ,GAAI,EAAE,CAAC,EACzG,CAAC,SAAS,MAAM,OAAO;EACvC,QAAQ;GACP,OAAO;EACR;EAEA,IAAI,KAAK,YAAY,QAAQ,KAAK,WAAW,KAAK;EAClD,IAAI,SAAS,KAAK,SAAS;GAC1B,KAAK,UAAU;GACf,IAAI,SAAS,MAAM,KAAK,gBAAgB;GACxC,KAAK,YAAY;EAClB;CACD;CAEA,kBAAwB;EACvB,IAAI,KAAK,OAAO,IAAI,UAAU,KAAK,YAAY,MAAM;EACrD,IAAI,KAAK,WAAW,MAAM;EAC1B,KAAK,YAAY;GAChB,GAAG,KAAK;GACR,UAAU;GACV,SAAS;GACT,SAAS,KAAK,UAAU,WAAW,KAAK,IAAI,IAAI,KAAK,UAAU;EAChE;CACD;;CAGA,UAAU,SAA8B;EACvC,MAAM,YAAY,SAAiB,YAAY,KAAK,OAAO,MAAM,IAAI;EACrE,QAAQ,QAAQ,MAAhB;GACC,KAAK;IACJ,KAAK,SAAS;IACd,KAAK,QAAQ,QAAQ;IACrB,KAAK,IAAI,SAAS,WAAW,QAAQ,SAAS,OAAO,qBAAqB,qBAAqB,QAAQ,QAAQ,EAC9G,SAAS,YACV,CAAC;IACD,IAAI,KAAK,iBAAiB,KAAK,gBAAgB;IAC/C,KAAK,YAAY;IACjB;GACD,KAAK;IACJ,KAAK,MAAM,SAAS,QAAQ,QAAQ,KAAK,QAAQ,IAAI,MAAM,IAAI;IAC/D,IAAI,QAAQ,OAAO,WAAW,GAAG;IACjC,KAAK,IAAI,SAAS,SAAS,UAAU,QAAQ,MAAM,IAAI,QAAQ,OAAO,OAAO,GAAG,QAAQ,OAAO,WAAW,IAAI,UAAU,YAAY;KACnI,SAAS,QAAQ,UAAU,aAAa,aAAa;KACrD,QAAQ,QAAQ,OAAO,KAAK,UAAU,GAAG,MAAM,KAAK,GAAG,SAAS,MAAM,IAAI,GAAG;IAC9E,CAAC;IACD;GACD,KAAK;IACJ,KAAK,OAAO,OAAO;IACnB;GACD,KAAK;IACJ,KAAK,YAAY;KAAE,QAAQ,QAAQ;KAAQ,QAAQ,QAAQ;IAAO,CAAC;IACnE;GACD,KAAK;IACJ,IAAI,QAAQ,UAAU,OACrB,KAAK,IAAI,SAAS,SAAS,cAAc,QAAQ,MAAM,QAAQ,QAAQ,SAAS,EAAE,SAAS,eAAe,CAAC;SACrG,IAAI,QAAQ,UAAU,WAC5B,KAAK,IAAI,SAAS,SAAS,GAAG,QAAQ,MAAM,UAAU,SAAS,QAAQ,EAAE,KAAK,EAAE,SAAS,eAAe,CAAC;SAEzG,KAAK,IAAI,SAAS,SAAS,GAAG,QAAQ,MAAM,SAAS,SAAS,QAAQ,EAAE,EAAE,IAAI,QAAQ,MAAM,WAAW;KACtG,SAAS;KACT,QAAQ,QAAQ,MAAM;IACvB,CAAC;IAEF;GACD,KAAK;IACJ,KAAK,IAAI,SAAS,QAAQ,UAAU,MAAM,UAAU,QAAQ,UAAU,MAAM,SAAS,SAAS,cAAc,OAAO,GAAG,EACrH,SAAS,OACV,CAAC;IACD;GACD,KAAK;IACJ,IAAI,QAAQ,IAAI;KACf,KAAK,YAAY,KAAK;KACtB,MAAM,UACJ,QAAQ,SAAS,IAAI,KAAK,QAAQ,OAAO,SAAS,QAAQ,WAAW,IAAI,UAAU,aAAa,OAChG,QAAQ,UAAU,IAAI,aAAa,QAAQ,QAAQ,GAAG,QAAQ,YAAY,IAAI,UAAU,aAAa;KACvG,KAAK,IAAI,SAAS,WAAW,YAAY,QAAQ,OAAO,UAAU,QAAQ,WAAW,IAAI,YAAY,aAAa,UAAU,EAC3H,SAAS,WACV,CAAC;IACF,OACC,KAAK,IAAI,SAAS,SAAS,mCAAmC,QAAQ,WAAW;KAAE,SAAS;KAAY,QAAQ,QAAQ;IAAM,CAAC;IAEhI;GACD,KAAK;IACJ,KAAK,IAAI,OAAO,WAAW,QAAQ,KAAK,GAAG,QAAQ,MAAM;KAAE,SAAS,QAAQ;KAAS,QAAQ,QAAQ;IAAO,CAAC;IAC7G;EACF;CACD;CAEA,OAAO,SAAwD;EAC9D,MAAM,YAAY,SAAiB,YAAY,KAAK,OAAO,MAAM,IAAI;EACrE,IAAI,QAAQ,UAAU,SAAS;GAC9B,KAAK,YAAY,QAAQ;GACzB,KAAK,IAAI,SAAS,SAAS,2BAA2B,QAAQ,MAAM,OAAO,GAAG,QAAQ,MAAM,WAAW,IAAI,SAAS,WAAW;IAC9H,SAAS;IACT,QAAQ,QAAQ,MAAM,IAAI,QAAQ;GACnC,CAAC;GACD,KAAK,YAAY;GACjB;EACD;EAEA,IAAI,QAAQ,UAAU,QAAQ;GAE7B,KAAK,YAAY,CAAC;GAClB,KAAK,IAAI,SAAS,SAAS,kBAAkB,EAAE,SAAS,MAAM,CAAC;GAC/D,KAAK,YAAY;GACjB;EACD;EAEA,IAAI,QAAQ,UAAU,SAAS;GAC9B,KAAK,IAAI,SAAS,SAAS,oBAAoB,SAAS,QAAQ,IAAI,EAAE,IAAI,QAAQ,WAAW;IAAE,SAAS;IAAO,QAAQ,QAAQ;GAAM,CAAC;GACtI;EACD;EAEA,IAAI,QAAQ,UAAU,YAAY,KAAK,QAAQ,OAAO,QAAQ,IAAI;OAC7D,KAAK,QAAQ,IAAI,QAAQ,IAAI;EAClC,MAAM,OAAO,QAAQ,UAAU,aAAa,aAAa,QAAQ,UAAU,WAAW,WAAW;EACjG,KAAK,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,QAAQ,MAAM,KAAK,IAAI,EAAE,QAAQ,SAAS,QAAQ,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC;CACpH;;;;;CAMA,YAAY,UAAiC;EAC5C,MAAM,WAAW,KAAK;EACtB,KAAK,YAAY;EACjB,IAAI,aAAa,MAAM;GACtB,KAAK,YAAY;GACjB,MAAM,SAAS,OAAO,KAAK,SAAS,MAAM,CAAC,CAAC;GAC5C,KAAK,IAAI,SAAS,SAAS,oBAAoB,SAAS,OAAO,OAAO,WAAW,OAAO,SAAS,WAAW,IAAI,UAAU,YAAY;IACrI,SAAS;IACT,QAAQ,SAAS,OAAO,KAAK,YAAY,gBAAgB;KAAE,MAAM,QAAQ;KAAM,MAAM,QAAQ,QAAQ;KAAG,OAAO;IAAK,CAAC,CAAC;GACvH,CAAC;GACD;EACD;EAEA,MAAM,UAAU,cAAc,UAAU,QAAQ;EAChD,IAAI,QAAQ,WAAW,GAAG;EAE1B,MAAM,SAAS,QAAQ,KAAK,WAAW,GAAG,OAAO,KAAK,GAAG,gBAAgB,MAAM,GAAG;EAClF,MAAM,OAAO,KAAK,OAAO,IAAI,UAAU,WAAW;EAClD,IAAI,SAAS,QAAQ;GACpB,KAAK,IAAI,SAAS,QAAQ,oBAAoB;IAAE,SAAS;IAAY;GAAO,CAAC;GAC7E,KAAK,gBAAgB;GACrB;EACD;EAEA,IAAI,SAAS,SAAS,CAAC,KAAK,YAAY;GACvC,KAAK,IAAI,SAAS,QAAQ,yDAAyD;IAClF,SAAS;IACT,QAAQ,CAAC,GAAG,QAAQ,SAAS,QAAQ,gCAAgC,iEAA+D;GACrI,CAAC;GACD;EACD;EAGA,KAAK,UAAU;GAAE,MAAM;GAAY,SAAS,aAAa,KAAK,SAAS,WAAW,CAAC,GAAG,OAAO;EAAE;EAC/F,KAAK,IAAI,SAAS,QAAQ,oBAAoB;GAAE,SAAS;GAAY;EAAO,CAAC;EAC7E,KAAK,YAAY;CAClB;;;;;CAMA,AAAO,QAAuC,MAAY,GAAG,MAAmD;EAC/G,OAAO,KAAK,WAAW,MAAM,GAAG,IAAI;CACrC;;CAGA,WAA0C,MAAY,GAAG,MAAmD;EAC3G,KAAK,aAAa,KAAK,WAAW,WAAW,KAAK,UAAU,MAAM,GAAG,IAAI,CAAC;EAC1E,OAAO,KAAK;CACb;;;;;;CAOA,WAA0C,MAAY,GAAG,MAAmD;EAC3G,MAAM,UAAU,KAAK,UAAU,MAAM,GAAG,IAAI;EAC5C,KAAK,aAAa,QAAQ,IAAI,CAAC,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,WAAW,MAAS;EAC9E,OAAO;CACR;;;;;CAMA,MAAM,UAAyC,MAAY,GAAG,MAAmD;EAChH,IAAI,KAAK,WAAW,MAAM;EAC1B,IAAI;GACH,MAAM,KAAK,OAAO,SAAS,MAAM,GAAG,IAAI;EACzC,SAAS,OAAO;GACf,KAAK,IAAI,SAAS,SAAS,QAAQ,KAAK,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EAC5G;CACD;CAEA,cAAoB;EACnB,KAAK,KAAK,UAAU,KAAK,MAAM;CAChC;AACD;AAEA,SAAgB,iBAAiB,QAAgD;CAChF,OAAO,IAAI,kBAAkB;EAC5B,SAAS,QAAQ;EACjB,MAAM;GACL,GAAG,cAAc,MAAM;GACvB,GAAG,iBAAiB,MAAM;GAC1B,GAAG,iBAAiB,MAAM;GAC1B,GAAG,OAAO,IAAI;GACd,OAAO,MAAM;GACb,GAAG,OAAO,IAAI;EACf;EACA,KAAK,OAAO;EACZ,KAAK;GACJ,GAAG,QAAQ;GACX,GAAG,OAAO,IAAI;GACd,WAAW;GACX,UAAU;GACV,aAAa,QAAQ,IAAI,aAAa,SAAY,SAAa,QAAQ,IAAI,gBAAgB,QAAQ,OAAO,QAAQ,MAAM;EACzH;EACA,aAAa,OAAO,IAAI;EACxB,KAAK;CACN,CAAC;AACF;AAEA,SAAS,SAAS,IAA2B;CAC5C,OAAO,OAAO,OAAO,KAAK,OAAO,GAAG;AACrC;AAEA,SAAS,cAAc,SAA8D;CACpF,OAAO,GAAG,QAAQ,OAAO,GAAG,QAAQ,KAAK,GAAG,QAAQ,OAAO,MAAM,QAAQ,GAAG;AAC7E;AAEA,MAAM,gCAAgB,IAAI,IAAY;CAAC;CAAS;CAAS;CAAQ;CAAW;CAAQ;AAAO,CAAC;AAE5F,SAAS,WAAW,OAAyB;CAC5C,OAAO,cAAc,IAAI,KAAK,IAAK,QAAqB;AACzD;;AAGA,SAAS,aAAa,UAAoC,MAAiD;CAC1G,MAAM,OAAO,WAA0B,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,KAAK,GAAG,OAAO;CACtF,MAAM,SAAS,IAAI,IAAI,SAAS,KAAK,WAAW,CAAC,IAAI,MAAM,GAAG,MAAM,CAAC,CAAC;CACtE,KAAK,MAAM,UAAU,MAAM,OAAO,IAAI,IAAI,MAAM,GAAG,MAAM;CACzD,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC3B;AAEA,SAAgB,eAAe,QAA+B;CAC7D,QAAQ,QAAR;EACC,KAAK,WACJ,OAAO;EACR,KAAK,SACJ,OAAO;EACR,KAAK,UACJ,OAAO;EACR,KAAK,SACJ,OAAO;CACT;AACD;;;;;;;;;;AC/sBA,eAAsB,mBAAoC;CACzD,IAAI;EACH,MAAM,CAAC,SAAS,YAAY,MAAM,QAAQ,IAAI,CAAC,OAAO,WAAW,GAAG,OAAO,aAAa,EAAE,UAAU,KAAK,CAAC,CAAC,CAAC;EAC5G,OAAO,QAAQ,WAAW,SAAS,UAAU,QAAQ,YAAY,SAAS,UAAU,cAAc,SAAS;CAC5G,QAAQ;EACP,OAAO;CACR;AACD;;;;;AAMA,eAAsB,sBAAsB,KAA8B;CACzE,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,IAAI,OAAO,aAAa,aAAa,OAAO;CAE5C,MAAM,OAAO,MAAM,iBAAiB;CACpC,IAAI,SAAS,aAAa,OAAO;CAEjC,OAAO,WAAW,KAAK,SAAS,GAAG,IAAI,IAAI,KAAK,KAAK;CACrD,OAAO,OAAO;AACf;;;;;;;;;ACpBA,IAAa,gBAAb,MAA2B;CAIT;CACC;CAJlB,UAA8B;CAE9B,AAAO,YACN,AAAgB,MAChB,AAAiB,MAChB;EAFe;EACC;CACf;CAEH,AAAO,OAAa;EACnB,IAAI,KAAK,SAAS;EAElB,UAAU,QAAQ,KAAK,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EACjD,KAAK,UAAU,kBAAkB,KAAK,MAAM,EAAE,OAAO,IAAI,CAAC;EAE1D,KAAK,QAAQ,GAAG,eAAe,KAAK,MAAM,CAAC;EAE3C,KAAK,MAAM,SAAS,KAAK,KAAK,QAAQ,GAAG,KAAK,OAAO,KAAK;EAC1D,KAAK,KAAK,GAAG,SAAS,KAAK,MAAM;CAClC;CAEA,AAAO,QAAc;EACpB,MAAM,SAAS,KAAK;EACpB,KAAK,UAAU;EACf,IAAI,CAAC,QAAQ;EAEb,KAAK,KAAK,IAAI,SAAS,KAAK,MAAM;EAClC,OAAO,IAAI;CACZ;CAEA,UAAU,UAA0B;EACnC,KAAK,SAAS,MAAM,GAAG,cAAc,KAAK,EAAE,GAAG;CAChD;AACD;;AAGA,SAAgB,cAAc,OAAyB;CAEtD,OAAO,CAAC,GADQ,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,YAAY,EAAE,GAAG,MAAM,MAAM,OAAO,CAAC,EAAE,GAAG,MAAM,QAAQ,OAAO,EAAE,EAAE,GAAG,yBAAyB,MAAM,IAAI,KAChI,IAAI,MAAM,UAAU,CAAC,EAAC,CAAE,KAAK,SAAS,KAAK,yBAAyB,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;AACtG;AAEA,MAAM,WAAW;;;;;AAMjB,SAAgB,WAAW,WAAmB,MAAc,sBAAY,IAAI,KAAK,GAAW;CAC3F,IAAI,WAAqB,CAAC;CAC1B,IAAI;EACH,WAAW,YAAY,SAAS,CAAC,CAC/B,QAAQ,SAAS,SAAS,KAAK,IAAI,CAAC,CAAC,CACrC,KAAK;CACR,QAAQ,CAER;CAEA,KAAK,MAAM,QAAQ,SAAS,MAAM,GAAG,KAAK,IAAI,GAAG,SAAS,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GACxF,OAAO,KAAK,WAAW,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;CAG9C,OAAO,KAAK,WAAW,OAAO,IAAI,YAAY,CAAC,CAAC,WAAW,KAAK,GAAG,EAAE,KAAK;AAC3E;;;;AC1CA,MAAM,UAAU;CAAC;CAAQ;CAAa;AAAO;AAC7C,MAAM,SAAS;CAAC;CAAS;CAAS;CAAQ;CAAQ;AAAO;AAEzD,eAAsB,OAAO,SAAwC;CACpE,IAAI,QAAQ,UAAU,UAAa,CAAC,eAAe,QAAQ,KAAK,GAC/D,MAAM,eAAe,cAAc;EAAE,OAAO,QAAQ;EAAO,QAAQ,eAAe,KAAK,IAAI;CAAE,CAAC;CAG/F,MAAM,SAAS,QAAQ;CACvB,IAAI,WAAW,UAAa,CAAC,QAAQ,SAAS,MAAM,GACnD,MAAM,eAAe,eAAe;EAAE,QAAQ;EAAY,OAAO,QAAQ;EAAS,SAAS,QAAQ,KAAK,IAAI;CAAE,CAAC;CAGhH,IAAI,QAAQ,UAAU,UAAa,CAAC,WAAW,QAAQ,KAAK,GAC3D,MAAM,eAAe,eAAe;EAAE,QAAQ;EAAW,OAAO,QAAQ;EAAO,SAAS,OAAO,KAAK,IAAI;CAAE,CAAC;CAI5G,QAAQ,IAAI,WAAW;CACvB,MAAM,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;EAAQ,KAAK;GAAE,GAAG,QAAQ;GAAK,UAAU;EAAc;CAAE,CAAC;CAC5I,MAAM,QAAQ,QAAQ;CAEtB,MAAM,SAAS,MAAM,iBAAiB,eAAe,MAAM,gBAAgB,QAAQ,QAAQ,KAAK,CAAC,CAAC;CAClG,MAAM,OAAO,kBAAkB,EAAE,KAAK,QAAQ,IAAI,CAAC;CACnD,MAAM,QAAQ,eAAe;CAC7B,MAAM,QAAQ,oBAAoB;EAAE,MAAM,QAAQ;EAAO,OAAO,eAAe;CAAE,CAAC;CAElF,MAAM,UAAU,MAAM,cAAc,QAAQ,KAAK;CACjD,MAAM,MAAM,SAAS,mBAAmB,SAAS,MAAM;CACvD,MAAM,UAAU,IAAI,WAAW,QAAQ;EAAE;EAAS;EAAO,YAAY,QAAQ;CAAO,CAAC;CACrF,MAAM,eAAe,SAAS,SAAS,QAAQ,IAAI,SAAS,QAAQ,IAAI,GAAG,EAAE,YAAY,MAAM,CAAC;CAEhG,MAAM,WAAW,CAChB,GAAI,OAAO,IAAI,UAAU,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,GACjD,GAAI,OAAO,IAAI,MAAM,MAAM,CAAC,WAAW,OAAO,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CACvF,CAAC,CAAC,KAAK,SAAS,IAAI,cAAc,MAAM,QAAQ,IAAI,CAAC;CACrD,KAAK,MAAM,QAAQ,UAAU,KAAK,KAAK;CACvC,MAAM,SAAS,eAAe,QAAQ;EAAE,UAAU,QAAQ;EAAS,OAAO,QAAQ;CAAM,CAAC;CACzF,MAAM,WACL,SAAS,SACL,MAAM,OAAO,qBAAoB,CAAE,kBAAkB,SAAS;EAC/D;EACA;EACA;EACA;EACA,eAAe,qBAAqB;EACpC,cAAc,YAAY;GACzB,IAAI,CAAC,UAAU,OAAO,GAAG,QAAQ,IAAI,SAAS,QAAQ,sCAAsC;EAC7F;CACD,CAAC,KACC,MAAM,OAAO,uBAAsB,CAAE,oBAAoB,SAAS;EAAE;EAAO;CAAO,CAAC;CAExF,IAAI,UAAiC;CACrC,MAAM,YAAY,SAAmC;EACpD,aAAa,YAAY;GACxB,SAAS,KAAK;GAGd,MAAM,QAAQ,QAAQ,aAAa,MAAM;GACzC,MAAM,QAAQ,KAAK;GACnB,KAAK,MAAM,QAAQ,UAAU,KAAK,MAAM;GACxC,QAAQ,KAAK,IAAI;EAClB,EAAC,CAAE;EACH,OAAO;CACR;CAGA,IAAI,YAAY;CAChB,MAAM,YAAY,eAAyB;EAC1C,IAAI,WAAW;GACd,QAAQ,OAAO,MAAM,uBAAuB;GAC5C,QAAQ,KAAK;GACb,QAAQ,KAAK,IAAI;EAClB;EAEA,YAAY;EACZ,AAAK,SAAS,IAAI;EAClB,QAAQ,OAAO,MAAM,iEAAiE;CACvF;CAEA,QAAQ,GAAG,UAAU,SAAS,SAAS,WAAW,CAAC;CACnD,QAAQ,GAAG,WAAW,SAAS,SAAS,UAAU,CAAC;CACnD,QAAQ,GAAG,UAAU,SAAS,SAAS,UAAU,CAAC;CAClD,IAAI,QAAQ,aAAa,SAAS,QAAQ,GAAG,iBAAiB,KAAK,QAAQ,QAAQ,QAAQ,CAAC;CAE5F,MAAM,WAAW,SAAS,MAAM,CAAC,CAAC,WAAW,SAAS,SAAS,EAAE,CAAC;CAClE,IAAI;EACH,MAAM,eAAe,QAAQ,KAAK;EAClC,MAAM,QAAQ,MAAM;EACpB,MAAM,MAAM,SAAS,aAAa,MAAM;CACzC,SAAS,OAAO;EACf,QAAQ,IAAI,SAAS,SAAS,iBAAiB,QAAQ,MAAM,kBAAkB,OAAO,OAAO,IAAI,IAAI,OAAO,KAAK,CAAC;EAClH,MAAM,SAAS,SAAS,KAAK;CAC9B;CACA,MAAM;AACP;;;;;;AAOA,eAAe,iBAAiB,QAA2D;CAC1F,IAAI,CAAC,OAAO,IAAI,KAAK,OAAO;CAE5B,MAAM,MAAM,MAAM,sBAAsB,OAAO,IAAI,GAAG;CACtD,OAAO,QAAQ,OAAO,IAAI,MAAM,SAAS;EAAE,GAAG;EAAQ,KAAK;GAAE,GAAG,OAAO;GAAK;EAAI;CAAE;AACnF;AAEA,kBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM;EACL,GAAG;EACH,KAAK;GACJ,MAAM;GACN,aAAa;GACb,SAAS;EACV;EACA,OAAO;GACN,MAAM;GACN,aAAa,uCAAuC,eAAe,KAAK,IAAI,EAAE;EAC/E;EACA,QAAQ;GACP,MAAM;GACN,aAAa,iCAAiC,QAAQ,KAAK,IAAI,EAAE;EAClE;EACA,SAAS;GACR,MAAM;GACN,aAAa;EACd;EACA,OAAO;GACN,MAAM;GACN,aAAa,+DAA+D,OAAO,KAAK,IAAI,EAAE;EAC/F;EAEA,QAAQ;GACP,MAAM;GACN,aAAa;GACb,qBAAqB;EACtB;CACD;CACA,MAAM,IAAI,EAAE,MAAM,WAAW;EAC5B,MAAM,UAAU,YAAY,SAAS,SAAS;EAC9C,MAAM,OAAO;GACZ,QAAQ,KAAK;GACb,KAAK,KAAK;GACV,KAAK,KAAK,MAAM,SAAY;GAC5B,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,SAAS,QAAQ,SAAS,IAAI,UAAU;GACxC,OAAO,KAAK;GACZ,QAAQ,KAAK;EACd,CAAC;CACF;AACD,CAAC"}
@@ -19,6 +19,15 @@ const cliDiagnostics = defineDiagnostics({
19
19
  reporters: [],
20
20
  codes: {
21
21
  PREPARE_OUTDATED: { why: (_p) => "The generated project files are out of date, run `stars prepare` to update it." },
22
+ TSCONFIG_LEGACY_EXTENDS: {
23
+ why: (p) => `${p.file} extends ./.stars/tsconfig.json, which \`stars prepare\` no longer writes from compatibility version 6`,
24
+ fix: (_p) => "Replace it with `{ \"files\": [], \"references\": [{ \"path\": \"./.stars/tsconfig.app.json\" }, { \"path\": \"./.stars/tsconfig.node.json\" }] }`, or set `future.compatibilityVersion` to 5."
25
+ },
26
+ TYPECHECK_FAILED: { why: (p) => `Type errors in ${p.projects}` },
27
+ TYPECHECK_NO_PROJECT: {
28
+ why: (p) => `No tsconfig to type-check in ${p.root}`,
29
+ fix: (_p) => "Create src/tsconfig.json or tsconfig.json, or set `dev.typecheck.tsconfig`."
30
+ },
22
31
  DISCORD_TOKEN_MISSING: {
23
32
  why: (_p) => "DISCORD_TOKEN is not set",
24
33
  fix: (_p) => "Set DISCORD_TOKEN in the environment or in the project .env file."
@@ -77,7 +86,7 @@ const cliDiagnostics = defineDiagnostics({
77
86
  switch (p.reason) {
78
87
  case "MODULE_LOAD_FAILED": return `Install "${p.module}" in the project, or fix its specifier in \`modules\` in stars.config.`;
79
88
  case "MODULE_INCOMPATIBLE": return "Update the module or @wolfstar/http-framework so their versions match.";
80
- case "MODULE_INVALID": return "Export the module with `defineModule` from @wolfstar/kit as the default export.";
89
+ case "MODULE_INVALID": return "Export the module with `defineModule` from @wolfstar/kit as the default export, and give its `meta` a `name` and, if it has a `configKey`, one that is not a built-in key of stars.config or used by another module.";
81
90
  case "MODULE_PLUGIN_INVALID": return "Pass `ctx.addPlugin` a package specifier, an absolute path or a `file:` URL, and JSON-serialisable options.";
82
91
  default: return "Fix the error the module threw (see the cause), or remove it from `modules` in stars.config.";
83
92
  }
@@ -93,4 +102,4 @@ const cliDiagnostics = defineDiagnostics({
93
102
 
94
103
  //#endregion
95
104
  export { cliDiagnostics as t };
96
- //# sourceMappingURL=diagnostics-BysbNnPD.js.map
105
+ //# sourceMappingURL=diagnostics-Dn3CXa8J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics-Dn3CXa8J.js","names":[],"sources":["../src/utils/diagnostics.ts"],"sourcesContent":["import { defineDiagnostics } from 'nostics';\n\n/**\n * Structured, stable diagnostic codes for everything `@wolfstar/cli` itself rejects (as opposed to `stars.config.*`\n * validation, which is `@wolfstar/http-framework`'s own {@link import('@wolfstar/schema').configDiagnostics}).\n *\n * `reporters` stays empty: `runMain` (`src/run.ts`) is the single place that renders a caught `Diagnostic` to the\n * terminal (`formatError`) and picks its exit code (`exitCodeOf`), so nothing here should print on its own — a\n * command that calls e.g. `runBuild` directly (as the test suite does) gets a plain thrown value instead of stray\n * console output.\n *\n * `why` and `fix` are always given the same, fully-typed params object, even when one of them ignores part of it or\n * neither takes any: a bare `() => value` next to a typed sibling loses nostics' param-type inference (a zero-arg\n * function widens to `unknown` params, erasing the sibling's fields from the merged type).\n */\nexport const cliDiagnostics = defineDiagnostics({\n\tdocsBase: (code) => `https://stars-components.js.org/docs/cli/errors#${code.toLowerCase()}`,\n\treporters: [],\n\tcodes: {\n\t\tPREPARE_OUTDATED: {\n\t\t\twhy: (_p: {}) => 'The generated project files are out of date, run `stars prepare` to update it.'\n\t\t},\n\t\tTSCONFIG_LEGACY_EXTENDS: {\n\t\t\twhy: (p: { file: string }) =>\n\t\t\t\t`${p.file} extends ./.stars/tsconfig.json, which \\`stars prepare\\` no longer writes from compatibility version 6`,\n\t\t\tfix: (_p: { file: string }) =>\n\t\t\t\t'Replace it with `{ \"files\": [], \"references\": [{ \"path\": \"./.stars/tsconfig.app.json\" }, { \"path\": \"./.stars/tsconfig.node.json\" }] }`, or set `future.compatibilityVersion` to 5.'\n\t\t},\n\t\tTYPECHECK_FAILED: {\n\t\t\twhy: (p: { projects: string }) => `Type errors in ${p.projects}`\n\t\t},\n\t\tTYPECHECK_NO_PROJECT: {\n\t\t\twhy: (p: { root: string }) => `No tsconfig to type-check in ${p.root}`,\n\t\t\tfix: (_p: { root: string }) => 'Create src/tsconfig.json or tsconfig.json, or set `dev.typecheck.tsconfig`.'\n\t\t},\n\t\tDISCORD_TOKEN_MISSING: {\n\t\t\twhy: (_p: {}) => 'DISCORD_TOKEN is not set',\n\t\t\tfix: (_p: {}) => 'Set DISCORD_TOKEN in the environment or in the project .env file.'\n\t\t},\n\t\tDISCORD_APPLICATION_ID_MISSING: {\n\t\t\twhy: (_p: {}) => 'The Discord application id is not set',\n\t\t\tfix: (_p: {}) => 'Set DISCORD_APPLICATION_ID (or APPLICATION_ID) in the environment or in the project .env file.'\n\t\t},\n\t\tDISCORD_REQUEST_FAILED: {\n\t\t\twhy: (p: { status: number; detail: string }) => `Discord answered ${p.status}${p.detail ? `: ${p.detail}` : ''}`,\n\t\t\tfix: (p: { status: number; detail: string }) =>\n\t\t\t\tp.status === 401 ? 'Check DISCORD_TOKEN.' : 'Check the application id and the bot permissions.'\n\t\t},\n\t\tBUILD_FAILED: {\n\t\t\twhy: (p: { message: string }) => `Build failed${p.message ? `: ${p.message}` : ''}`\n\t\t},\n\t\tCOMMAND_NOT_FOUND: {\n\t\t\twhy: (p: { names: string }) => `No deployed command is named ${p.names}`,\n\t\t\tfix: (_p: { names: string }) => 'Run `stars commands list` to see what is deployed.'\n\t\t},\n\t\tABORTED: {\n\t\t\twhy: (_p: {}) => 'Aborted'\n\t\t},\n\t\tCONFIRMATION_REQUIRED: {\n\t\t\twhy: (_p: {}) => 'Refusing to delete commands without a confirmation',\n\t\t\tfix: (_p: {}) => 'Pass --yes to delete them, or --name to pick one, from a script.'\n\t\t},\n\t\tDEPLOY_CONFIRMATION_REQUIRED: {\n\t\t\twhy: (_p: {}) => 'Refusing to overwrite the deployed commands without a confirmation',\n\t\t\tfix: (_p: {}) => 'Pass --yes to deploy from a script, or with --json.'\n\t\t},\n\t\tCOMMANDS_DIFFER: {\n\t\t\twhy: (p: { count: number }) => `${p.count} deployed command(s) differ from the ones the project defines`,\n\t\t\tfix: (_p: { count: number }) => 'Run `stars commands deploy` to deploy them.'\n\t\t},\n\t\tLOCAL_COMMANDS_UNAVAILABLE: {\n\t\t\twhy: (p: { reason: string; fix: string }) => `Could not read the commands the project defines: ${p.reason}`,\n\t\t\tfix: (p: { reason: string; fix: string }) => p.fix\n\t\t},\n\t\tDOCTOR_FAILED: {\n\t\t\twhy: (p: { count: number }) => `${p.count} check(s) failed`\n\t\t},\n\t\tUNKNOWN_SHELL: {\n\t\t\twhy: (p: { shell: string }) => `No completions for the shell \\`${p.shell}\\`.`,\n\t\t\tfix: (_p: { shell: string }) => 'Use one of: bash, zsh, fish.'\n\t\t},\n\t\tINVALID_THEME: {\n\t\t\twhy: (p: { theme: string; themes: string }) => `Unknown theme \\`${p.theme}\\`.`,\n\t\t\tfix: (p: { theme: string; themes: string }) => `Use one of: ${p.themes}.`\n\t\t},\n\t\tINVALID_OPTION: {\n\t\t\twhy: (p: { option: string; value: string; allowed: string }) => `Unknown value \\`${p.value}\\` for ${p.option}.`,\n\t\t\tfix: (p: { option: string; value: string; allowed: string }) => `Use one of: ${p.allowed}.`\n\t\t},\n\t\tCODEGEN_OUTDATED: {\n\t\t\twhy: (_p: {}) => 'Generated files are out of date, run `stars codegen` to update them.'\n\t\t},\n\t\tDEPENDENCY_MISSING: {\n\t\t\twhy: (p: { name: string; root: string; hint: string }) => `\"${p.name}\" is not installed in ${p.root}`,\n\t\t\tfix: (p: { name: string; root: string; hint: string }) => p.hint\n\t\t},\n\t\tMODULE_FAILED: {\n\t\t\twhy: (p: { module: string; reason: string; message: string }) => p.message,\n\t\t\tfix: (p: { module: string; reason: string; message: string }) => {\n\t\t\t\tswitch (p.reason) {\n\t\t\t\t\tcase 'MODULE_LOAD_FAILED':\n\t\t\t\t\t\treturn `Install \"${p.module}\" in the project, or fix its specifier in \\`modules\\` in stars.config.`;\n\t\t\t\t\tcase 'MODULE_INCOMPATIBLE':\n\t\t\t\t\t\treturn 'Update the module or @wolfstar/http-framework so their versions match.';\n\t\t\t\t\tcase 'MODULE_INVALID':\n\t\t\t\t\t\treturn 'Export the module with `defineModule` from @wolfstar/kit as the default export, and give its `meta` a `name` and, if it has a `configKey`, one that is not a built-in key of stars.config or used by another module.';\n\t\t\t\t\tcase 'MODULE_PLUGIN_INVALID':\n\t\t\t\t\t\treturn 'Pass `ctx.addPlugin` a package specifier, an absolute path or a `file:` URL, and JSON-serialisable options.';\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn 'Fix the error the module threw (see the cause), or remove it from `modules` in stars.config.';\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tMODULES_PRELOAD_REQUIRED: {\n\t\t\twhy: (p: { tool: string; plugins: string }) =>\n\t\t\t\t`The runtime plugins added by modules (${p.plugins}) are registered through \\`node --import\\` with build.tool \"${p.tool}\", which only \\`stars dev\\` does for you`,\n\t\t\tfix: (_p: { tool: string; plugins: string }) =>\n\t\t\t\t'Start the production bot with `node --import ./.stars/modules.mjs <entry>`; `stars prepare` (and `stars build`) writes that file.'\n\t\t},\n\t\tCODEGEN_FAILED: {\n\t\t\twhy: (p: { code: number | null; stderr: string }) => `i18next-type-generator exited with code ${p.code}${p.stderr ? `: ${p.stderr}` : ''}`\n\t\t}\n\t}\n});\n\nexport type CliDiagnosticCode = keyof typeof cliDiagnostics;\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,iBAAiB,kBAAkB;CAC/C,WAAW,SAAS,mDAAmD,KAAK,YAAY;CACxF,WAAW,CAAC;CACZ,OAAO;EACN,kBAAkB,EACjB,MAAM,OAAW,iFAClB;EACA,yBAAyB;GACxB,MAAM,MACL,GAAG,EAAE,KAAK;GACX,MAAM,OACL;EACF;EACA,kBAAkB,EACjB,MAAM,MAA4B,kBAAkB,EAAE,WACvD;EACA,sBAAsB;GACrB,MAAM,MAAwB,gCAAgC,EAAE;GAChE,MAAM,OAAyB;EAChC;EACA,uBAAuB;GACtB,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,gCAAgC;GAC/B,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,wBAAwB;GACvB,MAAM,MAA0C,oBAAoB,EAAE,SAAS,EAAE,SAAS,KAAK,EAAE,WAAW;GAC5G,MAAM,MACL,EAAE,WAAW,MAAM,yBAAyB;EAC9C;EACA,cAAc,EACb,MAAM,MAA2B,eAAe,EAAE,UAAU,KAAK,EAAE,YAAY,KAChF;EACA,mBAAmB;GAClB,MAAM,MAAyB,gCAAgC,EAAE;GACjE,MAAM,OAA0B;EACjC;EACA,SAAS,EACR,MAAM,OAAW,UAClB;EACA,uBAAuB;GACtB,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,8BAA8B;GAC7B,MAAM,OAAW;GACjB,MAAM,OAAW;EAClB;EACA,iBAAiB;GAChB,MAAM,MAAyB,GAAG,EAAE,MAAM;GAC1C,MAAM,OAA0B;EACjC;EACA,4BAA4B;GAC3B,MAAM,MAAuC,oDAAoD,EAAE;GACnG,MAAM,MAAuC,EAAE;EAChD;EACA,eAAe,EACd,MAAM,MAAyB,GAAG,EAAE,MAAM,kBAC3C;EACA,eAAe;GACd,MAAM,MAAyB,kCAAkC,EAAE,MAAM;GACzE,MAAM,OAA0B;EACjC;EACA,eAAe;GACd,MAAM,MAAyC,mBAAmB,EAAE,MAAM;GAC1E,MAAM,MAAyC,eAAe,EAAE,OAAO;EACxE;EACA,gBAAgB;GACf,MAAM,MAA0D,mBAAmB,EAAE,MAAM,SAAS,EAAE,OAAO;GAC7G,MAAM,MAA0D,eAAe,EAAE,QAAQ;EAC1F;EACA,kBAAkB,EACjB,MAAM,OAAW,uEAClB;EACA,oBAAoB;GACnB,MAAM,MAAoD,IAAI,EAAE,KAAK,wBAAwB,EAAE;GAC/F,MAAM,MAAoD,EAAE;EAC7D;EACA,eAAe;GACd,MAAM,MAA2D,EAAE;GACnE,MAAM,MAA2D;IAChE,QAAQ,EAAE,QAAV;KACC,KAAK,sBACJ,OAAO,YAAY,EAAE,OAAO;KAC7B,KAAK,uBACJ,OAAO;KACR,KAAK,kBACJ,OAAO;KACR,KAAK,yBACJ,OAAO;KACR,SACC,OAAO;IACT;GACD;EACD;EACA,0BAA0B;GACzB,MAAM,MACL,yCAAyC,EAAE,QAAQ,8DAA8D,EAAE,KAAK;GACzH,MAAM,OACL;EACF;EACA,gBAAgB,EACf,MAAM,MAA+C,2CAA2C,EAAE,OAAO,EAAE,SAAS,KAAK,EAAE,WAAW,KACvI;CACD;AACD,CAAC"}