@wolfstar/cli 2.2.0 → 2.3.0-next-20261004142621
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.
- package/LICENSE +201 -201
- package/README.md +465 -304
- package/dist/{_shared-DJrpalNQ.js → _shared-BIQK0Bhm.js} +2 -2
- package/dist/_shared-BIQK0Bhm.js.map +1 -0
- package/dist/bridge-BvkmlAOZ.js +410 -0
- package/dist/bridge-BvkmlAOZ.js.map +1 -0
- package/dist/{build-CluOR8dJ.js → build-DJcc95Yq.js} +5 -5
- package/dist/build-DJcc95Yq.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{codegen-D6V1i_fa.js → codegen-aJSyPz-J.js} +4 -4
- package/dist/codegen-aJSyPz-J.js.map +1 -0
- package/dist/command-diff-BK912Hjc.js +78 -0
- package/dist/command-diff-BK912Hjc.js.map +1 -0
- package/dist/commands-CIPWQtF0.js +3 -0
- package/dist/commands-Clpbqq3K.js +15 -0
- package/dist/commands-Clpbqq3K.js.map +1 -0
- package/dist/{commands-BJ589_AC.js → commands-DVC7ky6f.js} +259 -9
- package/dist/commands-DVC7ky6f.js.map +1 -0
- package/dist/completions-D2KYtrrv.js +161 -0
- package/dist/completions-D2KYtrrv.js.map +1 -0
- package/dist/{dev-DJJZN4NJ.js → dev-oPPVR7d_.js} +434 -28
- package/dist/dev-oPPVR7d_.js.map +1 -0
- package/dist/{diagnostics-3JRAy8Xj.js → diagnostics-BysbNnPD.js} +22 -1
- package/dist/diagnostics-BysbNnPD.js.map +1 -0
- package/dist/doctor-DkVUwgDd.js +334 -0
- package/dist/doctor-DkVUwgDd.js.map +1 -0
- package/dist/errors-COFWKKKw.js.map +1 -1
- package/dist/external-CxFKxwi3.js.map +1 -1
- package/dist/framework-auto-imports-Gu_PXSyr.js.map +1 -1
- package/dist/{hooks-BfDFM38k.js → hooks-Cy6F2bhH.js} +20 -4
- package/dist/hooks-Cy6F2bhH.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{info-C1Kx_4Og.js → info-CKJVMWIT.js} +15 -4
- package/dist/info-CKJVMWIT.js.map +1 -0
- package/dist/{locales-BzOLRBVg.js → locales-BJAP4HYf.js} +5 -5
- package/dist/locales-BJAP4HYf.js.map +1 -0
- package/dist/log-view-B7uJEnMR.js +342 -0
- package/dist/log-view-B7uJEnMR.js.map +1 -0
- package/dist/{nitro-yjqZBh5L.js → nitro-B8u1iVgf.js} +2 -2
- package/dist/nitro-B8u1iVgf.js.map +1 -0
- package/dist/none-uC_wi_l4.js.map +1 -1
- package/dist/output-mode-Bp7Da8vJ.js.map +1 -1
- package/dist/{plain-B6z85uQP.js → plain-DG7cy0Kk.js} +7 -2
- package/dist/plain-DG7cy0Kk.js.map +1 -0
- package/dist/{prepare-Cb45Z4re.js → prepare-BM93i3Rm.js} +4 -4
- package/dist/prepare-BM93i3Rm.js.map +1 -0
- package/dist/{project-D-8VIcyF.js → project-zlQStwsf.js} +2 -2
- package/dist/project-zlQStwsf.js.map +1 -0
- package/dist/{run-BiLZqib3.js → run-DMM2YlP3.js} +2 -12
- package/dist/run-DMM2YlP3.js.map +1 -0
- package/dist/{theme-3Fc_LI-2.js → theme-yS2h5dd_.js} +25 -1
- package/dist/theme-yS2h5dd_.js.map +1 -0
- package/dist/tsc-C5l5TQGC.js +3 -0
- package/dist/{tsc-DEBcwIO0.js → tsc-puVAcwmo.js} +24 -5
- package/dist/tsc-puVAcwmo.js.map +1 -0
- package/dist/{tsdown-DrWXld54.js → tsdown-Dwt3JhPw.js} +2 -2
- package/dist/tsdown-Dwt3JhPw.js.map +1 -0
- package/dist/{tui-BRddrLQP.js → tui-nldGSD4c.js} +913 -141
- package/dist/tui-nldGSD4c.js.map +1 -0
- package/dist/version-BzclCE19.js.map +1 -1
- package/dist/{vite-Bf7nrJx7.js → vite-YZUtv2Hk.js} +2 -2
- package/dist/vite-YZUtv2Hk.js.map +1 -0
- package/package.json +5 -5
- package/dist/_shared-DJrpalNQ.js.map +0 -1
- package/dist/build-CluOR8dJ.js.map +0 -1
- package/dist/codegen-D6V1i_fa.js.map +0 -1
- package/dist/commands-BJ589_AC.js.map +0 -1
- package/dist/dev-DJJZN4NJ.js.map +0 -1
- package/dist/diagnostics-3JRAy8Xj.js.map +0 -1
- package/dist/hooks-BfDFM38k.js.map +0 -1
- package/dist/info-C1Kx_4Og.js.map +0 -1
- package/dist/locales-BzOLRBVg.js.map +0 -1
- package/dist/log-buffer-CY82aqnb.js +0 -72
- package/dist/log-buffer-CY82aqnb.js.map +0 -1
- package/dist/nitro-yjqZBh5L.js.map +0 -1
- package/dist/plain-B6z85uQP.js.map +0 -1
- package/dist/prepare-Cb45Z4re.js.map +0 -1
- package/dist/project-D-8VIcyF.js.map +0 -1
- package/dist/run-BiLZqib3.js.map +0 -1
- package/dist/theme-3Fc_LI-2.js.map +0 -1
- package/dist/tsc-B931Ezh7.js +0 -3
- package/dist/tsc-DEBcwIO0.js.map +0 -1
- package/dist/tsdown-DrWXld54.js.map +0 -1
- package/dist/tui-BRddrLQP.js.map +0 -1
- package/dist/tunnel-DHSxOZKr.js +0 -175
- package/dist/tunnel-DHSxOZKr.js.map +0 -1
- package/dist/vite-Bf7nrJx7.js.map +0 -1
|
@@ -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-
|
|
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-
|
|
18
|
+
//# sourceMappingURL=nitro-B8u1iVgf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"none-uC_wi_l4.js","names":[],"sources":["../src/builders/none.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\
|
|
1
|
+
{"version":3,"file":"none-uC_wi_l4.js","names":[],"sources":["../src/builders/none.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { Builder, BuilderEvents, BuildOutcome } from './types.js';\n\n/**\n * No build step: watches the configured paths and reports every change as an instant successful \"build\".\n */\nexport class NoneBuilder extends EventEmitter<BuilderEvents> implements Builder {\n\tpublic readonly tool = 'none' as const;\n\t#watcher: { close(): Promise<void> } | null = null;\n\n\tpublic constructor(private readonly config: ResolvedStarsConfig) {\n\t\tsuper();\n\t}\n\n\tpublic build(): Promise<BuildOutcome> {\n\t\tthis.emit('start');\n\t\tconst outcome: BuildOutcome = { ok: true, durationMs: 0, message: null };\n\t\tthis.emit('success', outcome);\n\t\treturn Promise.resolve(outcome);\n\t}\n\n\tpublic async watch(): Promise<void> {\n\t\tconst { watch } = await import('chokidar');\n\t\tconst watcher = watch([...this.config.dev.watch], {\n\t\t\tignored: [...this.config.dev.ignore],\n\t\t\tignoreInitial: true,\n\t\t\tcwd: this.config.root\n\t\t});\n\t\tthis.#watcher = watcher;\n\n\t\twatcher.on('all', (event, path) => {\n\t\t\tthis.emit('log', 'info', `${event}: ${path}`);\n\t\t\tvoid this.build();\n\t\t});\n\t\twatcher.on('error', (error) => this.emit('log', 'error', error instanceof Error ? error.message : String(error)));\n\n\t\tawait new Promise<void>((resolve) => watcher.once('ready', resolve));\n\t\tawait this.build();\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tconst watcher = this.#watcher;\n\t\tthis.#watcher = null;\n\t\tawait watcher?.close();\n\t}\n}\n"],"mappings":";;;;;;AAOA,IAAa,cAAb,cAAiC,aAA+C;CAI3C;CAHpC,AAAgB,OAAO;CACvB,WAA8C;CAE9C,AAAO,YAAY,AAAiB,QAA6B;EAChE,MAAM;EAD6B;CAEpC;CAEA,AAAO,QAA+B;EACrC,KAAK,KAAK,OAAO;EACjB,MAAM,UAAwB;GAAE,IAAI;GAAM,YAAY;GAAG,SAAS;EAAK;EACvE,KAAK,KAAK,WAAW,OAAO;EAC5B,OAAO,QAAQ,QAAQ,OAAO;CAC/B;CAEA,MAAa,QAAuB;EACnC,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,UAAU,MAAM,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,GAAG;GACjD,SAAS,CAAC,GAAG,KAAK,OAAO,IAAI,MAAM;GACnC,eAAe;GACf,KAAK,KAAK,OAAO;EAClB,CAAC;EACD,KAAK,WAAW;EAEhB,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAClC,KAAK,KAAK,OAAO,QAAQ,GAAG,MAAM,IAAI,MAAM;GAC5C,AAAK,KAAK,MAAM;EACjB,CAAC;EACD,QAAQ,GAAG,UAAU,UAAU,KAAK,KAAK,OAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,CAAC;EAEhH,MAAM,IAAI,SAAe,YAAY,QAAQ,KAAK,SAAS,OAAO,CAAC;EACnE,MAAM,KAAK,MAAM;CAClB;CAEA,MAAa,QAAuB;EACnC,MAAM,UAAU,KAAK;EACrB,KAAK,WAAW;EAChB,MAAM,SAAS,MAAM;CACtB;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-mode-Bp7Da8vJ.js","names":[],"sources":["../src/utils/output-mode.ts"],"sourcesContent":["export type OutputMode = 'tui' | 'plain';\
|
|
1
|
+
{"version":3,"file":"output-mode-Bp7Da8vJ.js","names":[],"sources":["../src/utils/output-mode.ts"],"sourcesContent":["export type OutputMode = 'tui' | 'plain';\n\nexport interface ResolveOutputModeOptions {\n\t/** `--no-tui` (`tui: false`) or `--tui` (`tui: true`) from the command line. */\n\ttui?: boolean;\n\tenv?: NodeJS.ProcessEnv;\n\t/** Whether stdout is an interactive terminal. */\n\tisTTY?: boolean;\n\t/** Raw-key input requires a terminal too, even when the output is a TTY. */\n\tisInputTTY?: boolean;\n\tcolumns?: number;\n\trows?: number;\n\t/** Whether the process runs in a CI environment. */\n\tisCI?: boolean;\n}\n\nconst truthy = new Set(['1', 'true', 'yes', 'on']);\n\n/**\n * Decides between the interactive TUI and plain line output.\n *\n * Precedence: `--no-tui` › `STARS_TUI=plain` › non-interactive stdout, CI or `TERM=dumb`.\n */\nexport function resolveOutputMode(options: ResolveOutputModeOptions = {}): OutputMode {\n\tconst env = options.env ?? process.env;\n\tconst isTTY = options.isTTY ?? Boolean(process.stdout.isTTY);\n\tconst isInputTTY = options.isInputTTY ?? options.isTTY ?? Boolean(process.stdin.isTTY);\n\tconst isCI = options.isCI ?? isCIEnvironment(env);\n\n\tif (options.tui === false) return 'plain';\n\n\tconst forced = env.STARS_TUI?.trim().toLowerCase();\n\tif (forced === 'plain' || forced === '0' || forced === 'false' || forced === 'off') return 'plain';\n\tif (!isTTY || !isInputTTY || env.TERM === 'dumb') return 'plain';\n\tif (forced === 'tui' || (forced && truthy.has(forced))) return isTTY ? 'tui' : 'plain';\n\n\tif (options.tui === true) return isTTY ? 'tui' : 'plain';\n\tif (isCI || (options.columns ?? process.stdout.columns ?? 80) < 40 || (options.rows ?? process.stdout.rows ?? 24) < 10) return 'plain';\n\treturn 'tui';\n}\n\nexport function isCIEnvironment(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn (\n\t\tBoolean(env.CI && !['false', '0'].includes(env.CI.toLowerCase())) ||\n\t\tBoolean(env.GITHUB_ACTIONS || env.GITLAB_CI || env.BUILDKITE || env.CIRCLECI)\n\t);\n}\n\n/**\n * Whether colours should be emitted, honouring `NO_COLOR` and `FORCE_COLOR`.\n */\nexport function shouldUseColor(env: NodeJS.ProcessEnv = process.env, isTTY = Boolean(process.stdout.isTTY)): boolean {\n\tif (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return false;\n\tif (env.FORCE_COLOR !== undefined) return env.FORCE_COLOR !== '0';\n\treturn isTTY && env.TERM !== 'dumb';\n}\n\n/**\n * Whether animations (spinners, blinking status) should be avoided.\n */\nexport function prefersReducedMotion(env: NodeJS.ProcessEnv = process.env): boolean {\n\tconst value = env.STARS_REDUCED_MOTION ?? env.REDUCED_MOTION;\n\treturn value !== undefined && value !== '' && value !== '0' && value.toLowerCase() !== 'false';\n}\n"],"mappings":";AAgBA,MAAM,yBAAS,IAAI,IAAI;CAAC;CAAK;CAAQ;CAAO;AAAI,CAAC;;;;;;AAOjD,SAAgB,kBAAkB,UAAoC,CAAC,GAAe;CACrF,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,OAAO,KAAK;CAC3D,MAAM,aAAa,QAAQ,cAAc,QAAQ,SAAS,QAAQ,QAAQ,MAAM,KAAK;CACrF,MAAM,OAAO,QAAQ,QAAQ,gBAAgB,GAAG;CAEhD,IAAI,QAAQ,QAAQ,OAAO,OAAO;CAElC,MAAM,SAAS,IAAI,WAAW,KAAK,CAAC,CAAC,YAAY;CACjD,IAAI,WAAW,WAAW,WAAW,OAAO,WAAW,WAAW,WAAW,OAAO,OAAO;CAC3F,IAAI,CAAC,SAAS,CAAC,cAAc,IAAI,SAAS,QAAQ,OAAO;CACzD,IAAI,WAAW,SAAU,UAAU,OAAO,IAAI,MAAM,GAAI,OAAO,QAAQ,QAAQ;CAE/E,IAAI,QAAQ,QAAQ,MAAM,OAAO,QAAQ,QAAQ;CACjD,IAAI,SAAS,QAAQ,WAAW,QAAQ,OAAO,WAAW,MAAM,OAAO,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,MAAM,IAAI,OAAO;CAC/H,OAAO;AACR;AAEA,SAAgB,gBAAgB,MAAyB,QAAQ,KAAc;CAC9E,OACC,QAAQ,IAAI,MAAM,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,YAAY,CAAC,CAAC,KAChE,QAAQ,IAAI,kBAAkB,IAAI,aAAa,IAAI,aAAa,IAAI,QAAQ;AAE9E;;;;AAKA,SAAgB,eAAe,MAAyB,QAAQ,KAAK,QAAQ,QAAQ,QAAQ,OAAO,KAAK,GAAY;CACpH,IAAI,IAAI,aAAa,UAAa,IAAI,aAAa,IAAI,OAAO;CAC9D,IAAI,IAAI,gBAAgB,QAAW,OAAO,IAAI,gBAAgB;CAC9D,OAAO,SAAS,IAAI,SAAS;AAC9B;;;;AAKA,SAAgB,qBAAqB,MAAyB,QAAQ,KAAc;CACnF,MAAM,QAAQ,IAAI,wBAAwB,IAAI;CAC9C,OAAO,UAAU,UAAa,UAAU,MAAM,UAAU,OAAO,MAAM,YAAY,MAAM;AACxF"}
|
|
@@ -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
|
-
|
|
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-
|
|
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-
|
|
3
|
-
import {
|
|
4
|
-
import { n as reportWarnings, t as prepareProject } from "./_shared-
|
|
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";
|
|
@@ -66,4 +66,4 @@ var prepare_default = defineCommand({
|
|
|
66
66
|
|
|
67
67
|
//#endregion
|
|
68
68
|
export { prepare_default as default };
|
|
69
|
-
//# sourceMappingURL=prepare-
|
|
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-
|
|
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-
|
|
67
|
+
//# sourceMappingURL=project-zlQStwsf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-zlQStwsf.js","names":[],"sources":["../src/utils/project.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { cliDiagnostics } from './diagnostics.js';\n\n/**\n * Resolves a module id from the project root, the way the project itself would.\n */\nexport function resolveFromProject(root: string, id: string): string | null {\n\ttry {\n\t\treturn createRequire(join(root, 'package.json')).resolve(id);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Imports a module from the project root, failing with an actionable error when it is not installed.\n */\nexport async function importFromProject<T>(root: string, id: string, hint: string): Promise<T> {\n\tconst resolved = resolveFromProject(root, id);\n\tif (!resolved) {\n\t\tthrow cliDiagnostics.DEPENDENCY_MISSING({ name: id, root, hint });\n\t}\n\n\treturn (await import(pathToFileURL(resolved).href)) as T;\n}\n\n/**\n * Resolves an executable a package declares in its `package.json#bin`, from the project's own `node_modules`.\n *\n * Going through `bin` rather than a hardcoded path is what makes this work across layouts: TypeScript 7 hides\n * `lib/tsc.js` behind its `exports` map, and packages move their entry points between releases.\n */\nexport function resolveBinary(root: string, packageName: string, binName: string): string | null {\n\tconst packageJsonPath = resolveFromProject(root, `${packageName}/package.json`);\n\tif (!packageJsonPath) return null;\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) as { bin?: string | Record<string, string> };\n\t\tconst bin = typeof packageJson.bin === 'string' ? packageJson.bin : packageJson.bin?.[binName];\n\t\treturn bin ? join(dirname(packageJsonPath), bin) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Finds the version of an installed package by walking `node_modules` up from `root`.\n */\nexport function findInstalledVersion(root: string, name: string): string | null {\n\tlet directory = root;\n\tfor (;;) {\n\t\tconst file = join(directory, 'node_modules', name, 'package.json');\n\t\tif (existsSync(file)) {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(readFileSync(file, 'utf-8')) as { version?: string };\n\t\t\t\treturn parsed.version ?? null;\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tconst parent = dirname(directory);\n\t\tif (parent === directory) return null;\n\t\tdirectory = parent;\n\t}\n}\n"],"mappings":";;;;;;;;;;AASA,SAAgB,mBAAmB,MAAc,IAA2B;CAC3E,IAAI;EACH,OAAO,cAAc,KAAK,MAAM,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC5D,QAAQ;EACP,OAAO;CACR;AACD;;;;AAKA,eAAsB,kBAAqB,MAAc,IAAY,MAA0B;CAC9F,MAAM,WAAW,mBAAmB,MAAM,EAAE;CAC5C,IAAI,CAAC,UACJ,MAAM,eAAe,mBAAmB;EAAE,MAAM;EAAI;EAAM;CAAK,CAAC;CAGjE,OAAQ,MAAM,OAAO,cAAc,QAAQ,CAAC,CAAC;AAC9C;;;;;;;AAQA,SAAgB,cAAc,MAAc,aAAqB,SAAgC;CAChG,MAAM,kBAAkB,mBAAmB,MAAM,GAAG,YAAY,cAAc;CAC9E,IAAI,CAAC,iBAAiB,OAAO;CAE7B,IAAI;EACH,MAAM,cAAc,KAAK,MAAM,aAAa,iBAAiB,OAAO,CAAC;EACrE,MAAM,MAAM,OAAO,YAAY,QAAQ,WAAW,YAAY,MAAM,YAAY,MAAM;EACtF,OAAO,MAAM,KAAK,QAAQ,eAAe,GAAG,GAAG,IAAI;CACpD,QAAQ;EACP,OAAO;CACR;AACD;;;;AAKA,SAAgB,qBAAqB,MAAc,MAA6B;CAC/E,IAAI,YAAY;CAChB,SAAS;EACR,MAAM,OAAO,KAAK,WAAW,gBAAgB,MAAM,cAAc;EACjE,IAAI,WAAW,IAAI,GAClB,IAAI;GAEH,OADe,KAAK,MAAM,aAAa,MAAM,OAAO,CACxC,CAAC,CAAC,WAAW;EAC1B,QAAQ;GACP,OAAO;EACR;EAGD,MAAM,SAAS,QAAQ,SAAS;EAChC,IAAI,WAAW,WAAW,OAAO;EACjC,YAAY;CACb;AACD"}
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
+
import { t as commands } from "./commands-Clpbqq3K.js";
|
|
1
2
|
import { t as readOwnPackageJson } from "./version-BzclCE19.js";
|
|
2
3
|
import { n as exitCodeOf, r as formatError } from "./errors-COFWKKKw.js";
|
|
3
4
|
import { defineCommand, renderUsage, runCommand } from "citty";
|
|
4
5
|
import process from "node:process";
|
|
5
6
|
|
|
6
|
-
//#region src/commands/index.ts
|
|
7
|
-
const commands = {
|
|
8
|
-
dev: () => import("./dev-DJJZN4NJ.js").then((module) => module.default),
|
|
9
|
-
build: () => import("./build-CluOR8dJ.js").then((module) => module.default),
|
|
10
|
-
info: () => import("./info-C1Kx_4Og.js").then((module) => module.default),
|
|
11
|
-
codegen: () => import("./codegen-D6V1i_fa.js").then((module) => module.default),
|
|
12
|
-
prepare: () => import("./prepare-Cb45Z4re.js").then((module) => module.default),
|
|
13
|
-
commands: () => import("./commands-BJ589_AC.js").then((module) => module.default)
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
//#endregion
|
|
17
7
|
//#region src/main.ts
|
|
18
8
|
const packageJson = readOwnPackageJson();
|
|
19
9
|
const main = defineCommand({
|
|
@@ -62,4 +52,4 @@ async function runMain(argv = process.argv.slice(2)) {
|
|
|
62
52
|
|
|
63
53
|
//#endregion
|
|
64
54
|
export { runMain as t };
|
|
65
|
-
//# sourceMappingURL=run-
|
|
55
|
+
//# sourceMappingURL=run-DMM2YlP3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-DMM2YlP3.js","names":["_runCommand"],"sources":["../src/main.ts","../src/run.ts"],"sourcesContent":["import { defineCommand, type CommandDef } from 'citty';\nimport { commands } from './commands/index.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\nconst packageJson = readOwnPackageJson();\n\nexport const main = defineCommand({\n\tmeta: {\n\t\tname: 'stars',\n\t\tversion: packageJson.version,\n\t\tdescription: packageJson.description\n\t},\n\tsubCommands: commands\n}) as AnyCommand;\n","import { renderUsage, runCommand as _runCommand, type CommandDef } from 'citty';\nimport process from 'node:process';\nimport { commands } from './commands/index.js';\nimport { main } from './main.js';\nimport { exitCodeOf, formatError } from './utils/errors.js';\nimport { readOwnPackageJson } from './utils/version.js';\n\n// citty types each command by its own arguments; the registry needs the erased form.\n// oxlint-disable-next-line typescript/no-explicit-any\ntype AnyCommand = CommandDef<any>;\n\n/**\n * Walks the command names of `stars <command> [<subcommand>] --help` so nested commands (`stars commands clean`)\n * render their own usage instead of their parent's.\n */\nasync function resolveHelpTarget(names: string[]): Promise<AnyCommand | null> {\n\tconst [first, ...rest] = names;\n\tif (!first || !Object.hasOwn(commands, first)) return null;\n\n\tlet command = await commands[first]!();\n\tfor (const name of rest) {\n\t\tconst resolved = typeof command.subCommands === 'function' ? await command.subCommands() : await command.subCommands;\n\t\tconst child: unknown = (resolved as Record<string, unknown> | undefined)?.[name];\n\t\tif (!child) break;\n\t\tcommand = (typeof child === 'function' ? await child() : child) as AnyCommand;\n\t}\n\n\treturn command;\n}\n\nexport async function runMain(argv: string[] = process.argv.slice(2)): Promise<void> {\n\tif (argv.includes('--version') || argv.includes('-V')) {\n\t\tconsole.log(readOwnPackageJson().version);\n\t\tprocess.exit(0);\n\t}\n\n\tif (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {\n\t\t// citty's showUsage logs through consola, which is muted in some environments; render and print directly.\n\t\tconst command = await resolveHelpTarget(argv.filter((argument) => !argument.startsWith('-')));\n\t\tconsole.log(await (command ? renderUsage(command, main) : renderUsage(main)));\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tawait _runCommand(main, { rawArgs: argv });\n\t} catch (error) {\n\t\tconsole.error(await formatError(error));\n\t\tprocess.exit(exitCodeOf(error));\n\t}\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc,mBAAmB;AAEvC,MAAa,OAAO,cAAc;CACjC,MAAM;EACL,MAAM;EACN,SAAS,YAAY;EACrB,aAAa,YAAY;CAC1B;CACA,aAAa;AACd,CAAC;;;;;;;;ACFD,eAAe,kBAAkB,OAA6C;CAC7E,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO,UAAU,KAAK,GAAG,OAAO;CAEtD,IAAI,UAAU,MAAM,SAAS,MAAM,CAAE;CACrC,KAAK,MAAM,QAAQ,MAAM;EAExB,MAAM,SADW,OAAO,QAAQ,gBAAgB,aAAa,MAAM,QAAQ,YAAY,IAAI,MAAM,QAAQ,YACzE,GAA2C;EAC3E,IAAI,CAAC,OAAO;EACZ,UAAW,OAAO,UAAU,aAAa,MAAM,MAAM,IAAI;CAC1D;CAEA,OAAO;AACR;AAEA,eAAsB,QAAQ,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;CACpF,IAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,IAAI,GAAG;EACtD,QAAQ,IAAI,mBAAmB,CAAC,CAAC,OAAO;EACxC,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI,KAAK,WAAW,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;EAExE,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,aAAa,CAAC,SAAS,WAAW,GAAG,CAAC,CAAC;EAC5F,QAAQ,IAAI,OAAO,UAAU,YAAY,SAAS,IAAI,IAAI,YAAY,IAAI,EAAE;EAC5E,QAAQ,KAAK,CAAC;CACf;CAEA,IAAI;EACH,MAAMA,WAAY,MAAM,EAAE,SAAS,KAAK,CAAC;CAC1C,SAAS,OAAO;EACf,QAAQ,MAAM,MAAM,YAAY,KAAK,CAAC;EACtC,QAAQ,KAAK,WAAW,KAAK,CAAC;CAC/B;AACD"}
|