@wolfstar/cli 2.1.0 → 2.3.0-next-20261004131917

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 (79) hide show
  1. package/README.md +203 -42
  2. package/dist/{_shared-B-hRZDRS.js → _shared-BIQK0Bhm.js} +12 -5
  3. package/dist/_shared-BIQK0Bhm.js.map +1 -0
  4. package/dist/bridge-BvkmlAOZ.js +410 -0
  5. package/dist/bridge-BvkmlAOZ.js.map +1 -0
  6. package/dist/{build-CPnSLYME.js → build-DJcc95Yq.js} +5 -5
  7. package/dist/{build-CPnSLYME.js.map → build-DJcc95Yq.js.map} +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/{codegen-BqpLGLLs.js → codegen-aJSyPz-J.js} +4 -4
  10. package/dist/{codegen-BqpLGLLs.js.map → codegen-aJSyPz-J.js.map} +1 -1
  11. package/dist/command-diff-BK912Hjc.js +78 -0
  12. package/dist/command-diff-BK912Hjc.js.map +1 -0
  13. package/dist/commands-CIPWQtF0.js +3 -0
  14. package/dist/commands-Clpbqq3K.js +15 -0
  15. package/dist/commands-Clpbqq3K.js.map +1 -0
  16. package/dist/{commands-ExM8HILu.js → commands-DVC7ky6f.js} +259 -9
  17. package/dist/commands-DVC7ky6f.js.map +1 -0
  18. package/dist/completions-D2KYtrrv.js +161 -0
  19. package/dist/completions-D2KYtrrv.js.map +1 -0
  20. package/dist/{dev-4wpEQC7l.js → dev-oPPVR7d_.js} +432 -45
  21. package/dist/dev-oPPVR7d_.js.map +1 -0
  22. package/dist/{diagnostics-CZBVxlpj.js → diagnostics-BysbNnPD.js} +38 -1
  23. package/dist/diagnostics-BysbNnPD.js.map +1 -0
  24. package/dist/doctor-DkVUwgDd.js +334 -0
  25. package/dist/doctor-DkVUwgDd.js.map +1 -0
  26. package/dist/{errors-Crt4hu0b.js → errors-COFWKKKw.js} +5 -2
  27. package/dist/errors-COFWKKKw.js.map +1 -0
  28. package/dist/hooks-Cy6F2bhH.js +332 -0
  29. package/dist/hooks-Cy6F2bhH.js.map +1 -0
  30. package/dist/index.d.ts +75 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +4 -4
  33. package/dist/{info-CdiQajgn.js → info-CKJVMWIT.js} +16 -5
  34. package/dist/info-CKJVMWIT.js.map +1 -0
  35. package/dist/{locales-C7X8VNmK.js → locales-BJAP4HYf.js} +5 -5
  36. package/dist/{locales-C7X8VNmK.js.map → locales-BJAP4HYf.js.map} +1 -1
  37. package/dist/log-view-B7uJEnMR.js +342 -0
  38. package/dist/log-view-B7uJEnMR.js.map +1 -0
  39. package/dist/{nitro-sP2F3SQu.js → nitro-B8u1iVgf.js} +2 -2
  40. package/dist/{nitro-sP2F3SQu.js.map → nitro-B8u1iVgf.js.map} +1 -1
  41. package/dist/{plain-B6z85uQP.js → plain-DG7cy0Kk.js} +7 -2
  42. package/dist/plain-DG7cy0Kk.js.map +1 -0
  43. package/dist/{prepare-B4ysyG6H.js → prepare-BM93i3Rm.js} +9 -5
  44. package/dist/prepare-BM93i3Rm.js.map +1 -0
  45. package/dist/{project-MD4dIo2X.js → project-zlQStwsf.js} +2 -2
  46. package/dist/{project-MD4dIo2X.js.map → project-zlQStwsf.js.map} +1 -1
  47. package/dist/{run-Ddwrxe1O.js → run-DMM2YlP3.js} +3 -13
  48. package/dist/run-DMM2YlP3.js.map +1 -0
  49. package/dist/{theme-3Fc_LI-2.js → theme-yS2h5dd_.js} +25 -1
  50. package/dist/theme-yS2h5dd_.js.map +1 -0
  51. package/dist/tsc-C5l5TQGC.js +3 -0
  52. package/dist/{tsc-DO7D_uCl.js → tsc-puVAcwmo.js} +24 -5
  53. package/dist/tsc-puVAcwmo.js.map +1 -0
  54. package/dist/{tsdown-CD68G8_U.js → tsdown-Dwt3JhPw.js} +2 -2
  55. package/dist/{tsdown-CD68G8_U.js.map → tsdown-Dwt3JhPw.js.map} +1 -1
  56. package/dist/{tui-BRddrLQP.js → tui-nldGSD4c.js} +913 -141
  57. package/dist/tui-nldGSD4c.js.map +1 -0
  58. package/dist/{vite-CLyB6wl7.js → vite-YZUtv2Hk.js} +2 -2
  59. package/dist/{vite-CLyB6wl7.js.map → vite-YZUtv2Hk.js.map} +1 -1
  60. package/package.json +5 -4
  61. package/dist/_shared-B-hRZDRS.js.map +0 -1
  62. package/dist/commands-ExM8HILu.js.map +0 -1
  63. package/dist/dev-4wpEQC7l.js.map +0 -1
  64. package/dist/diagnostics-CZBVxlpj.js.map +0 -1
  65. package/dist/errors-Crt4hu0b.js.map +0 -1
  66. package/dist/hooks-H9kjLCMk.js +0 -148
  67. package/dist/hooks-H9kjLCMk.js.map +0 -1
  68. package/dist/info-CdiQajgn.js.map +0 -1
  69. package/dist/log-buffer-CY82aqnb.js +0 -72
  70. package/dist/log-buffer-CY82aqnb.js.map +0 -1
  71. package/dist/plain-B6z85uQP.js.map +0 -1
  72. package/dist/prepare-B4ysyG6H.js.map +0 -1
  73. package/dist/run-Ddwrxe1O.js.map +0 -1
  74. package/dist/theme-3Fc_LI-2.js.map +0 -1
  75. package/dist/tsc-DO7D_uCl.js.map +0 -1
  76. package/dist/tsc-YnAWKn3n.js +0 -3
  77. package/dist/tui-BRddrLQP.js.map +0 -1
  78. package/dist/tunnel-DT1FH6oA.js +0 -175
  79. package/dist/tunnel-DT1FH6oA.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info-CKJVMWIT.js","names":[],"sources":["../src/commands/info.ts"],"sourcesContent":["import { displayPath, type ResolvedStarsConfig, type StarsEnvSetupOptions } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { arch, platform } from 'node:os';\nimport { relative } from 'node:path';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { applyEnvOptions, loadProject } from '../utils/hooks.js';\nimport { modulesPreloadWarning } from '../utils/modules.js';\nimport { resolveOutputMode, shouldUseColor } from '../utils/output-mode.js';\nimport { findInstalledVersion } from '../utils/project.js';\nimport { readOwnPackageJson } from '../utils/version.js';\n\nexport interface InfoOptions extends ProjectArgs {\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport interface ProjectInfo {\n\tcli: { version: string; node: string; platform: string; outputMode: 'tui' | 'plain' };\n\tproject: {\n\t\tcwd: string;\n\t\troot: string;\n\t\tconfigFile: string | null;\n\t\tname: string | null;\n\t\tversion: string | null;\n\t\tentry: string;\n\t\tframeworkVersion: string | null;\n\t};\n\tbuild: ResolvedStarsConfig['build'];\n\tdev: ResolvedStarsConfig['dev'];\n\tcodegen: ResolvedStarsConfig['codegen'];\n\timports: ResolvedStarsConfig['imports'];\n\texperimental: ResolvedStarsConfig['experimental'];\n\tfuture: ResolvedStarsConfig['future'];\n\tenv: ResolvedStarsConfig['env'];\n\t/** The names of the hooks registered in `stars.config`, flattened (`build:done`). */\n\thooks: string[];\n\t/** The installed modules, and the runtime plugins they registered (`module → export from package`). */\n\tmodules: { installed: string[]; plugins: string[] };\n\t/** Non-fatal configuration diagnostics, as `CODE: message`. */\n\twarnings: string[];\n\t/**\n\t * The option names set in the `tsdown`/`vite` blocks. Only the names: the values hold plugins and callbacks,\n\t * which neither serialize to JSON nor read usefully on a terminal.\n\t */\n\toptions: { tsdown: string[]; vite: string[] };\n}\n\nexport function collectInfo(config: ResolvedStarsConfig): ProjectInfo {\n\treturn {\n\t\tcli: {\n\t\t\tversion: readOwnPackageJson().version,\n\t\t\tnode: process.version,\n\t\t\tplatform: `${platform()} ${arch()}`,\n\t\t\toutputMode: resolveOutputMode()\n\t\t},\n\t\tproject: {\n\t\t\tcwd: config.cwd,\n\t\t\troot: config.root,\n\t\t\tconfigFile: config.configFile,\n\t\t\tname: config.packageJson?.name ?? null,\n\t\t\tversion: config.packageJson?.version ?? null,\n\t\t\tentry: config.entry,\n\t\t\tframeworkVersion: findInstalledVersion(config.root, '@wolfstar/http-framework')\n\t\t},\n\t\tbuild: config.build,\n\t\tdev: config.dev,\n\t\tcodegen: config.codegen,\n\t\timports: config.imports,\n\t\texperimental: config.experimental,\n\t\tfuture: config.future,\n\t\tenv: config.env,\n\t\thooks: Object.keys(config.hooks),\n\t\tmodules: {\n\t\t\tinstalled: (config.runtime?.modules ?? []).map((module) => module.name),\n\t\t\tplugins: (config.runtime?.plugins ?? []).map((plugin) => `${plugin.module} → ${plugin.export} from ${plugin.from}`)\n\t\t},\n\t\twarnings: [...config.warnings, modulesPreloadWarning(config)]\n\t\t\t.filter((warning) => warning !== null)\n\t\t\t.map((warning) => `${warning.code}: ${warning.message}`),\n\t\toptions: { tsdown: Object.keys(config.tsdown), vite: Object.keys(config.vite) }\n\t};\n}\n\nexport function formatInfo(info: ProjectInfo, useColor: boolean): string {\n\tconst colors = createColors({ useColor });\n\tconst { root } = info.project;\n\tconst show = (path: string | null) => (path === null ? colors.dim('none') : displayPath(root, path));\n\tconst row = (label: string, value: string) => ` ${colors.dim(label.padEnd(12))}${value}`;\n\tconst section = (title: string, rows: string[]) => [colors.bold(title), ...rows].join('\\n');\n\n\treturn [\n\t\tsection(`stars ${colors.green(`v${info.cli.version}`)}`, [\n\t\t\trow('node', info.cli.node),\n\t\t\trow('platform', info.cli.platform),\n\t\t\trow('output', info.cli.outputMode),\n\t\t\trow(\n\t\t\t\t'framework',\n\t\t\t\tinfo.project.frameworkVersion\n\t\t\t\t\t? `@wolfstar/http-framework v${info.project.frameworkVersion}`\n\t\t\t\t\t: colors.yellow('@wolfstar/http-framework not installed')\n\t\t\t)\n\t\t]),\n\t\tsection('Project', [\n\t\t\trow(\n\t\t\t\t'name',\n\t\t\t\tinfo.project.name\n\t\t\t\t\t? `${info.project.name}${info.project.version ? colors.dim(` v${info.project.version}`) : ''}`\n\t\t\t\t\t: colors.dim('unnamed')\n\t\t\t),\n\t\t\trow('root', root),\n\t\t\trow(\n\t\t\t\t'config',\n\t\t\t\tinfo.project.configFile ? relative(root, info.project.configFile) || info.project.configFile : colors.dim('none (defaults)')\n\t\t\t),\n\t\t\trow('entry', show(info.project.entry))\n\t\t]),\n\t\tsection('Build', [\n\t\t\trow('tool', info.build.tool),\n\t\t\t// Which file the build tool is configured from: its own, or this project's `stars.config`.\n\t\t\trow('config', info.build.configFile ? show(info.build.configFile) : colors.dim('stars.config')),\n\t\t\trow('options', describeOptions(info, colors)),\n\t\t\trow('outDir', show(info.build.outDir)),\n\t\t\trow('tsconfig', show(info.build.tsconfig)),\n\t\t\trow('runs', show(info.build.output))\n\t\t]),\n\t\tsection('Dev', [\n\t\t\trow('watch', info.dev.watch.map(show).join(', ')),\n\t\t\trow('debounce', `${info.dev.debounce}ms`),\n\t\t\trow('node args', info.dev.nodeArgs.join(' ') || colors.dim('none')),\n\t\t\trow('args', info.dev.args.join(' ') || colors.dim('none')),\n\t\t\trow('url', info.dev.url ?? colors.dim('unknown, set dev.url or HTTP_PORT')),\n\t\t\trow('health', info.dev.health ?? colors.dim('none')),\n\t\t\trow(\n\t\t\t\t'typecheck',\n\t\t\t\tinfo.dev.typecheck.enabled ? `${info.dev.typecheck.checker} → ${show(info.dev.typecheck.tsconfig)}` : colors.dim('disabled')\n\t\t\t),\n\t\t\trow('tunnel', describeTunnel(info.dev.tunnel, colors)),\n\t\t\trow('log file', info.dev.logFile ? show(info.dev.logFile) : colors.dim('disabled')),\n\t\t\trow('log dir', info.dev.logs.dir ? `${show(info.dev.logs.dir)} (keeps ${info.dev.logs.keep})` : colors.dim('disabled')),\n\t\t\trow('layout', info.dev.layout),\n\t\t\trow('channels', info.dev.logs.channels?.join(', ') ?? colors.dim('all')),\n\t\t\trow('levels', info.dev.logs.levels.join(', ')),\n\t\t\trow('commands', `refresh: ${info.dev.commands.refresh}`),\n\t\t\trow('hmr', info.dev.hmr ? 'left to the bot when it hot reloads' : colors.dim('always restart'))\n\t\t]),\n\t\tsection('Codegen', [\n\t\t\trow('i18n', info.codegen.i18n ? `${show(info.codegen.i18n.locales)} → ${show(info.codegen.i18n.output)}` : colors.dim('disabled'))\n\t\t]),\n\t\tsection('Future', [\n\t\t\trow('compat', `v${info.future.compatibilityVersion} defaults`),\n\t\t\t...info.warnings.map((warning) => row('warning', colors.yellow(warning)))\n\t\t]),\n\t\tsection('Env', [row('register', info.env.enabled ? colors.green(describeEnvOptions(info.env.options)) : colors.dim('disabled'))]),\n\t\tsection('Hooks', [row('registered', info.hooks.join(', ') || colors.dim('none'))]),\n\t\tsection('Modules', [\n\t\t\trow('installed', info.modules.installed.join(', ') || colors.dim('none')),\n\t\t\t...info.modules.plugins.map((plugin) => row('plugin', plugin))\n\t\t]),\n\t\tsection('Experimental', [\n\t\t\trow('vite', flag(info.experimental.enableVite, colors)),\n\t\t\trow('nitro', flag(info.experimental.enableNitro, colors)),\n\t\t\t...(info.experimental.enableNitro ? [row('nitro preset', info.experimental.nitro.preset)] : []),\n\t\t\trow('external', flag(info.experimental.enableExternalVite, colors))\n\t\t]),\n\t\tsection('Imports', [\n\t\t\trow('auto', info.imports.enabled ? colors.green('enabled') : colors.dim('disabled')),\n\t\t\trow('dirs', info.imports.dirs.map(show).join(', ')),\n\t\t\trow('presets', info.imports.presets.join(', ') || colors.dim('none')),\n\t\t\trow('dts', show(info.imports.dts))\n\t\t])\n\t].join('\\n\\n');\n}\n\nfunction describeOptions(info: ProjectInfo, colors: ReturnType<typeof createColors>): string {\n\tconst names = info.build.tool === 'vite' ? info.options.vite : info.options.tsdown;\n\treturn names.length > 0 ? names.join(', ') : colors.dim('none');\n}\n\nfunction describeEnvOptions(options: Readonly<StarsEnvSetupOptions>): string {\n\tconst entries = Object.entries(options).map(([key, value]) => `${key} ${String(value)}`);\n\treturn entries.length > 0 ? `enabled (${entries.join(', ')})` : 'enabled';\n}\n\nfunction flag(enabled: boolean, colors: ReturnType<typeof createColors>): string {\n\treturn enabled ? colors.green('enabled') : colors.dim('disabled');\n}\n\nfunction describeTunnel(tunnel: ResolvedStarsConfig['dev']['tunnel'], colors: ReturnType<typeof createColors>): string {\n\tswitch (tunnel.mode) {\n\t\tcase 'quick':\n\t\t\treturn 'cloudflared quick tunnel';\n\t\tcase 'url':\n\t\t\treturn tunnel.url;\n\t\tdefault:\n\t\t\treturn colors.dim('disabled');\n\t}\n}\n\nexport async function runInfo(options: InfoOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst project = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\t// What the build would use: `env:options` may change the env files.\n\tconst config = await applyEnvOptions(project.config, project.hooks);\n\tconst info = collectInfo(config);\n\tstdout.write(`${options.json ? JSON.stringify(info, null, 2) : formatInfo(info, shouldUseColor())}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'info',\n\t\tdescription: 'Print the resolved project configuration and environment'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runInfo({ config: args.config, cwd: args.cwd, json: args.json });\n\t}\n});\n"],"mappings":"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"}
@@ -12,20 +12,20 @@ async function createBuilder(config, hooks) {
12
12
  return new ExternalBuilder(config);
13
13
  }
14
14
  if (config.experimental.enableNitro) {
15
- const { NitroBuilder } = await import("./nitro-sP2F3SQu.js");
15
+ const { NitroBuilder } = await import("./nitro-B8u1iVgf.js");
16
16
  return new NitroBuilder(config);
17
17
  }
18
18
  switch (config.build.tool) {
19
19
  case "tsdown": {
20
- const { TsdownBuilder } = await import("./tsdown-CD68G8_U.js");
20
+ const { TsdownBuilder } = await import("./tsdown-Dwt3JhPw.js");
21
21
  return new TsdownBuilder(config, hooks);
22
22
  }
23
23
  case "vite": {
24
- const { ViteBuilder } = await import("./vite-CLyB6wl7.js");
24
+ const { ViteBuilder } = await import("./vite-YZUtv2Hk.js");
25
25
  return new ViteBuilder(config);
26
26
  }
27
27
  case "tsc": {
28
- const { TscBuilder } = await import("./tsc-YnAWKn3n.js");
28
+ const { TscBuilder } = await import("./tsc-C5l5TQGC.js");
29
29
  return new TscBuilder(config);
30
30
  }
31
31
  case "none": {
@@ -94,4 +94,4 @@ var Locales = class extends EventEmitter {
94
94
 
95
95
  //#endregion
96
96
  export { createBuilder as n, Locales as t };
97
- //# sourceMappingURL=locales-C7X8VNmK.js.map
97
+ //# sourceMappingURL=locales-BJAP4HYf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"locales-C7X8VNmK.js","names":[],"sources":["../src/builders/index.ts","../src/utils/locales.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { StarsHookable } from '../utils/hooks.js';\nimport type { Builder } from './types.js';\n\n/**\n * Creates the builder for `build.tool`. `hooks` reach the builders that expose hooks of their own (`tsdown:options`).\n */\nexport async function createBuilder(config: ResolvedStarsConfig, hooks?: StarsHookable): Promise<Builder> {\n\t// The project runs its own build, so the CLI only watches what it writes (see `ExternalBuilder`) — including when\n\t// it is driving `vite build` with its own `nitro()` plugin itself; `build.output` already points at Nitro's\n\t// `server/index.mjs` in that case (see `resolveBuild`).\n\tif (config.experimental.enableExternalVite) {\n\t\tconst { ExternalBuilder } = await import('./external.js');\n\t\treturn new ExternalBuilder(config);\n\t}\n\n\t// Nitro is itself a Vite plugin — there is no separate `nitro build` step — so it is handled before the\n\t// `build.tool` switch below, the same way `enableExternalVite` is.\n\tif (config.experimental.enableNitro) {\n\t\tconst { NitroBuilder } = await import('./nitro.js');\n\t\treturn new NitroBuilder(config);\n\t}\n\n\tswitch (config.build.tool) {\n\t\tcase 'tsdown': {\n\t\t\tconst { TsdownBuilder } = await import('./tsdown.js');\n\t\t\treturn new TsdownBuilder(config, hooks);\n\t\t}\n\t\tcase 'vite': {\n\t\t\tconst { ViteBuilder } = await import('./vite.js');\n\t\t\treturn new ViteBuilder(config);\n\t\t}\n\t\tcase 'tsc': {\n\t\t\tconst { TscBuilder } = await import('./tsc.js');\n\t\t\treturn new TscBuilder(config);\n\t\t}\n\t\tcase 'none': {\n\t\t\tconst { NoneBuilder } = await import('./none.js');\n\t\t\treturn new NoneBuilder(config);\n\t\t}\n\t}\n}\n\nexport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\n","import { EventEmitter } from 'node:events';\nimport { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { LogLevel } from './log-buffer.js';\n\nexport interface LocalesEvents {\n\tchange: [];\n\tlog: [level: LogLevel, text: string];\n}\n\n/** Keeps the conventional `src/locales` data directory next to the compiled application. */\nexport class Locales extends EventEmitter<LocalesEvents> {\n\treadonly source: string;\n\treadonly destination: string;\n\t#watcher: { close(): Promise<void> } | null = null;\n\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\n\t\tsuper();\n\t\tthis.source = join(config.root, 'src', 'locales');\n\t\tthis.destination = join(config.build.outDir, 'locales');\n\t}\n\n\tpublic copy(): boolean {\n\t\tif (this.config.build.tool === 'none' || !existsSync(this.source)) return false;\n\t\tmkdirSync(this.destination, { recursive: true });\n\t\tcpSync(this.source, this.destination, { recursive: true, force: true });\n\t\treturn true;\n\t}\n\n\tpublic async watch(): Promise<void> {\n\t\tif (this.config.build.tool === 'none' || !existsSync(this.source) || this.#watcher) return;\n\t\tconst { watch } = await import('chokidar');\n\t\tconst watcher = watch(this.source, { ignoreInitial: true });\n\t\tthis.#watcher = watcher;\n\n\t\twatcher.on('all', (event, path) => {\n\t\t\ttry {\n\t\t\t\tconst target = join(this.destination, relative(this.source, path));\n\t\t\t\tif (event === 'unlink' || event === 'unlinkDir') rmSync(target, { recursive: event === 'unlinkDir', force: true });\n\t\t\t\telse if (existsSync(path)) {\n\t\t\t\t\tmkdirSync(dirname(target), { recursive: true });\n\t\t\t\t\tcpSync(path, target, { recursive: event === 'addDir', force: true });\n\t\t\t\t}\n\t\t\t\tthis.emit('change');\n\t\t\t} catch (error) {\n\t\t\t\tthis.emit('log', 'error', `Failed to copy locales: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t}\n\t\t});\n\t\twatcher.on('error', (error) => this.emit('log', 'error', error instanceof Error ? error.message : String(error)));\n\t\tawait new Promise<void>((resolve) => watcher.once('ready', resolve));\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tconst watcher = this.#watcher;\n\t\tthis.#watcher = null;\n\t\tawait watcher?.close();\n\t}\n}\n"],"mappings":";;;;;;;;AAOA,eAAsB,cAAc,QAA6B,OAAyC;CAIzG,IAAI,OAAO,aAAa,oBAAoB;EAC3C,MAAM,EAAE,oBAAoB,MAAM,OAAO;EACzC,OAAO,IAAI,gBAAgB,MAAM;CAClC;CAIA,IAAI,OAAO,aAAa,aAAa;EACpC,MAAM,EAAE,iBAAiB,MAAM,OAAO;EACtC,OAAO,IAAI,aAAa,MAAM;CAC/B;CAEA,QAAQ,OAAO,MAAM,MAArB;EACC,KAAK,UAAU;GACd,MAAM,EAAE,kBAAkB,MAAM,OAAO;GACvC,OAAO,IAAI,cAAc,QAAQ,KAAK;EACvC;EACA,KAAK,QAAQ;GACZ,MAAM,EAAE,gBAAgB,MAAM,OAAO;GACrC,OAAO,IAAI,YAAY,MAAM;EAC9B;EACA,KAAK,OAAO;GACX,MAAM,EAAE,eAAe,MAAM,OAAO;GACpC,OAAO,IAAI,WAAW,MAAM;EAC7B;EACA,KAAK,QAAQ;GACZ,MAAM,EAAE,gBAAgB,MAAM,OAAO;GACrC,OAAO,IAAI,YAAY,MAAM;EAC9B;CACD;AACD;;;;;AC7BA,IAAa,UAAb,cAA6B,aAA4B;CAKpB;CAJpC,AAAS;CACT,AAAS;CACT,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;EAEnC,KAAK,SAAS,KAAK,OAAO,MAAM,OAAO,SAAS;EAChD,KAAK,cAAc,KAAK,OAAO,MAAM,QAAQ,SAAS;CACvD;CAEA,AAAO,OAAgB;EACtB,IAAI,KAAK,OAAO,MAAM,SAAS,UAAU,CAAC,WAAW,KAAK,MAAM,GAAG,OAAO;EAC1E,UAAU,KAAK,aAAa,EAAE,WAAW,KAAK,CAAC;EAC/C,OAAO,KAAK,QAAQ,KAAK,aAAa;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACtE,OAAO;CACR;CAEA,MAAa,QAAuB;EACnC,IAAI,KAAK,OAAO,MAAM,SAAS,UAAU,CAAC,WAAW,KAAK,MAAM,KAAK,KAAK,UAAU;EACpF,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,UAAU,MAAM,KAAK,QAAQ,EAAE,eAAe,KAAK,CAAC;EAC1D,KAAK,WAAW;EAEhB,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAClC,IAAI;IACH,MAAM,SAAS,KAAK,KAAK,aAAa,SAAS,KAAK,QAAQ,IAAI,CAAC;IACjE,IAAI,UAAU,YAAY,UAAU,aAAa,OAAO,QAAQ;KAAE,WAAW,UAAU;KAAa,OAAO;IAAK,CAAC;SAC5G,IAAI,WAAW,IAAI,GAAG;KAC1B,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;KAC9C,OAAO,MAAM,QAAQ;MAAE,WAAW,UAAU;MAAU,OAAO;KAAK,CAAC;IACpE;IACA,KAAK,KAAK,QAAQ;GACnB,SAAS,OAAO;IACf,KAAK,KAAK,OAAO,SAAS,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GAC9G;EACD,CAAC;EACD,QAAQ,GAAG,UAAU,UAAU,KAAK,KAAK,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;EAChH,MAAM,IAAI,SAAe,YAAY,QAAQ,KAAK,SAAS,OAAO,CAAC;CACpE;CAEA,MAAa,QAAuB;EACnC,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,MAAM,SAAS,MAAM;CACtB;AACD"}
1
+ {"version":3,"file":"locales-BJAP4HYf.js","names":[],"sources":["../src/builders/index.ts","../src/utils/locales.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { StarsHookable } from '../utils/hooks.js';\nimport type { Builder } from './types.js';\n\n/**\n * Creates the builder for `build.tool`. `hooks` reach the builders that expose hooks of their own (`tsdown:options`).\n */\nexport async function createBuilder(config: ResolvedStarsConfig, hooks?: StarsHookable): Promise<Builder> {\n\t// The project runs its own build, so the CLI only watches what it writes (see `ExternalBuilder`) — including when\n\t// it is driving `vite build` with its own `nitro()` plugin itself; `build.output` already points at Nitro's\n\t// `server/index.mjs` in that case (see `resolveBuild`).\n\tif (config.experimental.enableExternalVite) {\n\t\tconst { ExternalBuilder } = await import('./external.js');\n\t\treturn new ExternalBuilder(config);\n\t}\n\n\t// Nitro is itself a Vite plugin — there is no separate `nitro build` step — so it is handled before the\n\t// `build.tool` switch below, the same way `enableExternalVite` is.\n\tif (config.experimental.enableNitro) {\n\t\tconst { NitroBuilder } = await import('./nitro.js');\n\t\treturn new NitroBuilder(config);\n\t}\n\n\tswitch (config.build.tool) {\n\t\tcase 'tsdown': {\n\t\t\tconst { TsdownBuilder } = await import('./tsdown.js');\n\t\t\treturn new TsdownBuilder(config, hooks);\n\t\t}\n\t\tcase 'vite': {\n\t\t\tconst { ViteBuilder } = await import('./vite.js');\n\t\t\treturn new ViteBuilder(config);\n\t\t}\n\t\tcase 'tsc': {\n\t\t\tconst { TscBuilder } = await import('./tsc.js');\n\t\t\treturn new TscBuilder(config);\n\t\t}\n\t\tcase 'none': {\n\t\t\tconst { NoneBuilder } = await import('./none.js');\n\t\t\treturn new NoneBuilder(config);\n\t\t}\n\t}\n}\n\nexport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\n","import { EventEmitter } from 'node:events';\nimport { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';\nimport { dirname, join, relative } from 'node:path';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { LogLevel } from './log-buffer.js';\n\nexport interface LocalesEvents {\n\tchange: [];\n\tlog: [level: LogLevel, text: string];\n}\n\n/** Keeps the conventional `src/locales` data directory next to the compiled application. */\nexport class Locales extends EventEmitter<LocalesEvents> {\n\treadonly source: string;\n\treadonly destination: string;\n\t#watcher: { close(): Promise<void> } | null = null;\n\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\n\t\tsuper();\n\t\tthis.source = join(config.root, 'src', 'locales');\n\t\tthis.destination = join(config.build.outDir, 'locales');\n\t}\n\n\tpublic copy(): boolean {\n\t\tif (this.config.build.tool === 'none' || !existsSync(this.source)) return false;\n\t\tmkdirSync(this.destination, { recursive: true });\n\t\tcpSync(this.source, this.destination, { recursive: true, force: true });\n\t\treturn true;\n\t}\n\n\tpublic async watch(): Promise<void> {\n\t\tif (this.config.build.tool === 'none' || !existsSync(this.source) || this.#watcher) return;\n\t\tconst { watch } = await import('chokidar');\n\t\tconst watcher = watch(this.source, { ignoreInitial: true });\n\t\tthis.#watcher = watcher;\n\n\t\twatcher.on('all', (event, path) => {\n\t\t\ttry {\n\t\t\t\tconst target = join(this.destination, relative(this.source, path));\n\t\t\t\tif (event === 'unlink' || event === 'unlinkDir') rmSync(target, { recursive: event === 'unlinkDir', force: true });\n\t\t\t\telse if (existsSync(path)) {\n\t\t\t\t\tmkdirSync(dirname(target), { recursive: true });\n\t\t\t\t\tcpSync(path, target, { recursive: event === 'addDir', force: true });\n\t\t\t\t}\n\t\t\t\tthis.emit('change');\n\t\t\t} catch (error) {\n\t\t\t\tthis.emit('log', 'error', `Failed to copy locales: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t}\n\t\t});\n\t\twatcher.on('error', (error) => this.emit('log', 'error', error instanceof Error ? error.message : String(error)));\n\t\tawait new Promise<void>((resolve) => watcher.once('ready', resolve));\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tconst watcher = this.#watcher;\n\t\tthis.#watcher = null;\n\t\tawait watcher?.close();\n\t}\n}\n"],"mappings":";;;;;;;;AAOA,eAAsB,cAAc,QAA6B,OAAyC;CAIzG,IAAI,OAAO,aAAa,oBAAoB;EAC3C,MAAM,EAAE,oBAAoB,MAAM,OAAO;EACzC,OAAO,IAAI,gBAAgB,MAAM;CAClC;CAIA,IAAI,OAAO,aAAa,aAAa;EACpC,MAAM,EAAE,iBAAiB,MAAM,OAAO;EACtC,OAAO,IAAI,aAAa,MAAM;CAC/B;CAEA,QAAQ,OAAO,MAAM,MAArB;EACC,KAAK,UAAU;GACd,MAAM,EAAE,kBAAkB,MAAM,OAAO;GACvC,OAAO,IAAI,cAAc,QAAQ,KAAK;EACvC;EACA,KAAK,QAAQ;GACZ,MAAM,EAAE,gBAAgB,MAAM,OAAO;GACrC,OAAO,IAAI,YAAY,MAAM;EAC9B;EACA,KAAK,OAAO;GACX,MAAM,EAAE,eAAe,MAAM,OAAO;GACpC,OAAO,IAAI,WAAW,MAAM;EAC7B;EACA,KAAK,QAAQ;GACZ,MAAM,EAAE,gBAAgB,MAAM,OAAO;GACrC,OAAO,IAAI,YAAY,MAAM;EAC9B;CACD;AACD;;;;;AC7BA,IAAa,UAAb,cAA6B,aAA4B;CAKpB;CAJpC,AAAS;CACT,AAAS;CACT,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;EAEnC,KAAK,SAAS,KAAK,OAAO,MAAM,OAAO,SAAS;EAChD,KAAK,cAAc,KAAK,OAAO,MAAM,QAAQ,SAAS;CACvD;CAEA,AAAO,OAAgB;EACtB,IAAI,KAAK,OAAO,MAAM,SAAS,UAAU,CAAC,WAAW,KAAK,MAAM,GAAG,OAAO;EAC1E,UAAU,KAAK,aAAa,EAAE,WAAW,KAAK,CAAC;EAC/C,OAAO,KAAK,QAAQ,KAAK,aAAa;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACtE,OAAO;CACR;CAEA,MAAa,QAAuB;EACnC,IAAI,KAAK,OAAO,MAAM,SAAS,UAAU,CAAC,WAAW,KAAK,MAAM,KAAK,KAAK,UAAU;EACpF,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,UAAU,MAAM,KAAK,QAAQ,EAAE,eAAe,KAAK,CAAC;EAC1D,KAAK,WAAW;EAEhB,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAClC,IAAI;IACH,MAAM,SAAS,KAAK,KAAK,aAAa,SAAS,KAAK,QAAQ,IAAI,CAAC;IACjE,IAAI,UAAU,YAAY,UAAU,aAAa,OAAO,QAAQ;KAAE,WAAW,UAAU;KAAa,OAAO;IAAK,CAAC;SAC5G,IAAI,WAAW,IAAI,GAAG;KAC1B,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;KAC9C,OAAO,MAAM,QAAQ;MAAE,WAAW,UAAU;MAAU,OAAO;KAAK,CAAC;IACpE;IACA,KAAK,KAAK,QAAQ;GACnB,SAAS,OAAO;IACf,KAAK,KAAK,OAAO,SAAS,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GAC9G;EACD,CAAC;EACD,QAAQ,GAAG,UAAU,UAAU,KAAK,KAAK,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;EAChH,MAAM,IAAI,SAAe,YAAY,QAAQ,KAAK,SAAS,OAAO,CAAC;CACpE;CAEA,MAAa,QAAuB;EACnC,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,MAAM,SAAS,MAAM;CACtB;AACD"}
@@ -0,0 +1,342 @@
1
+ import { DEFAULT_LOG_LEVELS, LOG_LEVELS } from "@wolfstar/schema";
2
+ import { EventEmitter } from "node:events";
3
+ import { stripVTControlCharacters } from "node:util";
4
+
5
+ //#region src/utils/log-buffer.ts
6
+ /**
7
+ * The channel an entry of each source lands on unless it names one: who wrote it. The bot's own events (`hmr`,
8
+ * `commands`, `interactions`, `http`, `lifecycle`) and plugins pick their own.
9
+ */
10
+ const SOURCE_CHANNELS = {
11
+ stars: "cli",
12
+ build: "build",
13
+ app: "bot",
14
+ tsc: "types",
15
+ tunnel: "tunnel"
16
+ };
17
+ /**
18
+ * A bounded, in-memory log store shared by the dev service and its renderers.
19
+ */
20
+ var LogBuffer = class extends EventEmitter {
21
+ capacity;
22
+ #entries = [];
23
+ #channels = /* @__PURE__ */ new Set();
24
+ #nextId = 1;
25
+ constructor(capacity = 2e3) {
26
+ super();
27
+ this.capacity = capacity;
28
+ }
29
+ push(input) {
30
+ const entry = {
31
+ id: this.#nextId++,
32
+ time: Date.now(),
33
+ ...input,
34
+ channel: input.channel ?? SOURCE_CHANNELS[input.source]
35
+ };
36
+ this.#channels.add(entry.channel);
37
+ this.#entries.push(entry);
38
+ if (this.#entries.length > this.capacity) this.#entries.splice(0, this.#entries.length - this.capacity);
39
+ this.emit("entry", entry);
40
+ return entry;
41
+ }
42
+ entries() {
43
+ return this.#entries;
44
+ }
45
+ /** Every channel an entry was logged on since the session started, sorted. Clearing the logs keeps them. */
46
+ channels() {
47
+ return [...this.#channels].sort();
48
+ }
49
+ filter(filter) {
50
+ const query = filter.query?.toLowerCase() ?? null;
51
+ return this.#entries.filter((entry) => (!filter.source || entry.source === filter.source) && (!filter.level || matchesLevel(entry.level, filter.level)) && (!query || entry.text.toLowerCase().includes(query)));
52
+ }
53
+ clear() {
54
+ this.#entries = [];
55
+ this.emit("clear");
56
+ }
57
+ };
58
+ const LEVEL_ORDER = {
59
+ trace: -1,
60
+ debug: 0,
61
+ info: 1,
62
+ success: 1,
63
+ warn: 2,
64
+ error: 3
65
+ };
66
+ /**
67
+ * Whether `level` is at least as severe as `minimum`.
68
+ */
69
+ function matchesLevel(level, minimum) {
70
+ return LEVEL_ORDER[level] >= LEVEL_ORDER[minimum];
71
+ }
72
+ /**
73
+ * Whether an application stderr line only continues the preceding JavaScript error. Stack frames and the fields
74
+ * Node prints after an `Error` are useful log lines, but they must not each increment the panel's error counter.
75
+ */
76
+ function isErrorDetail(entry) {
77
+ if (entry.source !== "app" || entry.level !== "error") return false;
78
+ const text = stripVTControlCharacters(entry.text);
79
+ return /^\s+at\s/.test(text) || /^\s+(?:type|path|code|cause|errno|syscall|address|port):/.test(text) || /^\s*}\s*$/.test(text) || !text.trim();
80
+ }
81
+ /** stderr is a transport, not a severity: Node and many loggers also send warnings there. */
82
+ function classifyAppLine(text, fallback) {
83
+ const plain = stripVTControlCharacters(text);
84
+ if (/\b(?:Error|ERROR|FATAL)\b|\bERR_[A-Z_]+\b/.test(plain)) return "error";
85
+ if (/\b(?:Warning|WARN|WARNING|DeprecationWarning|ExperimentalWarning)\b/.test(plain) || /^\(node:\d+\).*warning/i.test(plain)) return "warn";
86
+ if (/^\s*(?:\(Use .*--trace-warnings|\[(?:info|debug)\]|INFO\b|DEBUG\b|[◇ℹ✔])/.test(plain)) return "info";
87
+ return fallback;
88
+ }
89
+
90
+ //#endregion
91
+ //#region src/dev/tui/log-view.ts
92
+ /** The levels a view filters by, in the order the dev UI lists them. */
93
+ const VIEW_LEVELS = [
94
+ "error",
95
+ "warn",
96
+ "info",
97
+ "debug",
98
+ "trace"
99
+ ];
100
+ /** `success` is an `info` that went well: it is painted differently, but filtered with it. */
101
+ function viewLevel(level) {
102
+ return level === "success" ? "info" : level;
103
+ }
104
+ function isLogLevel(value) {
105
+ return LOG_LEVELS.includes(value);
106
+ }
107
+ /** The filter a session starts with: `--channel`/`--level` first, then `dev.logs`, then everything but `trace`. */
108
+ function initialLogView(config, flags = {}) {
109
+ const flagged = flags.channels?.flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean) ?? [];
110
+ const channels = flagged.length > 0 ? flagged : config.dev.logs?.channels ?? null;
111
+ const levels = flags.level ? LOG_LEVELS.slice(LOG_LEVELS.indexOf(flags.level)) : config.dev.logs?.levels ?? DEFAULT_LOG_LEVELS;
112
+ return {
113
+ allow: channels === null ? null : new Set(channels),
114
+ hidden: /* @__PURE__ */ new Set(),
115
+ levels: new Set(levels),
116
+ query: ""
117
+ };
118
+ }
119
+ function isChannelVisible(filter, channel) {
120
+ return (filter.allow === null || filter.allow.has(channel)) && !filter.hidden.has(channel);
121
+ }
122
+ function matchesView(entry, filter) {
123
+ if (!isChannelVisible(filter, entry.channel) || !filter.levels.has(viewLevel(entry.level))) return false;
124
+ if (!filter.query) return true;
125
+ const query = filter.query.toLowerCase();
126
+ return [entry.text, ...entry.detail ?? []].some((line) => stripVTControlCharacters(line).toLowerCase().includes(query));
127
+ }
128
+ function toggleChannel(filter, channel) {
129
+ const allow = filter.allow === null ? null : new Set(filter.allow);
130
+ const hidden = new Set(filter.hidden);
131
+ if (isChannelVisible(filter, channel)) {
132
+ hidden.add(channel);
133
+ allow?.delete(channel);
134
+ } else {
135
+ hidden.delete(channel);
136
+ allow?.add(channel);
137
+ }
138
+ return {
139
+ ...filter,
140
+ allow,
141
+ hidden
142
+ };
143
+ }
144
+ /** Shows only `channel`; on the channel that is already alone, shows every channel again. */
145
+ function soloChannel(filter, channel) {
146
+ const alone = filter.allow?.size === 1 && filter.allow.has(channel) && filter.hidden.size === 0;
147
+ return {
148
+ ...filter,
149
+ allow: alone ? null : /* @__PURE__ */ new Set([channel]),
150
+ hidden: /* @__PURE__ */ new Set()
151
+ };
152
+ }
153
+ /** Never leaves the view without a level: switching the last one off is ignored. */
154
+ function toggleLevel(filter, level) {
155
+ const levels = new Set(filter.levels);
156
+ if (levels.has(level)) levels.delete(level);
157
+ else levels.add(level);
158
+ return levels.size === 0 ? filter : {
159
+ ...filter,
160
+ levels
161
+ };
162
+ }
163
+ /** Shows only `level`; on the level that is already alone, shows every level again. */
164
+ function soloLevel(filter, level) {
165
+ const alone = filter.levels.size === 1 && filter.levels.has(level);
166
+ return {
167
+ ...filter,
168
+ levels: new Set(alone ? VIEW_LEVELS : [level])
169
+ };
170
+ }
171
+ /**
172
+ * Lays entries out as terminal lines. An entry with detail lines is a block, set apart by a rule above and below; a
173
+ * stack frame the bot printed after an error is folded under that error instead of being a message of its own.
174
+ */
175
+ function buildRows(entries, options = {}) {
176
+ if (!options.group) return layout(entries);
177
+ const channels = /* @__PURE__ */ new Map();
178
+ for (const entry of entries) {
179
+ const list = channels.get(entry.channel);
180
+ if (list) list.push(entry);
181
+ else channels.set(entry.channel, [entry]);
182
+ }
183
+ return [...channels].flatMap(([channel, list]) => [{
184
+ kind: "header",
185
+ channel,
186
+ count: list.length
187
+ }, ...layout(list)]);
188
+ }
189
+ /**
190
+ * What a terminal line can show of a log line: no colour codes, and no control characters. A tab is the one that
191
+ * matters: the terminal expands it to up to eight columns the layout never counted, and the line wraps.
192
+ */
193
+ function printable(text) {
194
+ return stripVTControlCharacters(text).replaceAll(" ", " ").replace(CONTROL_CHARACTERS, "");
195
+ }
196
+ const CONTROL_CHARACTERS = /[\u0000-\u0008\u000B-\u001F\u007F]/g;
197
+ function layout(entries) {
198
+ const rows = [];
199
+ const rule = () => {
200
+ if (rows.length > 0 && rows.at(-1).kind !== "rule") rows.push({ kind: "rule" });
201
+ };
202
+ for (const entry of entries) {
203
+ const [first = "", ...rest] = stripVTControlCharacters(entry.text).split("\n").map(printable);
204
+ if (isErrorDetail(entry) && rows.at(-1) !== void 0 && rows.at(-1).kind !== "rule") {
205
+ rows.push({
206
+ kind: "detail",
207
+ entry,
208
+ text: first.trim()
209
+ });
210
+ continue;
211
+ }
212
+ const block = entry.level !== "error" && (entry.detail?.length ?? 0) > 0;
213
+ if (block) rule();
214
+ rows.push({
215
+ kind: "entry",
216
+ entry,
217
+ text: first
218
+ });
219
+ for (const line of [...rest, ...(entry.detail ?? []).map(printable)]) rows.push({
220
+ kind: "detail",
221
+ entry,
222
+ text: line
223
+ });
224
+ if (block) rows.push({ kind: "rule" });
225
+ }
226
+ if (rows.at(-1)?.kind === "rule") rows.pop();
227
+ return rows;
228
+ }
229
+ const entryId = (row) => row?.kind === "entry" || row?.kind === "detail" ? row.entry.id : null;
230
+ /** The pin for a view ending at `end` (exclusive), `null` when that is the end of the stream: the view is live. */
231
+ function pinAt(rows, end) {
232
+ if (end >= rows.length) return null;
233
+ for (let index = end - 1; index >= 0; index--) {
234
+ const id = entryId(rows[index]);
235
+ if (id === null) continue;
236
+ const first = rows.findIndex((row) => entryId(row) === id);
237
+ return {
238
+ id,
239
+ extra: end - 1 - first
240
+ };
241
+ }
242
+ return null;
243
+ }
244
+ /**
245
+ * One past the last row a pinned view shows. When the pinned entry is gone (dropped from the buffer, or filtered
246
+ * out) the view falls back to the oldest rows there are, which is where that entry was heading.
247
+ */
248
+ function pinnedEnd(rows, pin, height) {
249
+ if (pin === null) return rows.length;
250
+ const floor = Math.min(height, rows.length);
251
+ const first = rows.findIndex((row) => entryId(row) === pin.id);
252
+ return first < 0 ? floor : Math.min(rows.length, Math.max(floor, first + 1 + pin.extra));
253
+ }
254
+ /** The row of the most recent error among `rows`, whatever order they are listed in, `-1` without one. */
255
+ function newestErrorRow(rows) {
256
+ let newest = -1;
257
+ for (const [index, row] of rows.entries()) {
258
+ if (row.kind !== "entry" || row.entry.level !== "error") continue;
259
+ const current = rows[newest];
260
+ if (current?.kind !== "entry" || row.entry.id > current.entry.id) newest = index;
261
+ }
262
+ return newest;
263
+ }
264
+ /** Lays labels out as words on lines of `width` columns. Each line lists the indices of its labels. */
265
+ function wrapLabels(labels, width) {
266
+ const lines = [];
267
+ let used = 0;
268
+ for (const [index, label] of labels.entries()) {
269
+ if (lines.length === 0 || used > 0 && used + 1 + label.length > width) {
270
+ lines.push([]);
271
+ used = 0;
272
+ }
273
+ lines.at(-1).push(index);
274
+ used += (used > 0 ? 1 : 0) + label.length;
275
+ }
276
+ return lines;
277
+ }
278
+ /** The `[start, end)` of at most `max` lines out of `count` that keeps `focused` in sight. */
279
+ function windowAround(count, focused, max) {
280
+ if (count <= max) return [0, count];
281
+ const size = Math.max(1, max);
282
+ const start = Math.max(0, Math.min(count - size, focused - size + 1));
283
+ return [start, start + size];
284
+ }
285
+ const TOKEN = new RegExp([
286
+ /(?<url>https?:\/\/[^\s)]+)/,
287
+ /(?<uuid>\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b)/,
288
+ /(?<route>\b(?:slash|user|message|component|modal|autocomplete):[^\s,]+)/,
289
+ /(?<path>(?:\.{1,2}\/|\/)?(?:[\w@.-]+\/)+[\w@.-]+\.[a-z]{1,5}\b(?::\d+(?::\d+)?)?)/,
290
+ /(?<quoted>`[^`\n]+`|'[^'\n]+')/,
291
+ /(?<method>\b(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b)/,
292
+ /(?<duration>\b\d+(?:\.\d+)?(?:ms|s)\b)/,
293
+ /(?<number>\b\d+\b)/
294
+ ].map((pattern) => pattern.source).join("|"), "g");
295
+ /**
296
+ * Splits a log line into what is worth telling apart at a glance: URLs, file paths, names, numbers. On the `http`
297
+ * channel the status code carries its class (`ok`, `warn`, `error`) instead of being a plain number.
298
+ */
299
+ function highlight(text, channel) {
300
+ const segments = [];
301
+ let index = 0;
302
+ for (const match of text.matchAll(TOKEN)) {
303
+ const groups = match.groups;
304
+ if (match.index > index) segments.push({ text: text.slice(index, match.index) });
305
+ segments.push({
306
+ text: match[0],
307
+ token: tokenOf(groups, match[0], channel)
308
+ });
309
+ index = match.index + match[0].length;
310
+ }
311
+ if (index < text.length) segments.push({ text: text.slice(index) });
312
+ return segments;
313
+ }
314
+ function tokenOf(groups, text, channel) {
315
+ if (groups.url !== void 0) return "url";
316
+ if (groups.uuid !== void 0 || groups.path !== void 0) return groups.path !== void 0 ? "path" : "dim";
317
+ if (groups.route !== void 0 || groups.quoted !== void 0 || groups.method !== void 0) return "name";
318
+ if (groups.number !== void 0 && channel === "http" && text.length === 3) return text.startsWith("5") ? "error" : text.startsWith("4") ? "warn" : "ok";
319
+ return "number";
320
+ }
321
+ const BADGES = {
322
+ trace: "T",
323
+ debug: "D",
324
+ info: "I",
325
+ success: "I",
326
+ warn: "W",
327
+ error: "E"
328
+ };
329
+ /** The one-letter badge of a level, the way the reference dashboards print them. */
330
+ function levelBadge(level) {
331
+ return BADGES[level];
332
+ }
333
+ /** `22:07:01`, always 24-hour, whatever the locale. */
334
+ function formatClock(time) {
335
+ const date = new Date(time);
336
+ const pad = (value) => value.toString().padStart(2, "0");
337
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
338
+ }
339
+
340
+ //#endregion
341
+ export { isErrorDetail as S, windowAround as _, initialLogView as a, SOURCE_CHANNELS as b, levelBadge as c, pinAt as d, pinnedEnd as f, toggleLevel as g, toggleChannel as h, highlight as i, matchesView as l, soloLevel as m, buildRows as n, isChannelVisible as o, soloChannel as p, formatClock as r, isLogLevel as s, VIEW_LEVELS as t, newestErrorRow as u, wrapLabels as v, classifyAppLine as x, LogBuffer as y };
342
+ //# sourceMappingURL=log-view-B7uJEnMR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-view-B7uJEnMR.js","names":[],"sources":["../src/utils/log-buffer.ts","../src/dev/tui/log-view.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport { stripVTControlCharacters } from 'node:util';\n\nexport type LogSource = 'stars' | 'build' | 'app' | 'tsc' | 'tunnel';\n/** The builders' levels, plus `trace` for the per-request entries the bot reports. */\nexport type LogLevel = import('@wolfstar/schema').BuilderLogLevel | 'trace';\n\n/**\n * The channel an entry of each source lands on unless it names one: who wrote it. The bot's own events (`hmr`,\n * `commands`, `interactions`, `http`, `lifecycle`) and plugins pick their own.\n */\nexport const SOURCE_CHANNELS: Readonly<Record<LogSource, string>> = { stars: 'cli', build: 'build', app: 'bot', tsc: 'types', tunnel: 'tunnel' };\n\nexport interface LogEntry {\n\treadonly id: number;\n\treadonly time: number;\n\treadonly source: LogSource;\n\t/** What the entry is about, for filtering. Defaults to {@link SOURCE_CHANNELS} of the source. */\n\treadonly channel: string;\n\treadonly level: LogLevel;\n\treadonly text: string;\n\t/** Lines that belong to the entry (a list of loaded commands, the hint of an error), shown under it. */\n\treadonly detail?: readonly string[];\n}\n\nexport interface LogFilter {\n\tsource?: LogSource | null;\n\tlevel?: LogLevel | null;\n\tquery?: string | null;\n}\n\nexport type LogInput = Omit<LogEntry, 'id' | 'time' | 'channel'> & { readonly channel?: string };\n\n/**\n * A bounded, in-memory log store shared by the dev service and its renderers.\n */\nexport class LogBuffer extends EventEmitter<{ entry: [LogEntry]; clear: [] }> {\n\t#entries: LogEntry[] = [];\n\t#channels = new Set<string>();\n\t#nextId = 1;\n\n\tpublic constructor(public readonly capacity = 2000) {\n\t\tsuper();\n\t}\n\n\tpublic push(input: LogInput): LogEntry {\n\t\tconst entry: LogEntry = { id: this.#nextId++, time: Date.now(), ...input, channel: input.channel ?? SOURCE_CHANNELS[input.source] };\n\t\tthis.#channels.add(entry.channel);\n\t\tthis.#entries.push(entry);\n\t\tif (this.#entries.length > this.capacity) this.#entries.splice(0, this.#entries.length - this.capacity);\n\t\tthis.emit('entry', entry);\n\t\treturn entry;\n\t}\n\n\tpublic entries(): readonly LogEntry[] {\n\t\treturn this.#entries;\n\t}\n\n\t/** Every channel an entry was logged on since the session started, sorted. Clearing the logs keeps them. */\n\tpublic channels(): string[] {\n\t\treturn [...this.#channels].sort();\n\t}\n\n\tpublic filter(filter: LogFilter): LogEntry[] {\n\t\tconst query = filter.query?.toLowerCase() ?? null;\n\t\treturn this.#entries.filter(\n\t\t\t(entry) =>\n\t\t\t\t(!filter.source || entry.source === filter.source) &&\n\t\t\t\t(!filter.level || matchesLevel(entry.level, filter.level)) &&\n\t\t\t\t(!query || entry.text.toLowerCase().includes(query))\n\t\t);\n\t}\n\n\tpublic clear(): void {\n\t\tthis.#entries = [];\n\t\tthis.emit('clear');\n\t}\n}\n\nconst LEVEL_ORDER: Record<LogLevel, number> = { trace: -1, debug: 0, info: 1, success: 1, warn: 2, error: 3 };\n\n/**\n * Whether `level` is at least as severe as `minimum`.\n */\nexport function matchesLevel(level: LogLevel, minimum: LogLevel): boolean {\n\treturn LEVEL_ORDER[level] >= LEVEL_ORDER[minimum];\n}\n\n/**\n * Whether an application stderr line only continues the preceding JavaScript error. Stack frames and the fields\n * Node prints after an `Error` are useful log lines, but they must not each increment the panel's error counter.\n */\nexport function isErrorDetail(entry: Pick<LogEntry, 'source' | 'level' | 'text'>): boolean {\n\tif (entry.source !== 'app' || entry.level !== 'error') return false;\n\tconst text = stripVTControlCharacters(entry.text);\n\treturn /^\\s+at\\s/.test(text) || /^\\s+(?:type|path|code|cause|errno|syscall|address|port):/.test(text) || /^\\s*}\\s*$/.test(text) || !text.trim();\n}\n\n/** stderr is a transport, not a severity: Node and many loggers also send warnings there. */\nexport function classifyAppLine(text: string, fallback: LogLevel): LogLevel {\n\tconst plain = stripVTControlCharacters(text);\n\tif (/\\b(?:Error|ERROR|FATAL)\\b|\\bERR_[A-Z_]+\\b/.test(plain)) return 'error';\n\tif (/\\b(?:Warning|WARN|WARNING|DeprecationWarning|ExperimentalWarning)\\b/.test(plain) || /^\\(node:\\d+\\).*warning/i.test(plain)) return 'warn';\n\tif (/^\\s*(?:\\(Use .*--trace-warnings|\\[(?:info|debug)\\]|INFO\\b|DEBUG\\b|[◇ℹ✔])/.test(plain)) return 'info';\n\treturn fallback;\n}\n","import { DEFAULT_LOG_LEVELS, LOG_LEVELS, type ResolvedStarsConfig, type StarsLogLevel } from '@wolfstar/schema';\nimport { stripVTControlCharacters } from 'node:util';\nimport { isErrorDetail, type LogEntry, type LogLevel } from '../../utils/log-buffer.js';\n\n/** The levels a view filters by, in the order the dev UI lists them. */\nexport const VIEW_LEVELS = ['error', 'warn', 'info', 'debug', 'trace'] as const satisfies readonly StarsLogLevel[];\n\n/** `success` is an `info` that went well: it is painted differently, but filtered with it. */\nexport function viewLevel(level: LogLevel): StarsLogLevel {\n\treturn level === 'success' ? 'info' : level;\n}\n\nexport function isLogLevel(value: string): value is StarsLogLevel {\n\treturn (LOG_LEVELS as readonly string[]).includes(value);\n}\n\n/**\n * Which entries a renderer shows. A channel is visible when `allow` lists it (or is `null`, for every channel) and\n * `hidden` does not: `allow` is what a preset or a solo narrows the view to, `hidden` what was switched off one by\n * one, so a channel that first logs later follows the preset instead of popping up.\n */\nexport interface LogViewFilter {\n\treadonly allow: ReadonlySet<string> | null;\n\treadonly hidden: ReadonlySet<string>;\n\treadonly levels: ReadonlySet<StarsLogLevel>;\n\treadonly query: string;\n}\n\nexport interface LogViewFlags {\n\t/** `--channel`, each value possibly a comma-separated list. */\n\tchannels?: readonly string[];\n\t/** `--level`: this level and every more severe one. */\n\tlevel?: StarsLogLevel;\n}\n\n/** The filter a session starts with: `--channel`/`--level` first, then `dev.logs`, then everything but `trace`. */\nexport function initialLogView(config: Pick<ResolvedStarsConfig, 'dev'>, flags: LogViewFlags = {}): LogViewFilter {\n\tconst flagged =\n\t\tflags.channels\n\t\t\t?.flatMap((value) => value.split(','))\n\t\t\t.map((value) => value.trim())\n\t\t\t.filter(Boolean) ?? [];\n\tconst channels = flagged.length > 0 ? flagged : (config.dev.logs?.channels ?? null);\n\tconst levels = flags.level ? LOG_LEVELS.slice(LOG_LEVELS.indexOf(flags.level)) : (config.dev.logs?.levels ?? DEFAULT_LOG_LEVELS);\n\treturn { allow: channels === null ? null : new Set(channels), hidden: new Set(), levels: new Set(levels), query: '' };\n}\n\nexport function isChannelVisible(filter: Pick<LogViewFilter, 'allow' | 'hidden'>, channel: string): boolean {\n\treturn (filter.allow === null || filter.allow.has(channel)) && !filter.hidden.has(channel);\n}\n\nexport function matchesView(entry: LogEntry, filter: LogViewFilter): boolean {\n\tif (!isChannelVisible(filter, entry.channel) || !filter.levels.has(viewLevel(entry.level))) return false;\n\tif (!filter.query) return true;\n\tconst query = filter.query.toLowerCase();\n\treturn [entry.text, ...(entry.detail ?? [])].some((line) => stripVTControlCharacters(line).toLowerCase().includes(query));\n}\n\nexport function toggleChannel(filter: LogViewFilter, channel: string): LogViewFilter {\n\tconst allow = filter.allow === null ? null : new Set(filter.allow);\n\tconst hidden = new Set(filter.hidden);\n\tif (isChannelVisible(filter, channel)) {\n\t\thidden.add(channel);\n\t\tallow?.delete(channel);\n\t} else {\n\t\thidden.delete(channel);\n\t\tallow?.add(channel);\n\t}\n\n\treturn { ...filter, allow, hidden };\n}\n\n/** Shows only `channel`; on the channel that is already alone, shows every channel again. */\nexport function soloChannel(filter: LogViewFilter, channel: string): LogViewFilter {\n\tconst alone = filter.allow?.size === 1 && filter.allow.has(channel) && filter.hidden.size === 0;\n\treturn { ...filter, allow: alone ? null : new Set([channel]), hidden: new Set() };\n}\n\n/** Never leaves the view without a level: switching the last one off is ignored. */\nexport function toggleLevel(filter: LogViewFilter, level: StarsLogLevel): LogViewFilter {\n\tconst levels = new Set(filter.levels);\n\tif (levels.has(level)) levels.delete(level);\n\telse levels.add(level);\n\treturn levels.size === 0 ? filter : { ...filter, levels };\n}\n\n/** Shows only `level`; on the level that is already alone, shows every level again. */\nexport function soloLevel(filter: LogViewFilter, level: StarsLogLevel): LogViewFilter {\n\tconst alone = filter.levels.size === 1 && filter.levels.has(level);\n\treturn { ...filter, levels: new Set(alone ? VIEW_LEVELS : [level]) };\n}\n\n/** One terminal line of the log pane. */\nexport type LogRow =\n\t| { readonly kind: 'entry'; readonly entry: LogEntry; readonly text: string }\n\t/** A line that belongs to the entry above it: its detail, the rest of a multi-line message, a stack frame. */\n\t| { readonly kind: 'detail'; readonly entry: LogEntry; readonly text: string }\n\t| { readonly kind: 'rule' }\n\t| { readonly kind: 'header'; readonly channel: string; readonly count: number };\n\nexport interface BuildRowsOptions {\n\t/** Lists the entries channel by channel, in the order the channels first logged, instead of by time. */\n\tgroup?: boolean;\n}\n\n/**\n * Lays entries out as terminal lines. An entry with detail lines is a block, set apart by a rule above and below; a\n * stack frame the bot printed after an error is folded under that error instead of being a message of its own.\n */\nexport function buildRows(entries: readonly LogEntry[], options: BuildRowsOptions = {}): LogRow[] {\n\tif (!options.group) return layout(entries);\n\n\tconst channels = new Map<string, LogEntry[]>();\n\tfor (const entry of entries) {\n\t\tconst list = channels.get(entry.channel);\n\t\tif (list) list.push(entry);\n\t\telse channels.set(entry.channel, [entry]);\n\t}\n\n\treturn [...channels].flatMap(([channel, list]) => [{ kind: 'header', channel, count: list.length } as const, ...layout(list)]);\n}\n\n/**\n * What a terminal line can show of a log line: no colour codes, and no control characters. A tab is the one that\n * matters: the terminal expands it to up to eight columns the layout never counted, and the line wraps.\n */\nfunction printable(text: string): string {\n\treturn stripVTControlCharacters(text).replaceAll('\\t', ' ').replace(CONTROL_CHARACTERS, '');\n}\n\n// oxlint-disable-next-line no-control-regex\nconst CONTROL_CHARACTERS = /[\\u0000-\\u0008\\u000B-\\u001F\\u007F]/g;\n\nfunction layout(entries: readonly LogEntry[]): LogRow[] {\n\tconst rows: LogRow[] = [];\n\tconst rule = () => {\n\t\tif (rows.length > 0 && rows.at(-1)!.kind !== 'rule') rows.push({ kind: 'rule' });\n\t};\n\n\tfor (const entry of entries) {\n\t\tconst [first = '', ...rest] = stripVTControlCharacters(entry.text).split('\\n').map(printable);\n\t\tif (isErrorDetail(entry) && rows.at(-1) !== undefined && rows.at(-1)!.kind !== 'rule') {\n\t\t\trows.push({ kind: 'detail', entry, text: first.trim() });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst block = entry.level !== 'error' && (entry.detail?.length ?? 0) > 0;\n\t\tif (block) rule();\n\t\trows.push({ kind: 'entry', entry, text: first });\n\t\tfor (const line of [...rest, ...(entry.detail ?? []).map(printable)]) rows.push({ kind: 'detail', entry, text: line });\n\t\tif (block) rows.push({ kind: 'rule' });\n\t}\n\n\tif (rows.at(-1)?.kind === 'rule') rows.pop();\n\treturn rows;\n}\n\n/**\n * Where a scrolled-back view stops: the entry of its last line, and how many lines past the first line of that\n * entry (its own detail lines, then a rule). An index into the rows would drift as soon as the buffer drops its\n * oldest entries or a filter changes.\n */\nexport interface LogPin {\n\treadonly id: number;\n\treadonly extra: number;\n}\n\nconst entryId = (row: LogRow | undefined): number | null => (row?.kind === 'entry' || row?.kind === 'detail' ? row.entry.id : null);\n\n/** The pin for a view ending at `end` (exclusive), `null` when that is the end of the stream: the view is live. */\nexport function pinAt(rows: readonly LogRow[], end: number): LogPin | null {\n\tif (end >= rows.length) return null;\n\tfor (let index = end - 1; index >= 0; index--) {\n\t\tconst id = entryId(rows[index]);\n\t\tif (id === null) continue;\n\t\t// Counted from the first line of the entry: a view may stop in the middle of a block.\n\t\tconst first = rows.findIndex((row) => entryId(row) === id);\n\t\treturn { id, extra: end - 1 - first };\n\t}\n\n\treturn null;\n}\n\n/**\n * One past the last row a pinned view shows. When the pinned entry is gone (dropped from the buffer, or filtered\n * out) the view falls back to the oldest rows there are, which is where that entry was heading.\n */\nexport function pinnedEnd(rows: readonly LogRow[], pin: LogPin | null, height: number): number {\n\tif (pin === null) return rows.length;\n\tconst floor = Math.min(height, rows.length);\n\tconst first = rows.findIndex((row) => entryId(row) === pin.id);\n\treturn first < 0 ? floor : Math.min(rows.length, Math.max(floor, first + 1 + pin.extra));\n}\n\n/** The row of the most recent error among `rows`, whatever order they are listed in, `-1` without one. */\nexport function newestErrorRow(rows: readonly LogRow[]): number {\n\tlet newest = -1;\n\tfor (const [index, row] of rows.entries()) {\n\t\tif (row.kind !== 'entry' || row.entry.level !== 'error') continue;\n\t\tconst current = rows[newest];\n\t\tif (current?.kind !== 'entry' || row.entry.id > current.entry.id) newest = index;\n\t}\n\n\treturn newest;\n}\n\n/** Lays labels out as words on lines of `width` columns. Each line lists the indices of its labels. */\nexport function wrapLabels(labels: readonly string[], width: number): number[][] {\n\tconst lines: number[][] = [];\n\tlet used = 0;\n\tfor (const [index, label] of labels.entries()) {\n\t\tif (lines.length === 0 || (used > 0 && used + 1 + label.length > width)) {\n\t\t\tlines.push([]);\n\t\t\tused = 0;\n\t\t}\n\n\t\tlines.at(-1)!.push(index);\n\t\tused += (used > 0 ? 1 : 0) + label.length;\n\t}\n\n\treturn lines;\n}\n\n/** The `[start, end)` of at most `max` lines out of `count` that keeps `focused` in sight. */\nexport function windowAround(count: number, focused: number, max: number): [start: number, end: number] {\n\tif (count <= max) return [0, count];\n\tconst size = Math.max(1, max);\n\tconst start = Math.max(0, Math.min(count - size, focused - size + 1));\n\treturn [start, start + size];\n}\n\nexport type TokenKind = 'url' | 'path' | 'number' | 'name' | 'dim' | 'ok' | 'warn' | 'error';\n\nexport interface Segment {\n\treadonly text: string;\n\treadonly token?: TokenKind;\n}\n\nconst TOKEN = new RegExp(\n\t[\n\t\t/(?<url>https?:\\/\\/[^\\s)]+)/,\n\t\t/(?<uuid>\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b)/,\n\t\t/(?<route>\\b(?:slash|user|message|component|modal|autocomplete):[^\\s,]+)/,\n\t\t/(?<path>(?:\\.{1,2}\\/|\\/)?(?:[\\w@.-]+\\/)+[\\w@.-]+\\.[a-z]{1,5}\\b(?::\\d+(?::\\d+)?)?)/,\n\t\t/(?<quoted>`[^`\\n]+`|'[^'\\n]+')/,\n\t\t/(?<method>\\b(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b)/,\n\t\t/(?<duration>\\b\\d+(?:\\.\\d+)?(?:ms|s)\\b)/,\n\t\t/(?<number>\\b\\d+\\b)/\n\t]\n\t\t.map((pattern) => pattern.source)\n\t\t.join('|'),\n\t'g'\n);\n\n/**\n * Splits a log line into what is worth telling apart at a glance: URLs, file paths, names, numbers. On the `http`\n * channel the status code carries its class (`ok`, `warn`, `error`) instead of being a plain number.\n */\nexport function highlight(text: string, channel?: string): Segment[] {\n\tconst segments: Segment[] = [];\n\tlet index = 0;\n\tfor (const match of text.matchAll(TOKEN)) {\n\t\tconst groups = match.groups!;\n\t\tif (match.index > index) segments.push({ text: text.slice(index, match.index) });\n\t\tsegments.push({ text: match[0], token: tokenOf(groups, match[0], channel) });\n\t\tindex = match.index + match[0].length;\n\t}\n\n\tif (index < text.length) segments.push({ text: text.slice(index) });\n\treturn segments;\n}\n\nfunction tokenOf(groups: Record<string, string | undefined>, text: string, channel: string | undefined): TokenKind {\n\tif (groups.url !== undefined) return 'url';\n\tif (groups.uuid !== undefined || groups.path !== undefined) return groups.path !== undefined ? 'path' : 'dim';\n\tif (groups.route !== undefined || groups.quoted !== undefined || groups.method !== undefined) return 'name';\n\tif (groups.number !== undefined && channel === 'http' && text.length === 3) {\n\t\treturn text.startsWith('5') ? 'error' : text.startsWith('4') ? 'warn' : 'ok';\n\t}\n\n\treturn 'number';\n}\n\nconst BADGES: Record<LogLevel, string> = { trace: 'T', debug: 'D', info: 'I', success: 'I', warn: 'W', error: 'E' };\n\n/** The one-letter badge of a level, the way the reference dashboards print them. */\nexport function levelBadge(level: LogLevel): string {\n\treturn BADGES[level];\n}\n\n/** `22:07:01`, always 24-hour, whatever the locale. */\nexport function formatClock(time: number): string {\n\tconst date = new Date(time);\n\tconst pad = (value: number) => value.toString().padStart(2, '0');\n\treturn `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as pluginRegistrations } from "./plugin-registrations-Dr_BicfC.js";
2
- import { n as importFromProject } from "./project-MD4dIo2X.js";
2
+ import { n as importFromProject } from "./project-zlQStwsf.js";
3
3
  import { NitroBuilder as NitroBuilder$1 } from "@wolfstar/nitro-server";
4
4
 
5
5
  //#region src/builders/nitro.ts
@@ -15,4 +15,4 @@ var NitroBuilder = class extends NitroBuilder$1 {
15
15
 
16
16
  //#endregion
17
17
  export { NitroBuilder };
18
- //# sourceMappingURL=nitro-sP2F3SQu.js.map
18
+ //# sourceMappingURL=nitro-B8u1iVgf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nitro-sP2F3SQu.js","names":["ServerBuilder"],"sources":["../src/builders/nitro.ts"],"sourcesContent":["import { NitroBuilder as ServerBuilder } from '@wolfstar/nitro-server';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { pluginRegistrations } from '../utils/plugin-registrations.js';\nimport { importFromProject } from '../utils/project.js';\n\n/** Connect the server integration to the CLI's diagnostics and plugin discovery. */\nexport class NitroBuilder extends ServerBuilder {\n\tpublic constructor(config: ResolvedStarsConfig) {\n\t\tsuper(config, { importFromProject, pluginRegistrations });\n\t}\n}\n"],"mappings":";;;;;;AAMA,IAAa,eAAb,cAAkCA,eAAc;CAC/C,AAAO,YAAY,QAA6B;EAC/C,MAAM,QAAQ;GAAE;GAAmB;EAAoB,CAAC;CACzD;AACD"}
1
+ {"version":3,"file":"nitro-B8u1iVgf.js","names":["ServerBuilder"],"sources":["../src/builders/nitro.ts"],"sourcesContent":["import { NitroBuilder as ServerBuilder } from '@wolfstar/nitro-server';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { pluginRegistrations } from '../utils/plugin-registrations.js';\nimport { importFromProject } from '../utils/project.js';\n\n/** Connect the server integration to the CLI's diagnostics and plugin discovery. */\nexport class NitroBuilder extends ServerBuilder {\n\tpublic constructor(config: ResolvedStarsConfig) {\n\t\tsuper(config, { importFromProject, pluginRegistrations });\n\t}\n}\n"],"mappings":";;;;;;AAMA,IAAa,eAAb,cAAkCA,eAAc;CAC/C,AAAO,YAAY,QAA6B;EAC/C,MAAM,QAAQ;GAAE;GAAmB;EAAoB,CAAC;CACzD;AACD"}
@@ -1,3 +1,4 @@
1
+ import { a as initialLogView, b as SOURCE_CHANNELS, l as matchesView } from "./log-view-B7uJEnMR.js";
1
2
  import { createColors } from "colorette";
2
3
 
3
4
  //#region src/dev/tui/plain.ts
@@ -8,6 +9,7 @@ function createPlainRenderer(service, options = {}) {
8
9
  const stdout = options.stdout ?? process.stdout;
9
10
  const colors = createColors({ useColor: options.color ?? false });
10
11
  const write = (text) => stdout.write(`${text}\n`);
12
+ const filter = options.filter ?? initialLogView(service.config);
11
13
  const prefixes = {
12
14
  stars: colors.cyan("stars"),
13
15
  build: colors.magenta("build"),
@@ -16,13 +18,16 @@ function createPlainRenderer(service, options = {}) {
16
18
  app: null
17
19
  };
18
20
  const onEntry = (entry) => {
19
- const prefix = prefixes[entry.source];
21
+ if (!matchesView(entry, filter)) return;
22
+ const prefix = entry.channel === SOURCE_CHANNELS[entry.source] ? prefixes[entry.source] : colors.cyan(entry.channel);
20
23
  if (!prefix) {
21
24
  write(entry.text);
25
+ for (const line of entry.detail ?? []) write(` ${line}`);
22
26
  return;
23
27
  }
24
28
  const paint = entry.level === "error" ? colors.red : entry.level === "warn" ? colors.yellow : entry.level === "success" ? colors.green : (value) => value;
25
29
  write(`${prefix} ${paint(entry.text)}`);
30
+ for (const line of entry.detail ?? []) write(`${prefix} ${colors.dim(line)}`);
26
31
  };
27
32
  const onClear = () => write(`${prefixes.stars} logs cleared`);
28
33
  return {
@@ -40,4 +45,4 @@ function createPlainRenderer(service, options = {}) {
40
45
 
41
46
  //#endregion
42
47
  export { createPlainRenderer };
43
- //# sourceMappingURL=plain-B6z85uQP.js.map
48
+ //# sourceMappingURL=plain-DG7cy0Kk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plain-DG7cy0Kk.js","names":[],"sources":["../src/dev/tui/plain.ts"],"sourcesContent":["import { createColors } from 'colorette';\nimport type { DevService } from '../dev-service.js';\nimport { SOURCE_CHANNELS, type LogEntry } from '../../utils/log-buffer.js';\nimport { initialLogView, matchesView, type LogViewFilter } from './log-view.js';\n\nexport interface PlainRendererOptions {\n\tstdout?: NodeJS.WritableStream;\n\tcolor?: boolean;\n\t/** Whether to attach process signal handlers. */\n\tsignals?: boolean;\n\t/** Which channels and levels are printed; defaults to `dev.logs`. The log file is never filtered. */\n\tfilter?: LogViewFilter;\n}\n\nexport interface Renderer {\n\t/** Starts rendering. Resolves when the user asks to quit (or never, in plain mode without signals). */\n\tstart(): Promise<void>;\n\t/** Stops rendering and restores the terminal. */\n\tstop(): void;\n}\n\n/**\n * Line-oriented renderer for non-interactive terminals, CI and redirected output.\n */\nexport function createPlainRenderer(service: DevService, options: PlainRendererOptions = {}): Renderer {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: options.color ?? false });\n\tconst write = (text: string) => stdout.write(`${text}\\n`);\n\tconst filter = options.filter ?? initialLogView(service.config);\n\n\tconst prefixes = {\n\t\tstars: colors.cyan('stars'),\n\t\tbuild: colors.magenta('build'),\n\t\ttsc: colors.blue('tsc'),\n\t\ttunnel: colors.yellow('tunnel'),\n\t\tapp: null\n\t} as const;\n\n\tconst onEntry = (entry: LogEntry) => {\n\t\tif (!matchesView(entry, filter)) return;\n\t\t// An entry on a channel of its own (`hmr`, `commands`, `http`, …) is prefixed with it; the bot's own output is\n\t\t// passed through as it is, so its logger's formatting survives.\n\t\tconst prefix = entry.channel === SOURCE_CHANNELS[entry.source] ? prefixes[entry.source] : colors.cyan(entry.channel);\n\t\tif (!prefix) {\n\t\t\twrite(entry.text);\n\t\t\tfor (const line of entry.detail ?? []) write(` ${line}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst paint =\n\t\t\tentry.level === 'error'\n\t\t\t\t? colors.red\n\t\t\t\t: entry.level === 'warn'\n\t\t\t\t\t? colors.yellow\n\t\t\t\t\t: entry.level === 'success'\n\t\t\t\t\t\t? colors.green\n\t\t\t\t\t\t: (value: string) => value;\n\t\twrite(`${prefix} ${paint(entry.text)}`);\n\t\tfor (const line of entry.detail ?? []) write(`${prefix} ${colors.dim(line)}`);\n\t};\n\n\tconst onClear = () => write(`${prefixes.stars} logs cleared`);\n\n\treturn {\n\t\tstart() {\n\t\t\tservice.logs.on('entry', onEntry);\n\t\t\tservice.logs.on('clear', onClear);\n\t\t\treturn new Promise<void>(() => {});\n\t\t},\n\t\tstop() {\n\t\t\tservice.logs.off('entry', onEntry);\n\t\t\tservice.logs.off('clear', onClear);\n\t\t}\n\t};\n}\n"],"mappings":";;;;;;;AAwBA,SAAgB,oBAAoB,SAAqB,UAAgC,CAAC,GAAa;CACtG,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,QAAQ,SAAS,MAAM,CAAC;CAChE,MAAM,SAAS,SAAiB,OAAO,MAAM,GAAG,KAAK,GAAG;CACxD,MAAM,SAAS,QAAQ,UAAU,eAAe,QAAQ,MAAM;CAE9D,MAAM,WAAW;EAChB,OAAO,OAAO,KAAK,OAAO;EAC1B,OAAO,OAAO,QAAQ,OAAO;EAC7B,KAAK,OAAO,KAAK,KAAK;EACtB,QAAQ,OAAO,OAAO,QAAQ;EAC9B,KAAK;CACN;CAEA,MAAM,WAAW,UAAoB;EACpC,IAAI,CAAC,YAAY,OAAO,MAAM,GAAG;EAGjC,MAAM,SAAS,MAAM,YAAY,gBAAgB,MAAM,UAAU,SAAS,MAAM,UAAU,OAAO,KAAK,MAAM,OAAO;EACnH,IAAI,CAAC,QAAQ;GACZ,MAAM,MAAM,IAAI;GAChB,KAAK,MAAM,QAAQ,MAAM,UAAU,CAAC,GAAG,MAAM,KAAK,MAAM;GACxD;EACD;EAEA,MAAM,QACL,MAAM,UAAU,UACb,OAAO,MACP,MAAM,UAAU,SACf,OAAO,SACP,MAAM,UAAU,YACf,OAAO,SACN,UAAkB;EACzB,MAAM,GAAG,OAAO,GAAG,MAAM,MAAM,IAAI,GAAG;EACtC,KAAK,MAAM,QAAQ,MAAM,UAAU,CAAC,GAAG,MAAM,GAAG,OAAO,KAAK,OAAO,IAAI,IAAI,GAAG;CAC/E;CAEA,MAAM,gBAAgB,MAAM,GAAG,SAAS,MAAM,cAAc;CAE5D,OAAO;EACN,QAAQ;GACP,QAAQ,KAAK,GAAG,SAAS,OAAO;GAChC,QAAQ,KAAK,GAAG,SAAS,OAAO;GAChC,OAAO,IAAI,cAAoB,CAAC,CAAC;EAClC;EACA,OAAO;GACN,QAAQ,KAAK,IAAI,SAAS,OAAO;GACjC,QAAQ,KAAK,IAAI,SAAS,OAAO;EAClC;CACD;AACD"}
@@ -1,7 +1,7 @@
1
1
  import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
3
- import { a as projectArgs, n as loadProject, o as resolveCwd } from "./hooks-H9kjLCMk.js";
4
- import { n as reportWarnings, t as prepareProject } from "./_shared-B-hRZDRS.js";
2
+ import { t as cliDiagnostics } from "./diagnostics-BysbNnPD.js";
3
+ import { d as resolveCwd, n as loadProject, u as projectArgs } from "./hooks-Cy6F2bhH.js";
4
+ import { n as reportWarnings, t as prepareProject } from "./_shared-BIQK0Bhm.js";
5
5
  import { defineCommand } from "citty";
6
6
  import { displayPath } from "@wolfstar/schema";
7
7
  import { createColors } from "colorette";
@@ -25,12 +25,16 @@ async function runPrepare(options) {
25
25
  else {
26
26
  const paintConfig = result.tsconfig.status === "outdated" ? colors.red : colors.green;
27
27
  stdout.write(`${colors.dim("stars")} tsconfig: ${paintConfig(result.tsconfig.status)} ${displayPath(config.root, result.tsconfig.path)}\n`);
28
+ if (result.modules) {
29
+ const paint = result.modules.status === "outdated" ? colors.red : colors.green;
30
+ stdout.write(`${colors.dim("stars")} modules: ${paint(result.modules.status)} ${displayPath(config.root, result.modules.path)}\n`);
31
+ }
28
32
  if (result.enabled) {
29
33
  const paint = result.status === "outdated" ? colors.red : colors.green;
30
34
  stdout.write(`${colors.dim("stars")} imports: ${paint(result.status)} ${displayPath(config.root, result.dts)}\n`);
31
35
  }
32
36
  }
33
- if (result.status === "outdated" || result.tsconfig.status === "outdated") throw cliDiagnostics.PREPARE_OUTDATED({});
37
+ if (result.status === "outdated" || result.tsconfig.status === "outdated" || result.modules?.status === "outdated") throw cliDiagnostics.PREPARE_OUTDATED({});
34
38
  }
35
39
  var prepare_default = defineCommand({
36
40
  meta: {
@@ -62,4 +66,4 @@ var prepare_default = defineCommand({
62
66
 
63
67
  //#endregion
64
68
  export { prepare_default as default };
65
- //# sourceMappingURL=prepare-B4ysyG6H.js.map
69
+ //# sourceMappingURL=prepare-BM93i3Rm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-BM93i3Rm.js","names":[],"sources":["../src/commands/prepare.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { loadProject } from '../utils/hooks.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport { prepareProject } from './_shared.js';\n\nexport interface PrepareTaskOptions extends ProjectArgs {\n\tcheck?: boolean;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\n/**\n * Generates `.stars/tsconfig.json` and `imports.dts` (see {@link StarsImportsConfig} in `@wolfstar/schema`), the way `nuxt\n * prepare` regenerates `.nuxt/imports.d.ts`. Run automatically by `stars dev` and `stars build` before the first\n * build; `--check` fails instead of writing, for CI.\n */\nexport async function runPrepare(options: PrepareTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { config, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(config, (text) => process.stderr.write(`${text}\\n`));\n\tconst result = await prepareProject(config, hooks, Boolean(options.check));\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n\t} else {\n\t\tconst paintConfig = result.tsconfig.status === 'outdated' ? colors.red : colors.green;\n\t\tstdout.write(`${colors.dim('stars')} tsconfig: ${paintConfig(result.tsconfig.status)} ${displayPath(config.root, result.tsconfig.path)}\\n`);\n\t\tif (result.modules) {\n\t\t\tconst paint = result.modules.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} modules: ${paint(result.modules.status)} ${displayPath(config.root, result.modules.path)}\\n`);\n\t\t}\n\t\tif (result.enabled) {\n\t\t\tconst paint = result.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} imports: ${paint(result.status)} ${displayPath(config.root, result.dts)}\\n`);\n\t\t}\n\t}\n\n\tif (result.status === 'outdated' || result.tsconfig.status === 'outdated' || result.modules?.status === 'outdated') {\n\t\tthrow cliDiagnostics.PREPARE_OUTDATED({});\n\t}\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'prepare',\n\t\tdescription: 'Generate TypeScript configuration and auto imports declarations'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tcheck: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Fail when the generated files are out of date instead of writing it',\n\t\t\tdefault: false\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runPrepare({ config: args.config, cwd: args.cwd, check: args.check, json: args.json });\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;AAsBA,eAAsB,WAAW,SAA4C;CAC5E,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,KAAK,CAAC,QAAQ,KAAK,CAAC;CAC3E,MAAM,EAAE,QAAQ,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CACpG,MAAM,eAAe,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,CAAC;CACxE,MAAM,SAAS,MAAM,eAAe,QAAQ,OAAO,QAAQ,QAAQ,KAAK,CAAC;CAEzE,IAAI,QAAQ,MACX,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,GAAG;MAC7C;EACN,MAAM,cAAc,OAAO,SAAS,WAAW,aAAa,OAAO,MAAM,OAAO;EAChF,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,aAAa,YAAY,OAAO,SAAS,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,SAAS,IAAI,EAAE,GAAG;EAC1I,IAAI,OAAO,SAAS;GACnB,MAAM,QAAQ,OAAO,QAAQ,WAAW,aAAa,OAAO,MAAM,OAAO;GACzE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,YAAY,MAAM,OAAO,QAAQ,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,QAAQ,IAAI,EAAE,GAAG;EAClI;EACA,IAAI,OAAO,SAAS;GACnB,MAAM,QAAQ,OAAO,WAAW,aAAa,OAAO,MAAM,OAAO;GACjE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,YAAY,MAAM,OAAO,MAAM,EAAE,GAAG,YAAY,OAAO,MAAM,OAAO,GAAG,EAAE,GAAG;EACjH;CACD;CAEA,IAAI,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW,cAAc,OAAO,SAAS,WAAW,YACvG,MAAM,eAAe,iBAAiB,CAAC,CAAC;AAE1C;AAEA,sBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM;EACL,GAAG;EACH,OAAO;GACN,MAAM;GACN,aAAa;GACb,SAAS;EACV;EACA,MAAM;GACL,MAAM;GACN,aAAa;GACb,SAAS;EACV;CACD;CACA,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,WAAW;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;GAAK,OAAO,KAAK;GAAO,MAAM,KAAK;EAAK,CAAC;CAC5F;AACD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { t as cliDiagnostics } from "./diagnostics-CZBVxlpj.js";
1
+ import { t as cliDiagnostics } from "./diagnostics-BysbNnPD.js";
2
2
  import { createRequire } from "node:module";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
@@ -64,4 +64,4 @@ function findInstalledVersion(root, name) {
64
64
 
65
65
  //#endregion
66
66
  export { resolveFromProject as i, importFromProject as n, resolveBinary as r, findInstalledVersion as t };
67
- //# sourceMappingURL=project-MD4dIo2X.js.map
67
+ //# sourceMappingURL=project-zlQStwsf.js.map