@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
@@ -0,0 +1,236 @@
1
+ import { i as readProjectEnv } from "./hooks-D_RVS0ba.js";
2
+ import { EventEmitter } from "node:events";
3
+ import { startTunnel } from "untun";
4
+
5
+ //#region src/dev/tunnel.ts
6
+ const SIGNALS = [
7
+ "SIGINT",
8
+ "SIGTERM",
9
+ "SIGHUP"
10
+ ];
11
+ function isCloudflaredExit(reason) {
12
+ return reason instanceof Error && reason.message.startsWith("cloudflared exited (");
13
+ }
14
+ /**
15
+ * Exposes the bot's interactions endpoint publicly while `stars dev` runs.
16
+ *
17
+ * `dev.tunnel: true` opens a `cloudflared` quick tunnel via `untun` (it changes on every run); a configured https
18
+ * URL is only probed, since the user already serves it. Writing the URL to the Discord application is opt-in
19
+ * through `dev.tunnel.updateEndpoint`, because it edits a live application.
20
+ */
21
+ var Tunnel = class extends EventEmitter {
22
+ config;
23
+ #startTunnel;
24
+ #tunnel = null;
25
+ #state = "off";
26
+ #url = null;
27
+ #wanted = false;
28
+ #rejectionGuard = null;
29
+ constructor(config, options = {}) {
30
+ super();
31
+ this.config = config;
32
+ this.#startTunnel = options.startTunnel ?? startTunnel;
33
+ }
34
+ get state() {
35
+ return this.#state;
36
+ }
37
+ /** The public URL of the interactions endpoint, `null` until the tunnel is up. */
38
+ get url() {
39
+ return this.#url;
40
+ }
41
+ async start(forceQuick = false) {
42
+ if (this.#state === "starting" || this.#state === "up") return;
43
+ const configured = this.config.dev.tunnel;
44
+ const tunnel = forceQuick && configured.mode === "off" ? {
45
+ mode: "quick",
46
+ path: "/",
47
+ updateEndpoint: false
48
+ } : configured;
49
+ if (tunnel.mode === "off") return;
50
+ this.#wanted = true;
51
+ this.#setState("starting", null);
52
+ const url = tunnel.mode === "url" ? await this.#useConfiguredUrl(tunnel) : await this.#openQuickTunnel();
53
+ if (!url || !this.#wanted) return;
54
+ this.#setState("up", endpointUrl(url, tunnel.path));
55
+ this.emit("log", "success", `Tunnel ready at ${this.#url}`);
56
+ if (tunnel.updateEndpoint) await this.#updateInteractionsEndpoint(this.#url);
57
+ }
58
+ /** Toggles the configured tunnel, opening a quick tunnel when the project did not configure one. */
59
+ toggle() {
60
+ return this.#state === "starting" || this.#state === "up" ? this.close() : this.start(true);
61
+ }
62
+ async close() {
63
+ this.#wanted = false;
64
+ const tunnel = this.#tunnel;
65
+ this.#tunnel = null;
66
+ this.#setState("off", null);
67
+ if (!tunnel) return;
68
+ try {
69
+ await tunnel.close();
70
+ } finally {
71
+ this.#releaseRejectionGuard();
72
+ }
73
+ }
74
+ async #useConfiguredUrl(tunnel) {
75
+ if (!await probe(endpointUrl(tunnel.url, tunnel.path))) this.emit("log", "warn", `${tunnel.url} did not answer; make sure it forwards to ${this.config.dev.url ?? "the bot"}`);
76
+ return tunnel.url;
77
+ }
78
+ async #openQuickTunnel() {
79
+ const target = this.config.dev.url;
80
+ if (!target) {
81
+ this.emit("log", "error", "A quick tunnel needs `dev.url` to know what to forward to");
82
+ this.#setState("failed", null);
83
+ return null;
84
+ }
85
+ this.emit("log", "info", "Opening a cloudflared quick tunnel…");
86
+ this.#installRejectionGuard();
87
+ try {
88
+ const tunnel = await this.#startWithoutSignalHandlers(target);
89
+ if (!this.#wanted) {
90
+ await tunnel?.close();
91
+ this.#releaseRejectionGuard();
92
+ return null;
93
+ }
94
+ if (!tunnel) {
95
+ this.emit("log", "error", "cloudflared setup was cancelled");
96
+ this.#setState("failed", null);
97
+ this.#releaseRejectionGuard();
98
+ return null;
99
+ }
100
+ this.#tunnel = tunnel;
101
+ return await tunnel.getURL();
102
+ } catch (error) {
103
+ this.#releaseRejectionGuard();
104
+ if (!this.#wanted) return null;
105
+ this.emit("log", "error", `cloudflared failed: ${error instanceof Error ? error.message : String(error)}`);
106
+ this.#setState("failed", null);
107
+ return null;
108
+ }
109
+ }
110
+ /**
111
+ * `untun` adds its own `SIGINT`/`SIGTERM`/`SIGHUP` listeners that call `process.exit()` once cloudflared is closed,
112
+ * which races `stars dev`'s graceful shutdown (it closes the tunnel through {@link close} anyway), so they are removed.
113
+ */
114
+ async #startWithoutSignalHandlers(target) {
115
+ const before = SIGNALS.map((signal) => new Set(process.listeners(signal)));
116
+ try {
117
+ return await this.#startTunnel({
118
+ url: target,
119
+ acceptCloudflareNotice: true
120
+ });
121
+ } finally {
122
+ SIGNALS.forEach((signal, index) => {
123
+ for (const listener of process.listeners(signal)) if (!before[index].has(listener)) process.off(signal, listener);
124
+ });
125
+ }
126
+ }
127
+ /**
128
+ * `untun` rejects a promise per connection when cloudflared exits and never handles it (and its location pattern
129
+ * does not match lowercase codes such as `mxp03`, so that promise is never settled before), which Node reports as an
130
+ * unhandled rejection that ends the process, whenever the tunnel closes. The guard swallows that one error for as
131
+ * long as this tunnel exists; anything else it sees is thrown again, as if it was not installed.
132
+ */
133
+ #installRejectionGuard() {
134
+ if (this.#rejectionGuard) return;
135
+ const guard = (reason) => {
136
+ if (!isCloudflaredExit(reason)) {
137
+ if (process.listeners("unhandledRejection").length === 1) throw reason;
138
+ return;
139
+ }
140
+ if (this.#state !== "up" || !this.#wanted) return;
141
+ this.#tunnel = null;
142
+ this.emit("log", "error", `cloudflared stopped unexpectedly: ${reason.message}`);
143
+ this.#setState("failed", null);
144
+ this.#releaseRejectionGuard();
145
+ };
146
+ this.#rejectionGuard = guard;
147
+ process.on("unhandledRejection", guard);
148
+ }
149
+ /** Node reports an unhandled rejection after the microtasks that follow it, so the guard has to outlive them. */
150
+ #releaseRejectionGuard() {
151
+ const guard = this.#rejectionGuard;
152
+ this.#rejectionGuard = null;
153
+ if (guard) setImmediate(() => process.off("unhandledRejection", guard));
154
+ }
155
+ /**
156
+ * Points the Discord application's interactions endpoint at the tunnel. Discord validates the endpoint with a
157
+ * signed ping before accepting it, so the bot has to be up already — this runs after the first successful build.
158
+ */
159
+ async #updateInteractionsEndpoint(url) {
160
+ const credentials = readDiscordCredentials(this.config);
161
+ if (!credentials) {
162
+ this.emit("log", "warn", "Skipped the interactions endpoint update: DISCORD_TOKEN is not set");
163
+ return;
164
+ }
165
+ try {
166
+ const response = await fetch("https://discord.com/api/v10/applications/@me", {
167
+ method: "PATCH",
168
+ headers: {
169
+ authorization: `Bot ${credentials.token}`,
170
+ "content-type": "application/json"
171
+ },
172
+ body: JSON.stringify({ interactions_endpoint_url: url }),
173
+ signal: AbortSignal.timeout(1e4)
174
+ });
175
+ if (response.ok) this.emit("log", "success", `Interactions endpoint set to ${url}`);
176
+ else this.emit("log", "error", `Discord rejected the interactions endpoint (${response.status}): ${(await response.text()).slice(0, 300)}`);
177
+ } catch (error) {
178
+ this.emit("log", "error", `Failed to update the interactions endpoint: ${error instanceof Error ? error.message : String(error)}`);
179
+ }
180
+ }
181
+ #setState(state, url) {
182
+ this.#state = state;
183
+ this.#url = url;
184
+ this.emit("state", state, url);
185
+ }
186
+ };
187
+ /**
188
+ * Joins the tunnel's origin with the path the interactions endpoint is served on.
189
+ */
190
+ function endpointUrl(origin, path) {
191
+ return path === "/" ? origin : new URL(path, origin.endsWith("/") ? origin : `${origin}/`).href;
192
+ }
193
+ async function probe(url) {
194
+ try {
195
+ return (await fetch(url, {
196
+ method: "HEAD",
197
+ signal: AbortSignal.timeout(5e3)
198
+ })).status < 500;
199
+ } catch {
200
+ return false;
201
+ }
202
+ }
203
+ /**
204
+ * Reads the Discord credentials the CLI needs from the environment, falling back to the project's `.env` files the
205
+ * way the bot itself does once it starts.
206
+ */
207
+ function readDiscordCredentials(config, env = process.env) {
208
+ const fromFiles = readProjectEnvFilesCached(config);
209
+ const read = (...keys) => {
210
+ for (const key of keys) {
211
+ const value = config.dev.env[key] ?? env[key] ?? fromFiles[key];
212
+ if (value) return value;
213
+ }
214
+ return null;
215
+ };
216
+ const token = read("DISCORD_TOKEN", "TOKEN");
217
+ if (!token) return null;
218
+ return {
219
+ token,
220
+ applicationId: read("DISCORD_APPLICATION_ID", "APPLICATION_ID", "DISCORD_CLIENT_ID", "CLIENT_ID")
221
+ };
222
+ }
223
+ let envFileCache = null;
224
+ /** The variables the bot loads (see {@link readProjectEnv}), once per project and `env` options. */
225
+ function readProjectEnvFilesCached(config) {
226
+ const key = JSON.stringify([config.root, config.env.options]);
227
+ if (envFileCache?.key !== key) envFileCache = {
228
+ key,
229
+ values: readProjectEnv(config)
230
+ };
231
+ return envFileCache.values;
232
+ }
233
+
234
+ //#endregion
235
+ export { endpointUrl as n, readDiscordCredentials as r, Tunnel as t };
236
+ //# sourceMappingURL=tunnel-BNV5cuJz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel-BNV5cuJz.js","names":[],"sources":["../src/dev/tunnel.ts"],"sourcesContent":["import type { ResolvedStarsConfig, ResolvedTunnelConfig } from '@wolfstar/schema';\nimport { readProjectEnv } from '../utils/project-env.js';\nimport { EventEmitter } from 'node:events';\nimport { startTunnel, type Tunnel as UntunTunnel } from 'untun';\nimport type { LogLevel } from '../utils/log-buffer.js';\n\nexport type TunnelState = 'off' | 'starting' | 'up' | 'failed';\n\nconst SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'] as const;\n\nfunction isCloudflaredExit(reason: unknown): reason is Error {\n\treturn reason instanceof Error && reason.message.startsWith('cloudflared exited (');\n}\n\nexport interface TunnelEvents {\n\tlog: [level: LogLevel, text: string];\n\tstate: [state: TunnelState, url: string | null];\n}\n\nexport interface TunnelOptions {\n\t/** Override for tests. */\n\tstartTunnel?: typeof startTunnel;\n}\n\n/**\n * Exposes the bot's interactions endpoint publicly while `stars dev` runs.\n *\n * `dev.tunnel: true` opens a `cloudflared` quick tunnel via `untun` (it changes on every run); a configured https\n * URL is only probed, since the user already serves it. Writing the URL to the Discord application is opt-in\n * through `dev.tunnel.updateEndpoint`, because it edits a live application.\n */\nexport class Tunnel extends EventEmitter<TunnelEvents> {\n\t#startTunnel: typeof startTunnel;\n\t#tunnel: UntunTunnel | null = null;\n\t#state: TunnelState = 'off';\n\t#url: string | null = null;\n\t#wanted = false;\n\t#rejectionGuard: ((reason: unknown) => void) | null = null;\n\n\tpublic constructor(\n\t\tprivate readonly config: ResolvedStarsConfig,\n\t\toptions: TunnelOptions = {}\n\t) {\n\t\tsuper();\n\t\tthis.#startTunnel = options.startTunnel ?? startTunnel;\n\t}\n\n\tpublic get state(): TunnelState {\n\t\treturn this.#state;\n\t}\n\n\t/** The public URL of the interactions endpoint, `null` until the tunnel is up. */\n\tpublic get url(): string | null {\n\t\treturn this.#url;\n\t}\n\n\tpublic async start(forceQuick = false): Promise<void> {\n\t\tif (this.#state === 'starting' || this.#state === 'up') return;\n\t\tconst configured = this.config.dev.tunnel;\n\t\tconst tunnel: ResolvedTunnelConfig =\n\t\t\tforceQuick && configured.mode === 'off' ? { mode: 'quick', path: '/', updateEndpoint: false } : configured;\n\t\tif (tunnel.mode === 'off') return;\n\n\t\tthis.#wanted = true;\n\t\tthis.#setState('starting', null);\n\t\tconst url = tunnel.mode === 'url' ? await this.#useConfiguredUrl(tunnel) : await this.#openQuickTunnel();\n\t\tif (!url || !this.#wanted) return;\n\n\t\tthis.#setState('up', endpointUrl(url, tunnel.path));\n\t\tthis.emit('log', 'success', `Tunnel ready at ${this.#url}`);\n\t\tif (tunnel.updateEndpoint) await this.#updateInteractionsEndpoint(this.#url!);\n\t}\n\n\t/** Toggles the configured tunnel, opening a quick tunnel when the project did not configure one. */\n\tpublic toggle(): Promise<void> {\n\t\treturn this.#state === 'starting' || this.#state === 'up' ? this.close() : this.start(true);\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis.#wanted = false;\n\t\tconst tunnel = this.#tunnel;\n\t\tthis.#tunnel = null;\n\t\tthis.#setState('off', null);\n\t\t// Without a tunnel, `#openQuickTunnel` is still waiting for one and closes it (then releases the guard) when it arrives.\n\t\tif (!tunnel) return;\n\t\ttry {\n\t\t\tawait tunnel.close();\n\t\t} finally {\n\t\t\tthis.#releaseRejectionGuard();\n\t\t}\n\t}\n\n\tasync #useConfiguredUrl(tunnel: Extract<ResolvedTunnelConfig, { mode: 'url' }>): Promise<string | null> {\n\t\tconst reachable = await probe(endpointUrl(tunnel.url, tunnel.path));\n\t\tif (!reachable) {\n\t\t\tthis.emit('log', 'warn', `${tunnel.url} did not answer; make sure it forwards to ${this.config.dev.url ?? 'the bot'}`);\n\t\t}\n\n\t\treturn tunnel.url;\n\t}\n\n\tasync #openQuickTunnel(): Promise<string | null> {\n\t\tconst target = this.config.dev.url;\n\t\tif (!target) {\n\t\t\tthis.emit('log', 'error', 'A quick tunnel needs `dev.url` to know what to forward to');\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\n\t\tthis.emit('log', 'info', 'Opening a cloudflared quick tunnel…');\n\t\tthis.#installRejectionGuard();\n\n\t\ttry {\n\t\t\tconst tunnel = await this.#startWithoutSignalHandlers(target);\n\t\t\tif (!this.#wanted) {\n\t\t\t\tawait tunnel?.close();\n\t\t\t\tthis.#releaseRejectionGuard();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!tunnel) {\n\t\t\t\tthis.emit('log', 'error', 'cloudflared setup was cancelled');\n\t\t\t\tthis.#setState('failed', null);\n\t\t\t\tthis.#releaseRejectionGuard();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tthis.#tunnel = tunnel;\n\t\t\treturn await tunnel.getURL();\n\t\t} catch (error) {\n\t\t\tthis.#releaseRejectionGuard();\n\t\t\t// Closing the tunnel makes cloudflared exit, which `untun` reports as a failure: that is not one.\n\t\t\tif (!this.#wanted) return null;\n\t\t\tthis.emit('log', 'error', `cloudflared failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * `untun` adds its own `SIGINT`/`SIGTERM`/`SIGHUP` listeners that call `process.exit()` once cloudflared is closed,\n\t * which races `stars dev`'s graceful shutdown (it closes the tunnel through {@link close} anyway), so they are removed.\n\t */\n\tasync #startWithoutSignalHandlers(target: string): Promise<UntunTunnel | undefined> {\n\t\tconst before = SIGNALS.map((signal) => new Set(process.listeners(signal)));\n\t\ttry {\n\t\t\treturn await this.#startTunnel({ url: target, acceptCloudflareNotice: true });\n\t\t} finally {\n\t\t\tSIGNALS.forEach((signal, index) => {\n\t\t\t\tfor (const listener of process.listeners(signal)) {\n\t\t\t\t\tif (!before[index]!.has(listener)) process.off(signal, listener);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * `untun` rejects a promise per connection when cloudflared exits and never handles it (and its location pattern\n\t * does not match lowercase codes such as `mxp03`, so that promise is never settled before), which Node reports as an\n\t * unhandled rejection that ends the process, whenever the tunnel closes. The guard swallows that one error for as\n\t * long as this tunnel exists; anything else it sees is thrown again, as if it was not installed.\n\t */\n\t#installRejectionGuard(): void {\n\t\tif (this.#rejectionGuard) return;\n\n\t\tconst guard = (reason: unknown): void => {\n\t\t\tif (!isCloudflaredExit(reason)) {\n\t\t\t\t// The guard is the only listener, so without this the rejection would be ignored instead of ending the process.\n\t\t\t\tif (process.listeners('unhandledRejection').length === 1) throw reason;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this.#state !== 'up' || !this.#wanted) return;\n\t\t\tthis.#tunnel = null;\n\t\t\tthis.emit('log', 'error', `cloudflared stopped unexpectedly: ${reason.message}`);\n\t\t\tthis.#setState('failed', null);\n\t\t\tthis.#releaseRejectionGuard();\n\t\t};\n\n\t\tthis.#rejectionGuard = guard;\n\t\tprocess.on('unhandledRejection', guard);\n\t}\n\n\t/** Node reports an unhandled rejection after the microtasks that follow it, so the guard has to outlive them. */\n\t#releaseRejectionGuard(): void {\n\t\tconst guard = this.#rejectionGuard;\n\t\tthis.#rejectionGuard = null;\n\t\tif (guard) setImmediate(() => process.off('unhandledRejection', guard));\n\t}\n\n\t/**\n\t * Points the Discord application's interactions endpoint at the tunnel. Discord validates the endpoint with a\n\t * signed ping before accepting it, so the bot has to be up already — this runs after the first successful build.\n\t */\n\tasync #updateInteractionsEndpoint(url: string): Promise<void> {\n\t\tconst credentials = readDiscordCredentials(this.config);\n\t\tif (!credentials) {\n\t\t\tthis.emit('log', 'warn', 'Skipped the interactions endpoint update: DISCORD_TOKEN is not set');\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch('https://discord.com/api/v10/applications/@me', {\n\t\t\t\tmethod: 'PATCH',\n\t\t\t\theaders: { authorization: `Bot ${credentials.token}`, 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({ interactions_endpoint_url: url }),\n\t\t\t\tsignal: AbortSignal.timeout(10_000)\n\t\t\t});\n\n\t\t\tif (response.ok) this.emit('log', 'success', `Interactions endpoint set to ${url}`);\n\t\t\telse\n\t\t\t\tthis.emit(\n\t\t\t\t\t'log',\n\t\t\t\t\t'error',\n\t\t\t\t\t`Discord rejected the interactions endpoint (${response.status}): ${(await response.text()).slice(0, 300)}`\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.emit('log', 'error', `Failed to update the interactions endpoint: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t}\n\n\t#setState(state: TunnelState, url: string | null): void {\n\t\tthis.#state = state;\n\t\tthis.#url = url;\n\t\tthis.emit('state', state, url);\n\t}\n}\n\n/**\n * Joins the tunnel's origin with the path the interactions endpoint is served on.\n */\nexport function endpointUrl(origin: string, path: string): string {\n\treturn path === '/' ? origin : new URL(path, origin.endsWith('/') ? origin : `${origin}/`).href;\n}\n\nasync function probe(url: string): Promise<boolean> {\n\ttry {\n\t\tconst response = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) });\n\t\treturn response.status < 500;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport interface DiscordCredentials {\n\ttoken: string;\n\tapplicationId: string | null;\n}\n\n/**\n * Reads the Discord credentials the CLI needs from the environment, falling back to the project's `.env` files the\n * way the bot itself does once it starts.\n */\nexport function readDiscordCredentials(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordCredentials | null {\n\tconst fromFiles = readProjectEnvFilesCached(config);\n\tconst read = (...keys: string[]): string | null => {\n\t\tfor (const key of keys) {\n\t\t\tconst value = config.dev.env[key] ?? env[key] ?? fromFiles[key];\n\t\t\tif (value) return value;\n\t\t}\n\t\treturn null;\n\t};\n\n\tconst token = read('DISCORD_TOKEN', 'TOKEN');\n\tif (!token) return null;\n\n\treturn { token, applicationId: read('DISCORD_APPLICATION_ID', 'APPLICATION_ID', 'DISCORD_CLIENT_ID', 'CLIENT_ID') };\n}\n\nlet envFileCache: { key: string; values: Record<string, string> } | null = null;\n\n/** The variables the bot loads (see {@link readProjectEnv}), once per project and `env` options. */\nfunction readProjectEnvFilesCached(config: ResolvedStarsConfig): Record<string, string> {\n\tconst key = JSON.stringify([config.root, config.env.options]);\n\tif (envFileCache?.key !== key) envFileCache = { key, values: readProjectEnv(config) };\n\treturn envFileCache.values;\n}\n"],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { i as shouldUseColor } from "./output-mode-Bp7Da8vJ.js";
2
+ import { t as cliDiagnostics } from "./diagnostics-Dn3CXa8J.js";
3
+ import { d as resolveCwd, n as loadProject, u as projectArgs } from "./hooks-D_RVS0ba.js";
4
+ import { n as reportWarnings, t as prepareProject } from "./_shared-CyzTojMA.js";
5
+ import { n as resolveTypecheckCommand } from "./typechecker-C3UOI2LF.js";
6
+ import { defineCommand } from "citty";
7
+ import { displayPath } from "@wolfstar/schema";
8
+ import { createColors } from "colorette";
9
+ import { spawn } from "node:child_process";
10
+
11
+ //#region src/commands/typecheck.ts
12
+ /**
13
+ * Type-checks the project once, the way `nuxt typecheck` does: regenerates `.stars/` first, then runs the project's own
14
+ * checker (`dev.typecheck.checker`, `golar` or `tsc`) on every project: the generated app and node configs from
15
+ * compatibility version 6, the single tsconfig below it. A project root `tsconfig.json` that only references them is
16
+ * never passed to `tsc -p`, which would check nothing.
17
+ */
18
+ async function runTypecheck(options) {
19
+ const stdout = options.stdout ?? process.stdout;
20
+ const colors = createColors({ useColor: shouldUseColor() });
21
+ const { config, hooks } = await loadProject({
22
+ cwd: resolveCwd(options),
23
+ configFile: options.config
24
+ });
25
+ await reportWarnings(config, (text) => process.stderr.write(`${text}\n`), { production: false });
26
+ await prepareProject(config, hooks);
27
+ const { projects } = config.dev.typecheck;
28
+ if (projects.length === 0) throw cliDiagnostics.TYPECHECK_NO_PROJECT({ root: config.root });
29
+ const failed = [];
30
+ for (const project of projects) {
31
+ const { command, args, node } = resolveTypecheckCommand(config, {
32
+ project,
33
+ once: true
34
+ });
35
+ stdout.write(`${colors.dim("stars")} typecheck ${displayPath(config.root, project)}\n`);
36
+ if (await new Promise((resolve, reject) => {
37
+ const child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {
38
+ cwd: config.root,
39
+ env: process.env,
40
+ stdio: "inherit",
41
+ windowsHide: true
42
+ });
43
+ child.once("error", reject);
44
+ child.once("exit", resolve);
45
+ }) !== 0) failed.push(displayPath(config.root, project));
46
+ }
47
+ if (failed.length > 0) throw cliDiagnostics.TYPECHECK_FAILED({ projects: failed.join(", ") });
48
+ stdout.write(`${colors.dim("stars")} ${colors.green("no type errors")}\n`);
49
+ }
50
+ var typecheck_default = defineCommand({
51
+ meta: {
52
+ name: "typecheck",
53
+ description: "Type-check the project, including the generated app and node TypeScript configurations"
54
+ },
55
+ args: { ...projectArgs },
56
+ async run({ args }) {
57
+ await runTypecheck({
58
+ config: args.config,
59
+ cwd: args.cwd
60
+ });
61
+ }
62
+ });
63
+
64
+ //#endregion
65
+ export { typecheck_default as default };
66
+ //# sourceMappingURL=typecheck-p_2rj9lL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typecheck-p_2rj9lL.js","names":[],"sources":["../src/commands/typecheck.ts"],"sourcesContent":["import { displayPath } from '@wolfstar/schema';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { spawn } from 'node:child_process';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { resolveTypecheckCommand } from '../dev/typechecker.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { loadProject } from '../utils/hooks.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { prepareProject, reportWarnings } from './_shared.js';\n\nexport interface TypecheckTaskOptions extends ProjectArgs {\n\tstdout?: NodeJS.WritableStream;\n}\n\n/**\n * Type-checks the project once, the way `nuxt typecheck` does: regenerates `.stars/` first, then runs the project's own\n * checker (`dev.typecheck.checker`, `golar` or `tsc`) on every project: the generated app and node configs from\n * compatibility version 6, the single tsconfig below it. A project root `tsconfig.json` that only references them is\n * never passed to `tsc -p`, which would check nothing.\n */\nexport async function runTypecheck(options: TypecheckTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() });\n\tconst { config, hooks } = await loadProject({ cwd: resolveCwd(options), configFile: options.config });\n\tawait reportWarnings(config, (text) => process.stderr.write(`${text}\\n`), { production: false });\n\tawait prepareProject(config, hooks);\n\n\tconst { projects } = config.dev.typecheck;\n\tif (projects.length === 0) throw cliDiagnostics.TYPECHECK_NO_PROJECT({ root: config.root });\n\n\tconst failed: string[] = [];\n\tfor (const project of projects) {\n\t\tconst { command, args, node } = resolveTypecheckCommand(config, { project, once: true });\n\t\tstdout.write(`${colors.dim('stars')} typecheck ${displayPath(config.root, project)}\\n`);\n\t\tconst code = await new Promise<number | null>((resolve, reject) => {\n\t\t\tconst child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {\n\t\t\t\tcwd: config.root,\n\t\t\t\tenv: process.env,\n\t\t\t\tstdio: 'inherit',\n\t\t\t\twindowsHide: true\n\t\t\t});\n\t\t\tchild.once('error', reject);\n\t\t\tchild.once('exit', resolve);\n\t\t});\n\t\tif (code !== 0) failed.push(displayPath(config.root, project));\n\t}\n\n\tif (failed.length > 0) throw cliDiagnostics.TYPECHECK_FAILED({ projects: failed.join(', ') });\n\tstdout.write(`${colors.dim('stars')} ${colors.green('no type errors')}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'typecheck',\n\t\tdescription: 'Type-check the project, including the generated app and node TypeScript configurations'\n\t},\n\targs: { ...projectArgs },\n\tasync run({ args }) {\n\t\tawait runTypecheck({ config: args.config, cwd: args.cwd });\n\t}\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,eAAsB,aAAa,SAA8C;CAChF,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,EAAE,CAAC;CAC1D,MAAM,EAAE,QAAQ,UAAU,MAAM,YAAY;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CACpG,MAAM,eAAe,SAAS,SAAS,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG,GAAG,EAAE,YAAY,MAAM,CAAC;CAC/F,MAAM,eAAe,QAAQ,KAAK;CAElC,MAAM,EAAE,aAAa,OAAO,IAAI;CAChC,IAAI,SAAS,WAAW,GAAG,MAAM,eAAe,qBAAqB,EAAE,MAAM,OAAO,KAAK,CAAC;CAE1F,MAAM,SAAmB,CAAC;CAC1B,KAAK,MAAM,WAAW,UAAU;EAC/B,MAAM,EAAE,SAAS,MAAM,SAAS,wBAAwB,QAAQ;GAAE;GAAS,MAAM;EAAK,CAAC;EACvF,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,aAAa,YAAY,OAAO,MAAM,OAAO,EAAE,GAAG;EAWtF,IAAI,MAVe,IAAI,SAAwB,SAAS,WAAW;GAClE,MAAM,QAAQ,MAAM,OAAO,QAAQ,WAAW,SAAS,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG;IAC7F,KAAK,OAAO;IACZ,KAAK,QAAQ;IACb,OAAO;IACP,aAAa;GACd,CAAC;GACD,MAAM,KAAK,SAAS,MAAM;GAC1B,MAAM,KAAK,QAAQ,OAAO;EAC3B,CAAC,MACY,GAAG,OAAO,KAAK,YAAY,OAAO,MAAM,OAAO,CAAC;CAC9D;CAEA,IAAI,OAAO,SAAS,GAAG,MAAM,eAAe,iBAAiB,EAAE,UAAU,OAAO,KAAK,IAAI,EAAE,CAAC;CAC5F,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,OAAO,MAAM,gBAAgB,EAAE,GAAG;AAC1E;AAEA,wBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM,EAAE,GAAG,YAAY;CACvB,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,aAAa;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;EAAI,CAAC;CAC1D;AACD,CAAC"}
@@ -0,0 +1,213 @@
1
+ import { t as cliDiagnostics } from "./diagnostics-Dn3CXa8J.js";
2
+ import { r as resolveBinary } from "./project-DBqQMFCk.js";
3
+ import { i as createLineSplitter, n as resolveTscBinary } from "./tsc-BArammxe.js";
4
+ import { EventEmitter } from "node:events";
5
+ import { spawn } from "node:child_process";
6
+
7
+ //#region src/dev/typechecker.ts
8
+ const WATCH_START = /Starting (incremental )?compilation/;
9
+ const WATCH_DONE = /Found (\d+) errors?\. Watching for file changes/;
10
+ const ONE_SHOT_DONE = /Found (\d+) errors?/;
11
+ const ERROR_LINE = /error TS\d+:/;
12
+ /**
13
+ * Runs a type checker next to the bot and reports type errors on their own channel, without ever blocking builds or
14
+ * restarts: `stars dev` keeps running whatever the build tool produced, the way Seedcord's `hmr.typecheck` and
15
+ * Vite's `checker` plugin do.
16
+ *
17
+ * `tsc` and `golar` (which forwards to TypeScript) watch the project themselves; `tsz` has no watch mode, so
18
+ * {@link Typechecker.check} re-runs it after every build instead.
19
+ */
20
+ var Typechecker = class extends EventEmitter {
21
+ config;
22
+ #child = null;
23
+ #state = "idle";
24
+ #errors = 0;
25
+ #pending = false;
26
+ constructor(config) {
27
+ super();
28
+ this.config = config;
29
+ }
30
+ get state() {
31
+ return this.#state;
32
+ }
33
+ get errors() {
34
+ return this.#errors;
35
+ }
36
+ /** Whether the checker re-runs per build instead of watching on its own. */
37
+ get oneShot() {
38
+ return this.config.dev.typecheck.enabled && !resolveTypecheckCommand(this.config).watch;
39
+ }
40
+ start() {
41
+ if (!this.config.dev.typecheck.enabled) return;
42
+ this.#run();
43
+ }
44
+ /**
45
+ * Re-runs a checker that cannot watch. Called after every successful build; a run already in flight is replaced,
46
+ * so a fast series of builds only leaves the last check standing.
47
+ */
48
+ check() {
49
+ if (!this.oneShot) return;
50
+ if (this.#child) {
51
+ this.#pending = true;
52
+ this.#child.kill();
53
+ return;
54
+ }
55
+ this.#run();
56
+ }
57
+ close() {
58
+ const child = this.#child;
59
+ this.#child = null;
60
+ this.#pending = false;
61
+ if (!child || child.exitCode !== null) return Promise.resolve();
62
+ return new Promise((resolve) => {
63
+ child.once("exit", () => resolve());
64
+ child.kill();
65
+ });
66
+ }
67
+ #run() {
68
+ const { command, args, node, watch } = resolveTypecheckCommand(this.config);
69
+ const child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {
70
+ cwd: this.config.root,
71
+ env: process.env,
72
+ stdio: [
73
+ "ignore",
74
+ "pipe",
75
+ "pipe"
76
+ ],
77
+ windowsHide: true
78
+ });
79
+ this.#child = child;
80
+ this.#setState("checking", 0);
81
+ let errors = 0;
82
+ const handleLine = (line) => {
83
+ if (ERROR_LINE.test(line)) errors++;
84
+ this.#handleLine(line);
85
+ };
86
+ const stdout = createLineSplitter(handleLine);
87
+ const stderr = createLineSplitter(handleLine);
88
+ child.stdout?.on("data", stdout.push);
89
+ child.stderr?.on("data", stderr.push);
90
+ child.once("exit", (code) => {
91
+ stdout.flush();
92
+ stderr.flush();
93
+ this.#child = null;
94
+ if (!watch && this.#state === "checking") this.#setState(code === 0 && errors === 0 ? "ok" : "failed", errors);
95
+ if (this.#pending) {
96
+ this.#pending = false;
97
+ this.#run();
98
+ }
99
+ });
100
+ child.once("error", (error) => {
101
+ this.#child = null;
102
+ this.emit("log", "error", error.code === "ENOENT" ? `${command} is not installed` : error.message);
103
+ this.#setState("failed", this.#errors);
104
+ });
105
+ }
106
+ #handleLine(line) {
107
+ const text = line.trim();
108
+ if (text.length === 0) return;
109
+ if (WATCH_START.test(text)) {
110
+ this.#setState("checking", 0);
111
+ return;
112
+ }
113
+ if (ERROR_LINE.test(text)) {
114
+ this.emit("log", "error", text);
115
+ return;
116
+ }
117
+ const done = WATCH_DONE.exec(text) ?? ONE_SHOT_DONE.exec(text);
118
+ if (done) {
119
+ const errors = Number(done[1]);
120
+ this.#setState(errors === 0 ? "ok" : "failed", errors);
121
+ this.emit("log", errors === 0 ? "success" : "error", errors === 0 ? "No type errors" : `${errors} type error${errors === 1 ? "" : "s"}`);
122
+ return;
123
+ }
124
+ this.emit("log", "info", text);
125
+ }
126
+ #setState(state, errors) {
127
+ this.#state = state;
128
+ this.#errors = errors;
129
+ this.emit("state", state, errors);
130
+ }
131
+ };
132
+ /**
133
+ * Builds the command line of the configured type checker, resolved from the project's own `node_modules`.
134
+ *
135
+ * @throws {Diagnostic} when the checker is not installed in the project.
136
+ */
137
+ function resolveTypecheckCommand(config, options = {}) {
138
+ const { checker, tsconfig } = config.dev.typecheck;
139
+ const project = options.project ?? tsconfig;
140
+ const flags = options.once ? ONCE_ARGS : WATCH_ARGS;
141
+ const watch = !options.once;
142
+ switch (checker) {
143
+ case "golar": {
144
+ const golar = resolveBinary(config.root, "golar", "golar");
145
+ if (!golar) throw missing(config, "golar", "Install it with `pnpm add -D golar`");
146
+ return {
147
+ command: golar,
148
+ args: [
149
+ "tsc",
150
+ ...flags,
151
+ "-p",
152
+ project
153
+ ],
154
+ node: true,
155
+ watch
156
+ };
157
+ }
158
+ case "tsz": {
159
+ const tsz = resolveBinary(config.root, "@mohsen-azimi/tsz-dev", "tsz");
160
+ if (tsz) return {
161
+ command: tsz,
162
+ args: [
163
+ "--noEmit",
164
+ "-p",
165
+ project
166
+ ],
167
+ node: true,
168
+ watch: false
169
+ };
170
+ const tryTsz = resolveBinary(config.root, "try-tsz", "try-tsz");
171
+ if (tryTsz) return {
172
+ command: tryTsz,
173
+ args: ["-p", project],
174
+ node: true,
175
+ watch: false
176
+ };
177
+ throw missing(config, "tsz", "Install it with `pnpm add -D @mohsen-azimi/tsz-dev` (or `try-tsz`)");
178
+ }
179
+ default: {
180
+ const tsc = resolveTscBinary(config.root);
181
+ if (!tsc) throw missing(config, "typescript", "Install it with `pnpm add -D typescript`");
182
+ return {
183
+ command: tsc,
184
+ args: [
185
+ ...flags,
186
+ "-p",
187
+ project
188
+ ],
189
+ node: true,
190
+ watch
191
+ };
192
+ }
193
+ }
194
+ }
195
+ const ONCE_ARGS = ["--noEmit"];
196
+ const WATCH_ARGS = [
197
+ "--noEmit",
198
+ "--watch",
199
+ "--preserveWatchOutput",
200
+ "--pretty",
201
+ "false"
202
+ ];
203
+ function missing(config, name, install) {
204
+ return cliDiagnostics.DEPENDENCY_MISSING({
205
+ name,
206
+ root: config.root,
207
+ hint: `${install}, pick another \`dev.typecheck.checker\`, or set \`dev.typecheck\` to false.`
208
+ });
209
+ }
210
+
211
+ //#endregion
212
+ export { resolveTypecheckCommand as n, Typechecker as t };
213
+ //# sourceMappingURL=typechecker-C3UOI2LF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typechecker-C3UOI2LF.js","names":[],"sources":["../src/dev/typechecker.ts"],"sourcesContent":["import type { ResolvedStarsConfig, StarsTypechecker } from '@wolfstar/schema';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { EventEmitter } from 'node:events';\nimport type { Diagnostic } from 'nostics';\nimport { resolveTscBinary } from '../builders/tsc.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport type { LogLevel } from '../utils/log-buffer.js';\nimport { createLineSplitter } from '../utils/process-supervisor.js';\nimport { resolveBinary } from '../utils/project.js';\n\nconst WATCH_START = /Starting (incremental )?compilation/;\nconst WATCH_DONE = /Found (\\d+) errors?\\. Watching for file changes/;\nconst ONE_SHOT_DONE = /Found (\\d+) errors?/;\nconst ERROR_LINE = /error TS\\d+:/;\n\nexport type TypecheckState = 'idle' | 'checking' | 'ok' | 'failed';\n\nexport interface TypecheckerEvents {\n\tlog: [level: LogLevel, text: string];\n\tstate: [state: TypecheckState, errors: number];\n}\n\nexport interface TypecheckCommand {\n\t/** The executable, and whether it is a script `node` has to run. */\n\treadonly command: string;\n\treadonly args: readonly string[];\n\treadonly node: boolean;\n\t/** Whether the checker watches the project itself, or has to be re-run after every build. */\n\treadonly watch: boolean;\n}\n\n/**\n * Runs a type checker next to the bot and reports type errors on their own channel, without ever blocking builds or\n * restarts: `stars dev` keeps running whatever the build tool produced, the way Seedcord's `hmr.typecheck` and\n * Vite's `checker` plugin do.\n *\n * `tsc` and `golar` (which forwards to TypeScript) watch the project themselves; `tsz` has no watch mode, so\n * {@link Typechecker.check} re-runs it after every build instead.\n */\nexport class Typechecker extends EventEmitter<TypecheckerEvents> {\n\t#child: ChildProcess | null = null;\n\t#state: TypecheckState = 'idle';\n\t#errors = 0;\n\t#pending = false;\n\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\n\t\tsuper();\n\t}\n\n\tpublic get state(): TypecheckState {\n\t\treturn this.#state;\n\t}\n\n\tpublic get errors(): number {\n\t\treturn this.#errors;\n\t}\n\n\t/** Whether the checker re-runs per build instead of watching on its own. */\n\tpublic get oneShot(): boolean {\n\t\treturn this.config.dev.typecheck.enabled && !resolveTypecheckCommand(this.config).watch;\n\t}\n\n\tpublic start(): void {\n\t\tif (!this.config.dev.typecheck.enabled) return;\n\t\tthis.#run();\n\t}\n\n\t/**\n\t * Re-runs a checker that cannot watch. Called after every successful build; a run already in flight is replaced,\n\t * so a fast series of builds only leaves the last check standing.\n\t */\n\tpublic check(): void {\n\t\tif (!this.oneShot) return;\n\t\tif (this.#child) {\n\t\t\tthis.#pending = true;\n\t\t\tthis.#child.kill();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#run();\n\t}\n\n\tpublic close(): Promise<void> {\n\t\tconst child = this.#child;\n\t\tthis.#child = null;\n\t\tthis.#pending = false;\n\t\tif (!child || child.exitCode !== null) return Promise.resolve();\n\n\t\treturn new Promise((resolve) => {\n\t\t\tchild.once('exit', () => resolve());\n\t\t\tchild.kill();\n\t\t});\n\t}\n\n\t#run(): void {\n\t\tconst { command, args, node, watch } = resolveTypecheckCommand(this.config);\n\t\tconst child = spawn(node ? process.execPath : command, node ? [command, ...args] : [...args], {\n\t\t\tcwd: this.config.root,\n\t\t\tenv: process.env,\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\twindowsHide: true\n\t\t});\n\t\tthis.#child = child;\n\t\tthis.#setState('checking', 0);\n\n\t\tlet errors = 0;\n\t\tconst handleLine = (line: string) => {\n\t\t\tif (ERROR_LINE.test(line)) errors++;\n\t\t\tthis.#handleLine(line);\n\t\t};\n\n\t\tconst stdout = createLineSplitter(handleLine);\n\t\tconst stderr = createLineSplitter(handleLine);\n\t\tchild.stdout?.on('data', stdout.push);\n\t\tchild.stderr?.on('data', stderr.push);\n\n\t\tchild.once('exit', (code) => {\n\t\t\tstdout.flush();\n\t\t\tstderr.flush();\n\t\t\tthis.#child = null;\n\n\t\t\tif (!watch && this.#state === 'checking') {\n\t\t\t\t// A one-shot checker only reports through its exit code when it prints no summary line.\n\t\t\t\tthis.#setState(code === 0 && errors === 0 ? 'ok' : 'failed', errors);\n\t\t\t}\n\n\t\t\tif (this.#pending) {\n\t\t\t\tthis.#pending = false;\n\t\t\t\tthis.#run();\n\t\t\t}\n\t\t});\n\t\tchild.once('error', (error: NodeJS.ErrnoException) => {\n\t\t\tthis.#child = null;\n\t\t\tthis.emit('log', 'error', error.code === 'ENOENT' ? `${command} is not installed` : error.message);\n\t\t\tthis.#setState('failed', this.#errors);\n\t\t});\n\t}\n\n\t#handleLine(line: string): void {\n\t\tconst text = line.trim();\n\t\tif (text.length === 0) return;\n\n\t\tif (WATCH_START.test(text)) {\n\t\t\tthis.#setState('checking', 0);\n\t\t\treturn;\n\t\t}\n\n\t\tif (ERROR_LINE.test(text)) {\n\t\t\tthis.emit('log', 'error', text);\n\t\t\treturn;\n\t\t}\n\n\t\tconst done = WATCH_DONE.exec(text) ?? ONE_SHOT_DONE.exec(text);\n\t\tif (done) {\n\t\t\tconst errors = Number(done[1]);\n\t\t\tthis.#setState(errors === 0 ? 'ok' : 'failed', errors);\n\t\t\tthis.emit('log', errors === 0 ? 'success' : 'error', errors === 0 ? 'No type errors' : `${errors} type error${errors === 1 ? '' : 's'}`);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.emit('log', 'info', text);\n\t}\n\n\t#setState(state: TypecheckState, errors: number): void {\n\t\tthis.#state = state;\n\t\tthis.#errors = errors;\n\t\tthis.emit('state', state, errors);\n\t}\n}\n\n/**\n * Builds the command line of the configured type checker, resolved from the project's own `node_modules`.\n *\n * @throws {Diagnostic} when the checker is not installed in the project.\n */\nexport function resolveTypecheckCommand(config: ResolvedStarsConfig, options: { project?: string; once?: boolean } = {}): TypecheckCommand {\n\tconst { checker, tsconfig } = config.dev.typecheck;\n\tconst project = options.project ?? tsconfig!;\n\t// `stars typecheck` checks a project once, with the checker's own output; `stars dev` watches it quietly.\n\tconst flags = options.once ? ONCE_ARGS : WATCH_ARGS;\n\tconst watch = !options.once;\n\n\tswitch (checker) {\n\t\tcase 'golar': {\n\t\t\t// `golar tsc` forwards everything after it to the TypeScript CLI, watch mode included.\n\t\t\tconst golar = resolveBinary(config.root, 'golar', 'golar');\n\t\t\tif (!golar) throw missing(config, 'golar', 'Install it with `pnpm add -D golar`');\n\n\t\t\treturn { command: golar, args: ['tsc', ...flags, '-p', project], node: true, watch };\n\t\t}\n\n\t\tcase 'tsz': {\n\t\t\t// `tsz` is an early, tsc-compatible checker with no watch mode; `try-tsz` is its comparison harness.\n\t\t\tconst tsz = resolveBinary(config.root, '@mohsen-azimi/tsz-dev', 'tsz');\n\t\t\tif (tsz) return { command: tsz, args: ['--noEmit', '-p', project], node: true, watch: false };\n\n\t\t\tconst tryTsz = resolveBinary(config.root, 'try-tsz', 'try-tsz');\n\t\t\tif (tryTsz) return { command: tryTsz, args: ['-p', project], node: true, watch: false };\n\n\t\t\tthrow missing(config, 'tsz', 'Install it with `pnpm add -D @mohsen-azimi/tsz-dev` (or `try-tsz`)');\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst tsc = resolveTscBinary(config.root);\n\t\t\tif (!tsc) throw missing(config, 'typescript', 'Install it with `pnpm add -D typescript`');\n\n\t\t\treturn { command: tsc, args: [...flags, '-p', project], node: true, watch };\n\t\t}\n\t}\n}\n\nconst ONCE_ARGS = ['--noEmit'] as const;\nconst WATCH_ARGS = ['--noEmit', '--watch', '--preserveWatchOutput', '--pretty', 'false'] as const;\n\nfunction missing(config: ResolvedStarsConfig, name: string, install: string): Diagnostic {\n\treturn cliDiagnostics.DEPENDENCY_MISSING({\n\t\tname,\n\t\troot: config.root,\n\t\thint: `${install}, pick another \\`dev.typecheck.checker\\`, or set \\`dev.typecheck\\` to false.`\n\t});\n}\n\nexport type { StarsTypechecker };\n"],"mappings":";;;;;;;AAUA,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,gBAAgB;AACtB,MAAM,aAAa;;;;;;;;;AA0BnB,IAAa,cAAb,cAAiC,aAAgC;CAM5B;CALpC,SAA8B;CAC9B,SAAyB;CACzB,UAAU;CACV,WAAW;CAEX,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;CAEpC;CAEA,IAAW,QAAwB;EAClC,OAAO,KAAK;CACb;CAEA,IAAW,SAAiB;EAC3B,OAAO,KAAK;CACb;;CAGA,IAAW,UAAmB;EAC7B,OAAO,KAAK,OAAO,IAAI,UAAU,WAAW,CAAC,wBAAwB,KAAK,MAAM,CAAC,CAAC;CACnF;CAEA,AAAO,QAAc;EACpB,IAAI,CAAC,KAAK,OAAO,IAAI,UAAU,SAAS;EACxC,KAAK,KAAK;CACX;;;;;CAMA,AAAO,QAAc;EACpB,IAAI,CAAC,KAAK,SAAS;EACnB,IAAI,KAAK,QAAQ;GAChB,KAAK,WAAW;GAChB,KAAK,OAAO,KAAK;GACjB;EACD;EAEA,KAAK,KAAK;CACX;CAEA,AAAO,QAAuB;EAC7B,MAAM,QAAQ,KAAK;EACnB,KAAK,SAAS;EACd,KAAK,WAAW;EAChB,IAAI,CAAC,SAAS,MAAM,aAAa,MAAM,OAAO,QAAQ,QAAQ;EAE9D,OAAO,IAAI,SAAS,YAAY;GAC/B,MAAM,KAAK,cAAc,QAAQ,CAAC;GAClC,MAAM,KAAK;EACZ,CAAC;CACF;CAEA,OAAa;EACZ,MAAM,EAAE,SAAS,MAAM,MAAM,UAAU,wBAAwB,KAAK,MAAM;EAC1E,MAAM,QAAQ,MAAM,OAAO,QAAQ,WAAW,SAAS,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,GAAG;GAC7F,KAAK,KAAK,OAAO;GACjB,KAAK,QAAQ;GACb,OAAO;IAAC;IAAU;IAAQ;GAAM;GAChC,aAAa;EACd,CAAC;EACD,KAAK,SAAS;EACd,KAAK,UAAU,YAAY,CAAC;EAE5B,IAAI,SAAS;EACb,MAAM,cAAc,SAAiB;GACpC,IAAI,WAAW,KAAK,IAAI,GAAG;GAC3B,KAAK,YAAY,IAAI;EACtB;EAEA,MAAM,SAAS,mBAAmB,UAAU;EAC5C,MAAM,SAAS,mBAAmB,UAAU;EAC5C,MAAM,QAAQ,GAAG,QAAQ,OAAO,IAAI;EACpC,MAAM,QAAQ,GAAG,QAAQ,OAAO,IAAI;EAEpC,MAAM,KAAK,SAAS,SAAS;GAC5B,OAAO,MAAM;GACb,OAAO,MAAM;GACb,KAAK,SAAS;GAEd,IAAI,CAAC,SAAS,KAAK,WAAW,YAE7B,KAAK,UAAU,SAAS,KAAK,WAAW,IAAI,OAAO,UAAU,MAAM;GAGpE,IAAI,KAAK,UAAU;IAClB,KAAK,WAAW;IAChB,KAAK,KAAK;GACX;EACD,CAAC;EACD,MAAM,KAAK,UAAU,UAAiC;GACrD,KAAK,SAAS;GACd,KAAK,KAAK,OAAO,SAAS,MAAM,SAAS,WAAW,GAAG,QAAQ,qBAAqB,MAAM,OAAO;GACjG,KAAK,UAAU,UAAU,KAAK,OAAO;EACtC,CAAC;CACF;CAEA,YAAY,MAAoB;EAC/B,MAAM,OAAO,KAAK,KAAK;EACvB,IAAI,KAAK,WAAW,GAAG;EAEvB,IAAI,YAAY,KAAK,IAAI,GAAG;GAC3B,KAAK,UAAU,YAAY,CAAC;GAC5B;EACD;EAEA,IAAI,WAAW,KAAK,IAAI,GAAG;GAC1B,KAAK,KAAK,OAAO,SAAS,IAAI;GAC9B;EACD;EAEA,MAAM,OAAO,WAAW,KAAK,IAAI,KAAK,cAAc,KAAK,IAAI;EAC7D,IAAI,MAAM;GACT,MAAM,SAAS,OAAO,KAAK,EAAE;GAC7B,KAAK,UAAU,WAAW,IAAI,OAAO,UAAU,MAAM;GACrD,KAAK,KAAK,OAAO,WAAW,IAAI,YAAY,SAAS,WAAW,IAAI,mBAAmB,GAAG,OAAO,aAAa,WAAW,IAAI,KAAK,KAAK;GACvI;EACD;EAEA,KAAK,KAAK,OAAO,QAAQ,IAAI;CAC9B;CAEA,UAAU,OAAuB,QAAsB;EACtD,KAAK,SAAS;EACd,KAAK,UAAU;EACf,KAAK,KAAK,SAAS,OAAO,MAAM;CACjC;AACD;;;;;;AAOA,SAAgB,wBAAwB,QAA6B,UAAgD,CAAC,GAAqB;CAC1I,MAAM,EAAE,SAAS,aAAa,OAAO,IAAI;CACzC,MAAM,UAAU,QAAQ,WAAW;CAEnC,MAAM,QAAQ,QAAQ,OAAO,YAAY;CACzC,MAAM,QAAQ,CAAC,QAAQ;CAEvB,QAAQ,SAAR;EACC,KAAK,SAAS;GAEb,MAAM,QAAQ,cAAc,OAAO,MAAM,SAAS,OAAO;GACzD,IAAI,CAAC,OAAO,MAAM,QAAQ,QAAQ,SAAS,qCAAqC;GAEhF,OAAO;IAAE,SAAS;IAAO,MAAM;KAAC;KAAO,GAAG;KAAO;KAAM;IAAO;IAAG,MAAM;IAAM;GAAM;EACpF;EAEA,KAAK,OAAO;GAEX,MAAM,MAAM,cAAc,OAAO,MAAM,yBAAyB,KAAK;GACrE,IAAI,KAAK,OAAO;IAAE,SAAS;IAAK,MAAM;KAAC;KAAY;KAAM;IAAO;IAAG,MAAM;IAAM,OAAO;GAAM;GAE5F,MAAM,SAAS,cAAc,OAAO,MAAM,WAAW,SAAS;GAC9D,IAAI,QAAQ,OAAO;IAAE,SAAS;IAAQ,MAAM,CAAC,MAAM,OAAO;IAAG,MAAM;IAAM,OAAO;GAAM;GAEtF,MAAM,QAAQ,QAAQ,OAAO,oEAAoE;EAClG;EAEA,SAAS;GACR,MAAM,MAAM,iBAAiB,OAAO,IAAI;GACxC,IAAI,CAAC,KAAK,MAAM,QAAQ,QAAQ,cAAc,0CAA0C;GAExF,OAAO;IAAE,SAAS;IAAK,MAAM;KAAC,GAAG;KAAO;KAAM;IAAO;IAAG,MAAM;IAAM;GAAM;EAC3E;CACD;AACD;AAEA,MAAM,YAAY,CAAC,UAAU;AAC7B,MAAM,aAAa;CAAC;CAAY;CAAW;CAAyB;CAAY;AAAO;AAEvF,SAAS,QAAQ,QAA6B,MAAc,SAA6B;CACxF,OAAO,eAAe,mBAAmB;EACxC;EACA,MAAM,OAAO;EACb,MAAM,GAAG,QAAQ;CAClB,CAAC;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { t as pluginRegistrations } from "./plugin-registrations-Dr_BicfC.js";
2
- import { n as importFromProject } from "./project-zlQStwsf.js";
2
+ import { n as importFromProject } from "./project-DBqQMFCk.js";
3
3
  import { ViteBuilder as ViteBuilder$1 } from "@wolfstar/vite-server";
4
4
 
5
5
  //#region src/builders/vite.ts
@@ -15,4 +15,4 @@ var ViteBuilder = class extends ViteBuilder$1 {
15
15
 
16
16
  //#endregion
17
17
  export { ViteBuilder };
18
- //# sourceMappingURL=vite-YZUtv2Hk.js.map
18
+ //# sourceMappingURL=vite-C5CN3xUu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vite-YZUtv2Hk.js","names":["ServerBuilder"],"sources":["../src/builders/vite.ts"],"sourcesContent":["import { ViteBuilder as ServerBuilder } from '@wolfstar/vite-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 ViteBuilder extends ServerBuilder {\n\tpublic constructor(config: ResolvedStarsConfig) {\n\t\tsuper(config, { importFromProject, pluginRegistrations });\n\t}\n}\n"],"mappings":";;;;;;AAMA,IAAa,cAAb,cAAiCA,cAAc;CAC9C,AAAO,YAAY,QAA6B;EAC/C,MAAM,QAAQ;GAAE;GAAmB;EAAoB,CAAC;CACzD;AACD"}
1
+ {"version":3,"file":"vite-C5CN3xUu.js","names":["ServerBuilder"],"sources":["../src/builders/vite.ts"],"sourcesContent":["import { ViteBuilder as ServerBuilder } from '@wolfstar/vite-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 ViteBuilder extends ServerBuilder {\n\tpublic constructor(config: ResolvedStarsConfig) {\n\t\tsuper(config, { importFromProject, pluginRegistrations });\n\t}\n}\n"],"mappings":";;;;;;AAMA,IAAa,cAAb,cAAiCA,cAAc;CAC9C,AAAO,YAAY,QAA6B;EAC/C,MAAM,QAAQ;GAAE;GAAmB;EAAoB,CAAC;CACzD;AACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wolfstar/cli",
3
- "version": "2.3.1",
3
+ "version": "2.6.0-next-20261007120201",
4
4
  "description": "The stars command line interface for @wolfstar/http-framework projects: typed configuration, dev server, build and project info",
5
5
  "keywords": [
6
6
  "api",
@@ -56,31 +56,31 @@
56
56
  "dependencies": {
57
57
  "@clack/prompts": "^1.8.1",
58
58
  "@sapphire/ts-config": "^5.0.3",
59
- "@wolfstar/kit": "^0.1.1",
60
- "@wolfstar/nitro-server": "^0.2.6",
61
- "@wolfstar/schema": "^0.6.0",
62
- "@wolfstar/vite-server": "^0.4.1",
59
+ "@wolfstar/kit": "^0.2.0-next-20261007120201",
60
+ "@wolfstar/nitro-server": "^0.2.9-next-20261007120201",
61
+ "@wolfstar/schema": "^0.9.0-next-20261007120201",
62
+ "@wolfstar/vite-server": "^0.4.4-next-20261007120201",
63
63
  "chokidar": "^5.0.0",
64
64
  "citty": "^0.2.2",
65
65
  "colorette": "^2.0.20",
66
66
  "hookable": "^6.1.2",
67
67
  "ink": "^7.1.1",
68
68
  "mlly": "^1.8.2",
69
- "my-bad": "^0.2.7",
69
+ "my-bad": "^0.2.9",
70
70
  "nostics": "^1.3.0",
71
71
  "react": "^19.3.0",
72
72
  "untun": "^0.2.2"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@types/react": "^19.3.0",
76
- "@vitest/coverage-v8": "^5.0.1",
76
+ "@vitest/coverage-v8": "^5.0.3",
77
77
  "@xterm/headless": "^6.0.0",
78
78
  "golar": "^0.1.10",
79
79
  "nitro": "^3.0.260903-beta",
80
80
  "tsdown": "^0.23.0",
81
81
  "typescript": "~7.0.2",
82
- "vite": "^8.3.0",
83
- "vitest": "^5.0.1"
82
+ "vite": "^8.3.1",
83
+ "vitest": "^5.0.3"
84
84
  },
85
85
  "peerDependencies": {
86
86
  "nitro": ">=3.0.0-0",