@alint-js/cli 0.0.5 → 0.0.6
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/dist/bin/index.mjs +1 -1
- package/dist/{cli-CoS-NVz_.mjs → cli-C4PnKXoK.mjs} +728 -476
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -3
package/dist/bin/index.mjs
CHANGED
|
@@ -1,16 +1,96 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
-
import { stat } from "node:fs/promises";
|
|
3
2
|
import { inspect } from "node:util";
|
|
4
|
-
import Gitignore from "gitignore-fs";
|
|
5
|
-
import c, { createColors } from "tinyrainbow";
|
|
6
|
-
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
7
|
-
import { AlintRunError, runAlint } from "@alint-js/core";
|
|
8
|
-
import { errorMessageFrom } from "@moeru/std/error";
|
|
9
3
|
import { cac } from "cac";
|
|
10
|
-
import {
|
|
4
|
+
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
5
|
+
import { AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
6
|
+
import { relative, resolve } from "pathe";
|
|
11
7
|
import { getBorderCharacters, table } from "table";
|
|
8
|
+
import { errorMessageFrom } from "@moeru/std/error";
|
|
9
|
+
import { readdir, stat } from "node:fs/promises";
|
|
10
|
+
import c, { createColors } from "tinyrainbow";
|
|
12
11
|
import cliSpinners from "cli-spinners";
|
|
13
|
-
import { relative } from "node:path";
|
|
12
|
+
import { relative as relative$1 } from "node:path";
|
|
13
|
+
import Gitignore from "gitignore-fs";
|
|
14
|
+
import { minimatch } from "minimatch";
|
|
15
|
+
//#region src/cli/commands/command.ts
|
|
16
|
+
function defineCommand(node) {
|
|
17
|
+
return node;
|
|
18
|
+
}
|
|
19
|
+
function registerCommandTree(cli, nodes, context, setPendingResult) {
|
|
20
|
+
for (const node of nodes) registerRootCommand(cli, node, context, setPendingResult);
|
|
21
|
+
}
|
|
22
|
+
function collectCommandOptions(node) {
|
|
23
|
+
const options = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const option of node.options ?? []) options.set(option.flags, option);
|
|
25
|
+
for (const child of node.children ?? []) for (const option of collectCommandOptions(child)) options.set(option.flags, option);
|
|
26
|
+
return [...options.values()];
|
|
27
|
+
}
|
|
28
|
+
function commandPattern(node) {
|
|
29
|
+
if (node.default) return node.arguments ?? node.name;
|
|
30
|
+
return [node.name, node.children ? "[...args]" : node.arguments].filter(Boolean).join(" ");
|
|
31
|
+
}
|
|
32
|
+
function dispatchCommand(context, node, args, options, path) {
|
|
33
|
+
const [subcommand, ...restArgs] = args;
|
|
34
|
+
const child = node.children?.find((item) => item.name === subcommand || item.alias?.includes(subcommand ?? ""));
|
|
35
|
+
if (child) return dispatchCommand(context, child, restArgs, options, [...path, child.name]);
|
|
36
|
+
if (!node.action) return Promise.resolve(reportUnknownCommand(context, path, args));
|
|
37
|
+
return Promise.resolve(node.action(context, ...parseCommandArguments(node, args), options));
|
|
38
|
+
}
|
|
39
|
+
function formatUnknownCommand(path, args) {
|
|
40
|
+
return [...path, ...args].filter(Boolean).join(" ");
|
|
41
|
+
}
|
|
42
|
+
function parseCommandArguments(node, args) {
|
|
43
|
+
if (!node.arguments) return [];
|
|
44
|
+
const parts = node.arguments.split(/\s+/u).filter(Boolean);
|
|
45
|
+
const values = [];
|
|
46
|
+
let argIndex = 0;
|
|
47
|
+
for (const part of parts) {
|
|
48
|
+
if (part.startsWith("[...") || part.startsWith("<...")) {
|
|
49
|
+
values.push(args.slice(argIndex));
|
|
50
|
+
argIndex = args.length;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (part.startsWith("<") && argIndex >= args.length) throw new Error(`Missing required argument ${part}.`);
|
|
54
|
+
values.push(args[argIndex]);
|
|
55
|
+
argIndex += 1;
|
|
56
|
+
}
|
|
57
|
+
return values;
|
|
58
|
+
}
|
|
59
|
+
function registerRootCommand(cli, node, context, setPendingResult) {
|
|
60
|
+
const command = cli.command(commandPattern(node), node.description);
|
|
61
|
+
if (node.allowUnknownOptions || node.children) command.allowUnknownOptions();
|
|
62
|
+
for (const alias of node.alias ?? []) command.alias(alias);
|
|
63
|
+
for (const option of collectCommandOptions(node)) command.option(option.flags, option.description, option.config);
|
|
64
|
+
command.action((...args) => {
|
|
65
|
+
const options = args.at(-1);
|
|
66
|
+
return setPendingResult(node.children ? dispatchCommand(context, node, args[0] ?? [], options, [node.name]) : Promise.resolve(node.action?.(context, ...args.slice(0, -1), options) ?? 0));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function reportUnknownCommand(context, path, args) {
|
|
70
|
+
context.io.stderr.write(`unknown config command: ${formatUnknownCommand(path, args)}\n`);
|
|
71
|
+
return 2;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/cli/commands/config/inspect.ts
|
|
75
|
+
const inspect$1 = defineCommand({
|
|
76
|
+
action: (context, file, options) => runConfigInspectCommand(file, options.config, context.io),
|
|
77
|
+
arguments: "<file>",
|
|
78
|
+
description: "Inspect resolved config for a file",
|
|
79
|
+
name: "inspect"
|
|
80
|
+
});
|
|
81
|
+
async function runConfigInspectCommand(file, configPath, io) {
|
|
82
|
+
const config = await loadAlintConfig(io.cwd, configPath);
|
|
83
|
+
const result = resolveConfigForFile(resolve(io.cwd, file), config, { cwd: io.cwd });
|
|
84
|
+
io.stdout.write(`file: ${file}\n`);
|
|
85
|
+
io.stdout.write(`ignored: ${result.ignored ? "yes" : "no"}\n`);
|
|
86
|
+
io.stdout.write("matched:\n");
|
|
87
|
+
for (const item of result.matched) io.stdout.write(` - ${item.name ?? "<anonymous>"}\n`);
|
|
88
|
+
io.stdout.write(`language: ${result.config.language ?? "<inferred>"}\n`);
|
|
89
|
+
io.stdout.write("rules:\n");
|
|
90
|
+
for (const [id, entry] of Object.entries(result.config.rules)) io.stdout.write(` ${id}: ${Array.isArray(entry) ? entry[0] : entry}\n`);
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
14
94
|
//#region src/cli/provider-registry.ts
|
|
15
95
|
function buildModelsUrl(endpoint) {
|
|
16
96
|
return new URL("models", endpoint.endsWith("/") ? endpoint : `${endpoint}/`).toString();
|
|
@@ -116,335 +196,186 @@ function formatTable(rows) {
|
|
|
116
196
|
});
|
|
117
197
|
}
|
|
118
198
|
//#endregion
|
|
119
|
-
//#region src/cli/commands/setup
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
return
|
|
199
|
+
//#region src/cli/commands/config/setup-config.ts
|
|
200
|
+
async function loadMergedSetupConfig(io) {
|
|
201
|
+
const globalSetupConfigPath = getGlobalSetupConfigPath(io.env ?? process.env);
|
|
202
|
+
const projectSetupConfigPath = getProjectSetupConfigPath(io.cwd);
|
|
203
|
+
const [globalSetupConfig, projectSetupConfig] = await Promise.all([loadSetupConfig(globalSetupConfigPath), loadSetupConfig(projectSetupConfigPath)]);
|
|
204
|
+
return mergeSetupConfigs(globalSetupConfig, projectSetupConfig);
|
|
125
205
|
}
|
|
126
|
-
|
|
127
|
-
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/cli/commands/config/models/ls.ts
|
|
208
|
+
const ls$1 = defineCommand({
|
|
209
|
+
async action(context) {
|
|
210
|
+
context.io.stdout.write(formatModelList(await loadMergedSetupConfig(context.io)));
|
|
211
|
+
return 0;
|
|
212
|
+
},
|
|
213
|
+
alias: ["ls"],
|
|
214
|
+
description: "List configured models",
|
|
215
|
+
name: "list"
|
|
216
|
+
});
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/cli/commands/config/probe.ts
|
|
219
|
+
function providerHeadersFromOptions(options) {
|
|
220
|
+
return parseHeaderList(toArray$1(options.providerHeader)) ?? {};
|
|
128
221
|
}
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
while (true) {
|
|
143
|
-
if (step === "scope") {
|
|
144
|
-
const scope = await prompts.select({
|
|
145
|
-
message: "Where should alint write setup config?",
|
|
146
|
-
options: [{
|
|
147
|
-
label: "Global",
|
|
148
|
-
value: "global"
|
|
149
|
-
}, {
|
|
150
|
-
label: "Local project",
|
|
151
|
-
value: "local"
|
|
152
|
-
}]
|
|
153
|
-
});
|
|
154
|
-
if (prompts.isCancel(scope)) return cancelPrompt();
|
|
155
|
-
draft.scope = scope;
|
|
156
|
-
step = "source";
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
if (step === "source") {
|
|
160
|
-
const source = await prompts.select({
|
|
161
|
-
message: "Choose provider setup mode.",
|
|
162
|
-
options: withBackOption([
|
|
163
|
-
{
|
|
164
|
-
label: "Custom OpenAI-compatible provider",
|
|
165
|
-
value: "custom"
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
label: "Ollama",
|
|
169
|
-
value: "ollama"
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
label: "Manual model entry",
|
|
173
|
-
value: "manual"
|
|
174
|
-
}
|
|
175
|
-
])
|
|
176
|
-
});
|
|
177
|
-
if (prompts.isCancel(source)) return cancelPrompt();
|
|
178
|
-
if (source === backValue) {
|
|
179
|
-
step = "scope";
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
draft.source = source;
|
|
183
|
-
step = "endpoint";
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
if (step === "endpoint") {
|
|
187
|
-
const endpoint = await promptEndpoint(prompts, draft.source ?? "custom");
|
|
188
|
-
if (prompts.isCancel(endpoint)) return cancelPrompt();
|
|
189
|
-
if (typeof endpoint !== "string") return cancelPrompt();
|
|
190
|
-
if (isBackInput(endpoint)) {
|
|
191
|
-
step = "source";
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
draft.endpoint = endpoint;
|
|
195
|
-
step = "providerId";
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (step === "providerId") {
|
|
199
|
-
const existingConfig = await loadSetupConfig(getConfigPath(io, draft.scope ?? "global"));
|
|
200
|
-
const providerId = await prompts.text({
|
|
201
|
-
defaultValue: draft.providerId ?? createProviderId(draft.endpoint ?? "", new Set(existingConfig.providers.map((provider) => provider.id))),
|
|
202
|
-
message: "Provider id",
|
|
203
|
-
placeholder: "Type .. to go back",
|
|
204
|
-
validate: (value) => isBackInput(value ?? "") || (value ?? "").trim().length > 0 ? void 0 : "Provider id is required."
|
|
205
|
-
});
|
|
206
|
-
if (prompts.isCancel(providerId)) return cancelPrompt();
|
|
207
|
-
if (typeof providerId !== "string") return cancelPrompt();
|
|
208
|
-
if (isBackInput(providerId)) {
|
|
209
|
-
step = "endpoint";
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
draft.providerId = providerId;
|
|
213
|
-
step = "headers";
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
if (step === "headers") {
|
|
217
|
-
const headerInput = await prompts.text({
|
|
218
|
-
defaultValue: draft.headerInput ?? "",
|
|
219
|
-
message: "Headers",
|
|
220
|
-
placeholder: "Authorization=Bearer token, X-Test=true; type .. to go back",
|
|
221
|
-
validate: (value) => {
|
|
222
|
-
if (isBackInput(value ?? "")) return;
|
|
223
|
-
try {
|
|
224
|
-
parseHeaderList(splitHeaderInput(value ?? ""));
|
|
225
|
-
return;
|
|
226
|
-
} catch {
|
|
227
|
-
return "Headers must be comma-separated Key=Value entries.";
|
|
228
|
-
}
|
|
222
|
+
function toArray$1(value) {
|
|
223
|
+
if (value === void 0) return [];
|
|
224
|
+
return (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/cli/commands/config/models/models.ts
|
|
228
|
+
const models = defineCommand({
|
|
229
|
+
children: [
|
|
230
|
+
defineCommand({
|
|
231
|
+
async action(context, options) {
|
|
232
|
+
if (!options.endpoint) {
|
|
233
|
+
context.io.stderr.write("config models probe requires --endpoint.\n");
|
|
234
|
+
return 2;
|
|
229
235
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
236
|
+
try {
|
|
237
|
+
const models = await probeModels(options.endpoint, providerHeadersFromOptions(options));
|
|
238
|
+
context.io.stdout.write(`${models.join("\n")}${models.length > 0 ? "\n" : ""}`);
|
|
239
|
+
return 0;
|
|
240
|
+
} catch (error) {
|
|
241
|
+
context.io.stderr.write(`failed to probe models: ${errorMessageFrom(error) ?? String(error)}\n`);
|
|
242
|
+
return 2;
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
description: "Probe OpenAI-compatible models",
|
|
246
|
+
name: "probe",
|
|
247
|
+
options: [{
|
|
248
|
+
description: "Provider endpoint",
|
|
249
|
+
flags: "--endpoint <url>"
|
|
250
|
+
}, {
|
|
251
|
+
description: "Provider header",
|
|
252
|
+
flags: "--provider-header <Key=Value>"
|
|
253
|
+
}]
|
|
254
|
+
}),
|
|
255
|
+
ls$1,
|
|
256
|
+
defineCommand({
|
|
257
|
+
async action(context, model) {
|
|
258
|
+
const candidate = findModel(await loadMergedSetupConfig(context.io), model);
|
|
259
|
+
if (candidate === void 0) {
|
|
260
|
+
context.io.stderr.write(`unknown model "${model}".\n`);
|
|
261
|
+
return 2;
|
|
262
|
+
}
|
|
263
|
+
context.io.stdout.write(formatModelShow(candidate));
|
|
264
|
+
return 0;
|
|
265
|
+
},
|
|
266
|
+
arguments: "<model>",
|
|
267
|
+
description: "Show configured model",
|
|
268
|
+
name: "show"
|
|
269
|
+
})
|
|
270
|
+
],
|
|
271
|
+
description: "Manage configured models",
|
|
272
|
+
name: "models"
|
|
273
|
+
});
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/cli/commands/config/providers/ls.ts
|
|
276
|
+
const ls = defineCommand({
|
|
277
|
+
async action(context) {
|
|
278
|
+
context.io.stdout.write(formatProviderList(await loadMergedSetupConfig(context.io)));
|
|
279
|
+
return 0;
|
|
280
|
+
},
|
|
281
|
+
alias: ["ls"],
|
|
282
|
+
description: "List configured providers",
|
|
283
|
+
name: "list"
|
|
284
|
+
});
|
|
285
|
+
//#endregion
|
|
286
|
+
//#region src/cli/commands/config/providers/probe.ts
|
|
287
|
+
const probe = defineCommand({
|
|
288
|
+
async action(context, options) {
|
|
289
|
+
if (!options.endpoint) {
|
|
290
|
+
context.io.stderr.write("config providers probe requires --endpoint.\n");
|
|
291
|
+
return 2;
|
|
242
292
|
}
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (!Array.isArray(selectedModels)) return cancelPrompt();
|
|
251
|
-
draft.selectedModels = selectedModels;
|
|
252
|
-
step = "defaultAlias";
|
|
253
|
-
continue;
|
|
293
|
+
try {
|
|
294
|
+
const models = await probeModels(options.endpoint, providerHeadersFromOptions(options));
|
|
295
|
+
context.io.stdout.write(`endpoint: ${options.endpoint}\nmodels: ${models.length}\n`);
|
|
296
|
+
return 0;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
context.io.stderr.write(`failed to probe provider: ${errorMessageFrom(error) ?? String(error)}\n`);
|
|
299
|
+
return 2;
|
|
254
300
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
301
|
+
},
|
|
302
|
+
description: "Probe provider reachability",
|
|
303
|
+
name: "probe",
|
|
304
|
+
options: [{
|
|
305
|
+
description: "Provider endpoint",
|
|
306
|
+
flags: "--endpoint <url>"
|
|
307
|
+
}, {
|
|
308
|
+
description: "Provider header",
|
|
309
|
+
flags: "--provider-header <Key=Value>"
|
|
310
|
+
}]
|
|
311
|
+
});
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/cli/commands/config/config.ts
|
|
314
|
+
const config = defineCommand({
|
|
315
|
+
children: [
|
|
316
|
+
inspect$1,
|
|
317
|
+
models,
|
|
318
|
+
defineCommand({
|
|
319
|
+
children: [
|
|
320
|
+
ls,
|
|
321
|
+
defineCommand({
|
|
322
|
+
async action(context, providerId) {
|
|
323
|
+
const provider = (await loadMergedSetupConfig(context.io)).providers.find((item) => item.id === providerId);
|
|
324
|
+
if (provider === void 0) {
|
|
325
|
+
context.io.stderr.write(`unknown provider "${providerId}".\n`);
|
|
326
|
+
return 2;
|
|
327
|
+
}
|
|
328
|
+
context.io.stdout.write(formatProviderShow(provider));
|
|
329
|
+
return 0;
|
|
330
|
+
},
|
|
331
|
+
arguments: "<provider>",
|
|
332
|
+
description: "Show configured provider",
|
|
333
|
+
name: "show"
|
|
334
|
+
}),
|
|
335
|
+
probe
|
|
336
|
+
],
|
|
337
|
+
description: "Manage configured providers",
|
|
338
|
+
name: "providers"
|
|
339
|
+
})
|
|
340
|
+
],
|
|
341
|
+
description: "Manage alint configuration",
|
|
342
|
+
name: "config"
|
|
343
|
+
});
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/cli/reporters/json.ts
|
|
346
|
+
function formatJson(result) {
|
|
347
|
+
return `${JSON.stringify(result, null, 2)}\n`;
|
|
348
|
+
}
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/cli/reporters/stylish.ts
|
|
351
|
+
const colors$1 = createColors({ force: true });
|
|
352
|
+
function formatStylish(input, options = {}) {
|
|
353
|
+
const diagnostics = Array.isArray(input) ? input : input.diagnostics;
|
|
354
|
+
const totalTokens = Array.isArray(input) ? void 0 : input.usage.totalTokens;
|
|
355
|
+
if (diagnostics.length === 0) return "";
|
|
356
|
+
const diagnosticsByFile = /* @__PURE__ */ new Map();
|
|
357
|
+
for (const diagnostic of diagnostics) {
|
|
358
|
+
const fileDiagnostics = diagnosticsByFile.get(diagnostic.filePath);
|
|
359
|
+
if (fileDiagnostics) {
|
|
360
|
+
fileDiagnostics.push(diagnostic);
|
|
273
361
|
continue;
|
|
274
362
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}, {
|
|
287
|
-
label: "No",
|
|
288
|
-
value: "no"
|
|
289
|
-
}])
|
|
290
|
-
});
|
|
291
|
-
if (prompts.isCancel(confirmed)) return cancelPrompt();
|
|
292
|
-
if (confirmed === backValue) {
|
|
293
|
-
step = "defaultAlias";
|
|
294
|
-
continue;
|
|
363
|
+
diagnosticsByFile.set(diagnostic.filePath, [diagnostic]);
|
|
364
|
+
}
|
|
365
|
+
const lines = [];
|
|
366
|
+
const style = createStyle(options.color === true);
|
|
367
|
+
for (const [filePath, fileDiagnostics] of diagnosticsByFile) {
|
|
368
|
+
lines.push(style.file(filePath));
|
|
369
|
+
for (const diagnostic of fileDiagnostics) {
|
|
370
|
+
const line = diagnostic.loc?.start.line ?? 0;
|
|
371
|
+
const column = diagnostic.loc?.start.column ?? 0;
|
|
372
|
+
const severity = diagnostic.severity === "warn" ? style.warning("warning") : style.error("error");
|
|
373
|
+
lines.push(` ${style.location(`${line}:${column}`)} ${severity} ${diagnostic.message} ${style.ruleId(diagnostic.ruleId)}`);
|
|
295
374
|
}
|
|
296
|
-
|
|
297
|
-
const configPath = getConfigPath(io, draft.scope ?? "global");
|
|
298
|
-
await writeSetupConfig(configPath, mergeSetupConfigs(await loadSetupConfig(configPath), {
|
|
299
|
-
providers: [nextProvider],
|
|
300
|
-
version: 1
|
|
301
|
-
}));
|
|
302
|
-
prompts.outro(`Wrote ${configPath}`);
|
|
303
|
-
return 0;
|
|
375
|
+
lines.push("");
|
|
304
376
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return [...options, {
|
|
308
|
-
label: "Back",
|
|
309
|
-
value: backValue
|
|
310
|
-
}];
|
|
311
|
-
}
|
|
312
|
-
function createProviderConfig(providerId, endpoint, headers, modelIds, addDefaultAlias) {
|
|
313
|
-
return {
|
|
314
|
-
endpoint,
|
|
315
|
-
headers,
|
|
316
|
-
id: providerId,
|
|
317
|
-
models: modelIds.map((modelId, index) => ({
|
|
318
|
-
aliases: index === 0 && addDefaultAlias ? ["default"] : void 0,
|
|
319
|
-
id: modelId,
|
|
320
|
-
name: modelId
|
|
321
|
-
})),
|
|
322
|
-
type: "openai-compatible"
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
function getConfigPath(io, scope) {
|
|
326
|
-
return scope === "local" ? getProjectSetupConfigPath(io.cwd) : getGlobalSetupConfigPath(io.env ?? process.env);
|
|
327
|
-
}
|
|
328
|
-
async function probeModelsWithSpinner(prompts, endpoint, headers) {
|
|
329
|
-
const spinner = prompts.spinner();
|
|
330
|
-
spinner.start("Probing models");
|
|
331
|
-
try {
|
|
332
|
-
const models = await probeModels(endpoint, headers ?? {});
|
|
333
|
-
spinner.stop(models.length > 0 ? `Found ${models.length} models` : "No models discovered");
|
|
334
|
-
return models;
|
|
335
|
-
} catch (error) {
|
|
336
|
-
spinner.stop(formatProbeModelsFailure(endpoint, error));
|
|
337
|
-
return [];
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
async function promptEndpoint(prompts, source) {
|
|
341
|
-
return prompts.text({
|
|
342
|
-
defaultValue: source === "ollama" ? "http://localhost:11434/v1" : void 0,
|
|
343
|
-
message: "Provider endpoint",
|
|
344
|
-
placeholder: source === "ollama" ? "http://localhost:11434/v1; type .. to go back" : "https://example.test/v1; type .. to go back",
|
|
345
|
-
validate: (value) => isBackInput(value ?? "") || (value ?? "").trim().length > 0 ? void 0 : "Provider endpoint is required."
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
async function promptModels(prompts, discoveredModels) {
|
|
349
|
-
if (discoveredModels.length > 0) {
|
|
350
|
-
const selectedModels = await prompts.multiselect({
|
|
351
|
-
message: "Select models",
|
|
352
|
-
options: withBackOption(discoveredModels.map((model) => ({
|
|
353
|
-
label: model,
|
|
354
|
-
value: model
|
|
355
|
-
}))),
|
|
356
|
-
required: true
|
|
357
|
-
});
|
|
358
|
-
return Array.isArray(selectedModels) && selectedModels.includes(backValue) ? backValue : selectedModels;
|
|
359
|
-
}
|
|
360
|
-
const modelInput = await prompts.text({
|
|
361
|
-
message: "Models",
|
|
362
|
-
placeholder: "qwen:8b, qwen:32b; type .. to go back",
|
|
363
|
-
validate: (value) => isBackInput(value ?? "") || splitModelInput(value ?? "").length > 0 ? void 0 : "At least one model is required."
|
|
364
|
-
});
|
|
365
|
-
if (prompts.isCancel(modelInput)) return modelInput;
|
|
366
|
-
return isBackInput(modelInput) ? backValue : splitModelInput(modelInput);
|
|
367
|
-
}
|
|
368
|
-
function splitHeaderInput(value) {
|
|
369
|
-
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
370
|
-
}
|
|
371
|
-
function splitModelInput(value) {
|
|
372
|
-
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
373
|
-
}
|
|
374
|
-
//#endregion
|
|
375
|
-
//#region src/cli/commands/setup/index.ts
|
|
376
|
-
async function runSetupCommand(options, io) {
|
|
377
|
-
if (!options.providerEndpoint) {
|
|
378
|
-
if (options.noInteractive !== true) return runInteractiveSetup({
|
|
379
|
-
...io,
|
|
380
|
-
stdin: io.stdin ?? process.stdin
|
|
381
|
-
});
|
|
382
|
-
io.stderr.write("setup requires --provider-endpoint in --no-interactive mode.\n");
|
|
383
|
-
return 2;
|
|
384
|
-
}
|
|
385
|
-
if (!options.providerId) {
|
|
386
|
-
io.stderr.write("setup requires --provider-id in --no-interactive mode.\n");
|
|
387
|
-
return 2;
|
|
388
|
-
}
|
|
389
|
-
const setupConfigPath = options.local ? getProjectSetupConfigPath(io.cwd) : getGlobalSetupConfigPath(io.env ?? process.env);
|
|
390
|
-
await writeSetupConfig(setupConfigPath, mergeSetupConfigs(await loadSetupConfig(setupConfigPath), createSetupConfig(options.providerId, options.providerEndpoint, options)));
|
|
391
|
-
return 0;
|
|
392
|
-
}
|
|
393
|
-
function createSetupConfig(providerId, providerEndpoint, options) {
|
|
394
|
-
const models = toArray$1(options.providerModel).map((model) => ({
|
|
395
|
-
id: model,
|
|
396
|
-
name: model
|
|
397
|
-
}));
|
|
398
|
-
return {
|
|
399
|
-
providers: [{
|
|
400
|
-
endpoint: providerEndpoint,
|
|
401
|
-
headers: parseHeaderList(toArray$1(options.providerHeader)),
|
|
402
|
-
id: providerId,
|
|
403
|
-
models,
|
|
404
|
-
type: "openai-compatible"
|
|
405
|
-
}],
|
|
406
|
-
version: 1
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
function toArray$1(value) {
|
|
410
|
-
if (value === void 0) return [];
|
|
411
|
-
return (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
|
|
412
|
-
}
|
|
413
|
-
//#endregion
|
|
414
|
-
//#region src/cli/reporters/json.ts
|
|
415
|
-
function formatJson(result) {
|
|
416
|
-
return `${JSON.stringify(result, null, 2)}\n`;
|
|
417
|
-
}
|
|
418
|
-
//#endregion
|
|
419
|
-
//#region src/cli/reporters/stylish.ts
|
|
420
|
-
const colors$1 = createColors({ force: true });
|
|
421
|
-
function formatStylish(input, options = {}) {
|
|
422
|
-
const diagnostics = Array.isArray(input) ? input : input.diagnostics;
|
|
423
|
-
const totalTokens = Array.isArray(input) ? void 0 : input.usage.totalTokens;
|
|
424
|
-
if (diagnostics.length === 0) return "";
|
|
425
|
-
const diagnosticsByFile = /* @__PURE__ */ new Map();
|
|
426
|
-
for (const diagnostic of diagnostics) {
|
|
427
|
-
const fileDiagnostics = diagnosticsByFile.get(diagnostic.filePath);
|
|
428
|
-
if (fileDiagnostics) {
|
|
429
|
-
fileDiagnostics.push(diagnostic);
|
|
430
|
-
continue;
|
|
431
|
-
}
|
|
432
|
-
diagnosticsByFile.set(diagnostic.filePath, [diagnostic]);
|
|
433
|
-
}
|
|
434
|
-
const lines = [];
|
|
435
|
-
const style = createStyle(options.color === true);
|
|
436
|
-
for (const [filePath, fileDiagnostics] of diagnosticsByFile) {
|
|
437
|
-
lines.push(style.file(filePath));
|
|
438
|
-
for (const diagnostic of fileDiagnostics) {
|
|
439
|
-
const line = diagnostic.loc?.start.line ?? 0;
|
|
440
|
-
const column = diagnostic.loc?.start.column ?? 0;
|
|
441
|
-
const severity = diagnostic.severity === "warn" ? style.warning("warning") : style.error("error");
|
|
442
|
-
lines.push(` ${style.location(`${line}:${column}`)} ${severity} ${diagnostic.message} ${style.ruleId(diagnostic.ruleId)}`);
|
|
443
|
-
}
|
|
444
|
-
lines.push("");
|
|
445
|
-
}
|
|
446
|
-
lines.push("", formatSummary(diagnostics, totalTokens, style));
|
|
447
|
-
return `${lines.join("\n")}\n`;
|
|
377
|
+
lines.push("", formatSummary(diagnostics, totalTokens, style));
|
|
378
|
+
return `${lines.join("\n")}\n`;
|
|
448
379
|
}
|
|
449
380
|
function countDiagnostics$2(diagnostics, severity) {
|
|
450
381
|
return diagnostics.filter((diagnostic) => diagnostic.severity === severity).length;
|
|
@@ -655,7 +586,7 @@ function formatEstimatedDuration(ms) {
|
|
|
655
586
|
}
|
|
656
587
|
function formatFilePath(filePath, cwd) {
|
|
657
588
|
if (!cwd) return filePath;
|
|
658
|
-
return relative(cwd, filePath) || filePath;
|
|
589
|
+
return relative$1(cwd, filePath) || filePath;
|
|
659
590
|
}
|
|
660
591
|
function formatFileRows(file, state, options, now) {
|
|
661
592
|
const firstRow = formatFileSummaryRow(file, state, options);
|
|
@@ -850,44 +781,62 @@ function createRenderingProgressReporter(summary, renderer) {
|
|
|
850
781
|
};
|
|
851
782
|
}
|
|
852
783
|
//#endregion
|
|
853
|
-
//#region src/cli/
|
|
854
|
-
async function
|
|
855
|
-
const
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
noInteractive: setupNoInteractive
|
|
863
|
-
}, io);
|
|
864
|
-
return pendingResult;
|
|
865
|
-
});
|
|
866
|
-
cli.command("config [...args]", "Manage alint configuration").option("--endpoint <url>", "Provider endpoint").option("--provider-header <Key=Value>", "Provider header").action((args, options) => {
|
|
867
|
-
pendingResult = runConfigCommand(args, options, io);
|
|
868
|
-
return pendingResult;
|
|
869
|
-
});
|
|
870
|
-
cli.command("[...files]", "Run alint").action((files = [], options) => {
|
|
871
|
-
pendingResult = runDefaultCommand(files, options, io);
|
|
872
|
-
return pendingResult;
|
|
873
|
-
});
|
|
874
|
-
const restoreConsole = interceptConsoleOutput(shouldCaptureHelp(argv) ? io.stdout : io.stderr);
|
|
875
|
-
try {
|
|
876
|
-
cli.parse(argv);
|
|
877
|
-
return await (pendingResult ?? Promise.resolve(0));
|
|
878
|
-
} finally {
|
|
879
|
-
restoreConsole();
|
|
784
|
+
//#region src/cli/commands/lint/discovery.ts
|
|
785
|
+
async function resolveLintFiles(files, config, cwd) {
|
|
786
|
+
const gitignore = shouldFilterGitignoredFiles(config) ? new Gitignore() : void 0;
|
|
787
|
+
const candidates = files.length > 0 ? files : await discoverLintFiles(config, cwd, gitignore);
|
|
788
|
+
if (!gitignore || candidates.length === 0) return candidates;
|
|
789
|
+
const lintFiles = [];
|
|
790
|
+
for (const file of candidates) {
|
|
791
|
+
if (await gitignore.ignores(resolve(cwd, file))) continue;
|
|
792
|
+
lintFiles.push(file);
|
|
880
793
|
}
|
|
794
|
+
return lintFiles;
|
|
881
795
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
796
|
+
function collectGlobalIgnorePatterns(config) {
|
|
797
|
+
return normalizeConfig(config).flatMap((item) => isGlobalIgnoreItem(item) ? [...item.ignores] : []);
|
|
798
|
+
}
|
|
799
|
+
async function discoverLintFiles(config, cwd, gitignore) {
|
|
800
|
+
if (!hasDiscoveryFilePatterns(config)) return [];
|
|
801
|
+
const candidates = (await walkFiles(cwd, {
|
|
802
|
+
cwd,
|
|
803
|
+
gitignore,
|
|
804
|
+
ignoredPatterns: collectGlobalIgnorePatterns(config)
|
|
805
|
+
})).map((file) => normalizeRelativePath(cwd, file)).filter((file) => matchesDiscoveryFile(file, config, { cwd }));
|
|
806
|
+
return [...new Set(candidates)].sort();
|
|
807
|
+
}
|
|
808
|
+
function isGlobalIgnoreItem(item) {
|
|
809
|
+
const keys = Object.keys(item).filter((key) => item[key] !== void 0);
|
|
810
|
+
return item.ignores !== void 0 && keys.every((key) => key === "ignores" || key === "name");
|
|
811
|
+
}
|
|
812
|
+
function matchesIgnoredDirectory(relativePath, patterns) {
|
|
813
|
+
return patterns.some((pattern) => minimatch(relativePath, pattern, { dot: true }) || minimatch(`${relativePath}/`, pattern, { dot: true }) || minimatch(`${relativePath}/__alint__`, pattern, { dot: true }));
|
|
814
|
+
}
|
|
815
|
+
function normalizeRelativePath(cwd, filePath) {
|
|
816
|
+
return relative(cwd, filePath).replaceAll("\\", "/");
|
|
817
|
+
}
|
|
818
|
+
function shouldFilterGitignoredFiles(config) {
|
|
819
|
+
return normalizeConfig(config).some((item) => item.ignore?.gitignore === true);
|
|
820
|
+
}
|
|
821
|
+
async function shouldPruneDirectory(path, options) {
|
|
822
|
+
if (matchesIgnoredDirectory(normalizeRelativePath(options.cwd, path), options.ignoredPatterns)) return true;
|
|
823
|
+
return await options.gitignore?.ignores(path) === true;
|
|
824
|
+
}
|
|
825
|
+
async function walkFiles(root, options) {
|
|
826
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
827
|
+
const files = [];
|
|
828
|
+
for (const entry of entries) {
|
|
829
|
+
const path = resolve(root, entry.name);
|
|
830
|
+
if (entry.isDirectory()) {
|
|
831
|
+
if (!await shouldPruneDirectory(path, options)) files.push(...await walkFiles(path, options));
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
if (entry.isFile()) files.push(path);
|
|
889
835
|
}
|
|
836
|
+
return files;
|
|
890
837
|
}
|
|
838
|
+
//#endregion
|
|
839
|
+
//#region src/cli/commands/lint/errors.ts
|
|
891
840
|
function formatRunError(error, color) {
|
|
892
841
|
return `${color ? c.red("error") : "error"} ${formatRunErrorContext(error)}\n Rule running failed due to ${error.failure?.message ?? error.message}\n`;
|
|
893
842
|
}
|
|
@@ -901,37 +850,28 @@ function formatRunErrorContext(error) {
|
|
|
901
850
|
failure.ruleId
|
|
902
851
|
].filter(Boolean).join(" > ");
|
|
903
852
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
stdout.write(`${args.map(String).join(" ")}\n`);
|
|
912
|
-
};
|
|
913
|
-
const writeConsoleDir = (item, options) => {
|
|
914
|
-
stdout.write(`${inspect(item, options)}\n`);
|
|
915
|
-
};
|
|
916
|
-
cliConsole.debug = writeConsoleLine;
|
|
917
|
-
cliConsole.dir = writeConsoleDir;
|
|
918
|
-
console.info = writeConsoleLine;
|
|
919
|
-
cliConsole.log = writeConsoleLine;
|
|
920
|
-
return () => {
|
|
921
|
-
cliConsole.debug = originalConsoleDebug;
|
|
922
|
-
cliConsole.dir = originalConsoleDir;
|
|
923
|
-
console.info = originalConsoleInfo;
|
|
924
|
-
cliConsole.log = originalConsoleLog;
|
|
925
|
-
};
|
|
926
|
-
}
|
|
927
|
-
function isNodeError(error) {
|
|
928
|
-
return error instanceof Error && "code" in error;
|
|
853
|
+
//#endregion
|
|
854
|
+
//#region src/cli/commands/lint/runner.ts
|
|
855
|
+
function resolveConfigRunner(config) {
|
|
856
|
+
return normalizeConfig(config).reduce((merged, item) => item.runner ? {
|
|
857
|
+
...merged,
|
|
858
|
+
...item.runner
|
|
859
|
+
} : merged, void 0);
|
|
929
860
|
}
|
|
930
|
-
|
|
931
|
-
const
|
|
932
|
-
const
|
|
933
|
-
const
|
|
934
|
-
|
|
861
|
+
function resolveRunnerConfig(setupConfig, config, options) {
|
|
862
|
+
const cache = resolveRunnerCacheConfig(setupConfig.runner?.cache, config.runner?.cache, options);
|
|
863
|
+
const fileConcurrency = parsePositiveIntegerOption(options.fileConcurrency, "--file-concurrency");
|
|
864
|
+
const ruleConcurrency = parsePositiveIntegerOption(options.ruleConcurrency, "--rule-concurrency");
|
|
865
|
+
const timeoutMs = parsePositiveIntegerOption(options.timeoutMs, "--timeout-ms");
|
|
866
|
+
const runner = {
|
|
867
|
+
...setupConfig.runner ?? {},
|
|
868
|
+
...config.runner ?? {},
|
|
869
|
+
cache,
|
|
870
|
+
fileConcurrency: fileConcurrency ?? config.runner?.fileConcurrency ?? setupConfig.runner?.fileConcurrency,
|
|
871
|
+
ruleConcurrency: ruleConcurrency ?? config.runner?.ruleConcurrency ?? setupConfig.runner?.ruleConcurrency,
|
|
872
|
+
timeoutMs: timeoutMs ?? config.runner?.timeoutMs ?? setupConfig.runner?.timeoutMs
|
|
873
|
+
};
|
|
874
|
+
return Object.values(runner).some((value) => value !== void 0) ? runner : void 0;
|
|
935
875
|
}
|
|
936
876
|
function mergeRunnerCacheConfig(setupCache, configCache) {
|
|
937
877
|
if (configCache === void 0) return setupCache;
|
|
@@ -948,16 +888,6 @@ function parsePositiveIntegerOption(value, label) {
|
|
|
948
888
|
if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`${label} must be a positive integer.`);
|
|
949
889
|
return parsed;
|
|
950
890
|
}
|
|
951
|
-
async function resolveLintFiles(files, config, cwd) {
|
|
952
|
-
if (config.ignore?.gitignore !== true || files.length === 0) return files;
|
|
953
|
-
const gitignore = new Gitignore();
|
|
954
|
-
const lintFiles = [];
|
|
955
|
-
for (const file of files) {
|
|
956
|
-
if (await gitignore.ignores(resolve(cwd, file))) continue;
|
|
957
|
-
lintFiles.push(file);
|
|
958
|
-
}
|
|
959
|
-
return lintFiles;
|
|
960
|
-
}
|
|
961
891
|
function resolveRunnerCacheConfig(setupCache, configCache, options) {
|
|
962
892
|
if (options.cache === false) return false;
|
|
963
893
|
const configuredCache = mergeRunnerCacheConfig(setupCache, configCache);
|
|
@@ -967,36 +897,33 @@ function resolveRunnerCacheConfig(setupCache, configCache, options) {
|
|
|
967
897
|
} : { location: options.cacheLocation };
|
|
968
898
|
return configuredCache;
|
|
969
899
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
900
|
+
//#endregion
|
|
901
|
+
//#region src/cli/commands/lint/index.ts
|
|
902
|
+
const lint = defineCommand({
|
|
903
|
+
action: (context, files = [], options) => runLintCommand(files, options, context.io, context.interceptConsoleOutput),
|
|
904
|
+
alias: ["!"],
|
|
905
|
+
arguments: "[...files]",
|
|
906
|
+
default: true,
|
|
907
|
+
description: "Run alint",
|
|
908
|
+
name: "lint"
|
|
909
|
+
});
|
|
910
|
+
async function assertConfigExists(cwd, configPath) {
|
|
911
|
+
const resolvedConfigPath = resolve(cwd, configPath);
|
|
912
|
+
try {
|
|
913
|
+
if (!(await stat(resolvedConfigPath)).isFile()) throw new Error(`Config file "${configPath}" is not a file.`);
|
|
914
|
+
} catch (error) {
|
|
915
|
+
if (isNodeError(error) && error.code === "ENOENT") throw new Error(`Config file "${configPath}" does not exist.`);
|
|
916
|
+
throw error;
|
|
917
|
+
}
|
|
984
918
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
if (args[0] === "models" && args[1] === "ls" && args.length === 2) return runModelsListCommand(io);
|
|
988
|
-
if (args[0] === "models" && args[1] === "show" && args.length === 3) return runModelsShowCommand(args[2], io);
|
|
989
|
-
if (args[0] === "providers" && args[1] === "ls" && args.length === 2) return runProvidersListCommand(io);
|
|
990
|
-
if (args[0] === "providers" && args[1] === "show" && args.length === 3) return runProvidersShowCommand(args[2], io);
|
|
991
|
-
if (args[0] === "providers" && args[1] === "probe" && args.length === 2) return runProvidersProbeCommand(options, io);
|
|
992
|
-
io.stderr.write(`unknown config command: ${args.join(" ")}\n`);
|
|
993
|
-
return 2;
|
|
919
|
+
function isNodeError(error) {
|
|
920
|
+
return error instanceof Error && "code" in error;
|
|
994
921
|
}
|
|
995
|
-
async function
|
|
922
|
+
async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
996
923
|
if (options.config) await assertConfigExists(io.cwd, options.config);
|
|
997
924
|
const [setupConfig, config] = await Promise.all([loadMergedSetupConfig(io), loadAlintConfig(io.cwd, options.config)]);
|
|
998
925
|
const lintFiles = await resolveLintFiles(files, config, io.cwd);
|
|
999
|
-
const runner = resolveRunnerConfig(setupConfig, config, options);
|
|
926
|
+
const runner = resolveRunnerConfig(setupConfig, { runner: resolveConfigRunner(config) }, options);
|
|
1000
927
|
const progress = shouldEnableProgress(options, io) ? createCliProgressReporter({
|
|
1001
928
|
color: io.stderr.isTTY === true,
|
|
1002
929
|
columns: io.stderr.columns ?? 80,
|
|
@@ -1030,70 +957,395 @@ async function runDefaultCommand(files, options, io) {
|
|
|
1030
957
|
io.stdout.write(formatDiagnostics(options.format, result, { color: io.stdout.isTTY === true }));
|
|
1031
958
|
return result.diagnostics.length > 0 ? 1 : 0;
|
|
1032
959
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
return
|
|
1036
|
-
}
|
|
1037
|
-
async function runModelsProbeCommand(options, io) {
|
|
1038
|
-
if (!options.endpoint) {
|
|
1039
|
-
io.stderr.write("config models probe requires --endpoint.\n");
|
|
1040
|
-
return 2;
|
|
1041
|
-
}
|
|
1042
|
-
try {
|
|
1043
|
-
const models = await probeModels(options.endpoint, parseHeaderList(toArray(options.providerHeader)) ?? {});
|
|
1044
|
-
io.stdout.write(`${models.join("\n")}${models.length > 0 ? "\n" : ""}`);
|
|
1045
|
-
return 0;
|
|
1046
|
-
} catch (error) {
|
|
1047
|
-
io.stderr.write(`failed to probe models: ${errorMessageFrom(error) ?? String(error)}\n`);
|
|
1048
|
-
return 2;
|
|
1049
|
-
}
|
|
960
|
+
function shouldEnableProgress(options, io) {
|
|
961
|
+
if (options.progress !== void 0) return options.progress;
|
|
962
|
+
return options.format === "stylish" && io.stderr.isTTY === true;
|
|
1050
963
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
return 0;
|
|
964
|
+
//#endregion
|
|
965
|
+
//#region src/cli/commands/setup/interactive.ts
|
|
966
|
+
const nonTtyMessage = "interactive setup requires a TTY. Use -N/--no-interactive with --provider-id and --provider-endpoint.\n";
|
|
967
|
+
const backValue = "__alint_back__";
|
|
968
|
+
function formatProbeModelsFailure(endpoint, error) {
|
|
969
|
+
const hint = endpoint.startsWith("https://localhost:11434") ? " Ollama usually uses http://localhost:11434/v1." : "";
|
|
970
|
+
return `Could not probe models: ${errorMessageFrom(error)}.${hint}`;
|
|
1059
971
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
return 0;
|
|
972
|
+
function isBackInput(value) {
|
|
973
|
+
return value.trim() === "..";
|
|
1063
974
|
}
|
|
1064
|
-
async function
|
|
1065
|
-
if (
|
|
1066
|
-
io.stderr.write(
|
|
975
|
+
async function runInteractiveSetup(io) {
|
|
976
|
+
if (io.stdin?.isTTY !== true || io.stdout.isTTY !== true) {
|
|
977
|
+
io.stderr.write(nonTtyMessage);
|
|
1067
978
|
return 2;
|
|
1068
979
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
980
|
+
const prompts = await import("@clack/prompts");
|
|
981
|
+
const cancelPrompt = () => {
|
|
982
|
+
prompts.cancel("Setup cancelled.");
|
|
983
|
+
return 1;
|
|
984
|
+
};
|
|
985
|
+
prompts.intro("alint setup");
|
|
986
|
+
const draft = {};
|
|
987
|
+
let step = "scope";
|
|
988
|
+
while (true) {
|
|
989
|
+
if (step === "scope") {
|
|
990
|
+
const scope = await prompts.select({
|
|
991
|
+
message: "Where should alint write setup config?",
|
|
992
|
+
options: [{
|
|
993
|
+
label: "Global",
|
|
994
|
+
value: "global"
|
|
995
|
+
}, {
|
|
996
|
+
label: "Local project",
|
|
997
|
+
value: "local"
|
|
998
|
+
}]
|
|
999
|
+
});
|
|
1000
|
+
if (prompts.isCancel(scope)) return cancelPrompt();
|
|
1001
|
+
draft.scope = scope;
|
|
1002
|
+
step = "source";
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
if (step === "source") {
|
|
1006
|
+
const source = await prompts.select({
|
|
1007
|
+
message: "Choose provider setup mode.",
|
|
1008
|
+
options: withBackOption([
|
|
1009
|
+
{
|
|
1010
|
+
label: "Custom OpenAI-compatible provider",
|
|
1011
|
+
value: "custom"
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
label: "Ollama",
|
|
1015
|
+
value: "ollama"
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
label: "Manual model entry",
|
|
1019
|
+
value: "manual"
|
|
1020
|
+
}
|
|
1021
|
+
])
|
|
1022
|
+
});
|
|
1023
|
+
if (prompts.isCancel(source)) return cancelPrompt();
|
|
1024
|
+
if (source === backValue) {
|
|
1025
|
+
step = "scope";
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
draft.source = source;
|
|
1029
|
+
step = "endpoint";
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
if (step === "endpoint") {
|
|
1033
|
+
const endpoint = await promptEndpoint(prompts, draft.source ?? "custom");
|
|
1034
|
+
if (prompts.isCancel(endpoint)) return cancelPrompt();
|
|
1035
|
+
if (typeof endpoint !== "string") return cancelPrompt();
|
|
1036
|
+
if (isBackInput(endpoint)) {
|
|
1037
|
+
step = "source";
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
draft.endpoint = endpoint;
|
|
1041
|
+
step = "providerId";
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
if (step === "providerId") {
|
|
1045
|
+
const existingConfig = await loadSetupConfig(getConfigPath(io, draft.scope ?? "global"));
|
|
1046
|
+
const providerId = await prompts.text({
|
|
1047
|
+
defaultValue: draft.providerId ?? createProviderId(draft.endpoint ?? "", new Set(existingConfig.providers.map((provider) => provider.id))),
|
|
1048
|
+
message: "Provider id",
|
|
1049
|
+
placeholder: "Type .. to go back",
|
|
1050
|
+
validate: (value) => isBackInput(value ?? "") || (value ?? "").trim().length > 0 ? void 0 : "Provider id is required."
|
|
1051
|
+
});
|
|
1052
|
+
if (prompts.isCancel(providerId)) return cancelPrompt();
|
|
1053
|
+
if (typeof providerId !== "string") return cancelPrompt();
|
|
1054
|
+
if (isBackInput(providerId)) {
|
|
1055
|
+
step = "endpoint";
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
draft.providerId = providerId;
|
|
1059
|
+
step = "headers";
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
if (step === "headers") {
|
|
1063
|
+
const headerInput = await prompts.text({
|
|
1064
|
+
defaultValue: draft.headerInput ?? "",
|
|
1065
|
+
message: "Headers",
|
|
1066
|
+
placeholder: "Authorization=Bearer token, X-Test=true; type .. to go back",
|
|
1067
|
+
validate: (value) => {
|
|
1068
|
+
if (isBackInput(value ?? "")) return;
|
|
1069
|
+
try {
|
|
1070
|
+
parseHeaderList(splitHeaderInput(value ?? ""));
|
|
1071
|
+
return;
|
|
1072
|
+
} catch {
|
|
1073
|
+
return "Headers must be comma-separated Key=Value entries.";
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
if (prompts.isCancel(headerInput)) return cancelPrompt();
|
|
1078
|
+
if (typeof headerInput !== "string") return cancelPrompt();
|
|
1079
|
+
if (isBackInput(headerInput)) {
|
|
1080
|
+
step = "providerId";
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
draft.headerInput = headerInput;
|
|
1084
|
+
draft.headers = parseHeaderList(splitHeaderInput(headerInput));
|
|
1085
|
+
draft.discoveredModels = draft.source === "manual" ? [] : await probeModelsWithSpinner(prompts, draft.endpoint ?? "", draft.headers);
|
|
1086
|
+
step = "models";
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (step === "models") {
|
|
1090
|
+
const selectedModels = await promptModels(prompts, draft.discoveredModels ?? []);
|
|
1091
|
+
if (prompts.isCancel(selectedModels)) return cancelPrompt();
|
|
1092
|
+
if (selectedModels === backValue) {
|
|
1093
|
+
step = "headers";
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
1096
|
+
if (!Array.isArray(selectedModels)) return cancelPrompt();
|
|
1097
|
+
draft.selectedModels = selectedModels;
|
|
1098
|
+
step = "defaultAlias";
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
if (step === "defaultAlias") {
|
|
1102
|
+
const addDefaultAlias = await prompts.select({
|
|
1103
|
+
message: `Add alias "default" to ${draft.selectedModels?.[0]}?`,
|
|
1104
|
+
options: withBackOption([{
|
|
1105
|
+
label: "Yes",
|
|
1106
|
+
value: "yes"
|
|
1107
|
+
}, {
|
|
1108
|
+
label: "No",
|
|
1109
|
+
value: "no"
|
|
1110
|
+
}])
|
|
1111
|
+
});
|
|
1112
|
+
if (prompts.isCancel(addDefaultAlias)) return cancelPrompt();
|
|
1113
|
+
if (addDefaultAlias === backValue) {
|
|
1114
|
+
step = "models";
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
1117
|
+
draft.addDefaultAlias = addDefaultAlias === "yes";
|
|
1118
|
+
step = "confirm";
|
|
1119
|
+
continue;
|
|
1120
|
+
}
|
|
1121
|
+
const nextProvider = createProviderConfig((draft.providerId ?? "").trim(), (draft.endpoint ?? "").trim(), draft.headers, draft.selectedModels ?? [], draft.addDefaultAlias ?? true);
|
|
1122
|
+
const confirmed = await prompts.select({
|
|
1123
|
+
message: [
|
|
1124
|
+
`Write ${draft.scope} setup config?`,
|
|
1125
|
+
`Provider: ${nextProvider.id}`,
|
|
1126
|
+
`Endpoint: ${nextProvider.endpoint}`,
|
|
1127
|
+
`Models: ${(draft.selectedModels ?? []).join(", ")}`
|
|
1128
|
+
].join("\n"),
|
|
1129
|
+
options: withBackOption([{
|
|
1130
|
+
label: "Yes",
|
|
1131
|
+
value: "yes"
|
|
1132
|
+
}, {
|
|
1133
|
+
label: "No",
|
|
1134
|
+
value: "no"
|
|
1135
|
+
}])
|
|
1136
|
+
});
|
|
1137
|
+
if (prompts.isCancel(confirmed)) return cancelPrompt();
|
|
1138
|
+
if (confirmed === backValue) {
|
|
1139
|
+
step = "defaultAlias";
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
if (confirmed === "no") return cancelPrompt();
|
|
1143
|
+
const configPath = getConfigPath(io, draft.scope ?? "global");
|
|
1144
|
+
await writeSetupConfig(configPath, mergeSetupConfigs(await loadSetupConfig(configPath), {
|
|
1145
|
+
providers: [nextProvider],
|
|
1146
|
+
version: 1
|
|
1147
|
+
}));
|
|
1148
|
+
prompts.outro(`Wrote ${configPath}`);
|
|
1072
1149
|
return 0;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
function withBackOption(options) {
|
|
1153
|
+
return [...options, {
|
|
1154
|
+
label: "Back",
|
|
1155
|
+
value: backValue
|
|
1156
|
+
}];
|
|
1157
|
+
}
|
|
1158
|
+
function createProviderConfig(providerId, endpoint, headers, modelIds, addDefaultAlias) {
|
|
1159
|
+
return {
|
|
1160
|
+
endpoint,
|
|
1161
|
+
headers,
|
|
1162
|
+
id: providerId,
|
|
1163
|
+
models: modelIds.map((modelId, index) => ({
|
|
1164
|
+
aliases: index === 0 && addDefaultAlias ? ["default"] : void 0,
|
|
1165
|
+
id: modelId,
|
|
1166
|
+
name: modelId
|
|
1167
|
+
})),
|
|
1168
|
+
type: "openai-compatible"
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function getConfigPath(io, scope) {
|
|
1172
|
+
return scope === "local" ? getProjectSetupConfigPath(io.cwd) : getGlobalSetupConfigPath(io.env ?? process.env);
|
|
1173
|
+
}
|
|
1174
|
+
async function probeModelsWithSpinner(prompts, endpoint, headers) {
|
|
1175
|
+
const spinner = prompts.spinner();
|
|
1176
|
+
spinner.start("Probing models");
|
|
1177
|
+
try {
|
|
1178
|
+
const models = await probeModels(endpoint, headers ?? {});
|
|
1179
|
+
spinner.stop(models.length > 0 ? `Found ${models.length} models` : "No models discovered");
|
|
1180
|
+
return models;
|
|
1073
1181
|
} catch (error) {
|
|
1074
|
-
|
|
1075
|
-
return
|
|
1182
|
+
spinner.stop(formatProbeModelsFailure(endpoint, error));
|
|
1183
|
+
return [];
|
|
1076
1184
|
}
|
|
1077
1185
|
}
|
|
1078
|
-
async function
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1186
|
+
async function promptEndpoint(prompts, source) {
|
|
1187
|
+
return prompts.text({
|
|
1188
|
+
defaultValue: source === "ollama" ? "http://localhost:11434/v1" : void 0,
|
|
1189
|
+
message: "Provider endpoint",
|
|
1190
|
+
placeholder: source === "ollama" ? "http://localhost:11434/v1; type .. to go back" : "https://example.test/v1; type .. to go back",
|
|
1191
|
+
validate: (value) => isBackInput(value ?? "") || (value ?? "").trim().length > 0 ? void 0 : "Provider endpoint is required."
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
async function promptModels(prompts, discoveredModels) {
|
|
1195
|
+
if (discoveredModels.length > 0) {
|
|
1196
|
+
const selectedModels = await prompts.multiselect({
|
|
1197
|
+
message: "Select models",
|
|
1198
|
+
options: withBackOption(discoveredModels.map((model) => ({
|
|
1199
|
+
label: model,
|
|
1200
|
+
value: model
|
|
1201
|
+
}))),
|
|
1202
|
+
required: true
|
|
1203
|
+
});
|
|
1204
|
+
return Array.isArray(selectedModels) && selectedModels.includes(backValue) ? backValue : selectedModels;
|
|
1083
1205
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1206
|
+
const modelInput = await prompts.text({
|
|
1207
|
+
message: "Models",
|
|
1208
|
+
placeholder: "qwen:8b, qwen:32b; type .. to go back",
|
|
1209
|
+
validate: (value) => isBackInput(value ?? "") || splitModelInput(value ?? "").length > 0 ? void 0 : "At least one model is required."
|
|
1210
|
+
});
|
|
1211
|
+
if (prompts.isCancel(modelInput)) return modelInput;
|
|
1212
|
+
return isBackInput(modelInput) ? backValue : splitModelInput(modelInput);
|
|
1086
1213
|
}
|
|
1087
|
-
function
|
|
1088
|
-
return
|
|
1214
|
+
function splitHeaderInput(value) {
|
|
1215
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
1089
1216
|
}
|
|
1090
|
-
function
|
|
1091
|
-
|
|
1092
|
-
|
|
1217
|
+
function splitModelInput(value) {
|
|
1218
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
1219
|
+
}
|
|
1220
|
+
//#endregion
|
|
1221
|
+
//#region src/cli/commands/setup/index.ts
|
|
1222
|
+
const setup = defineCommand({
|
|
1223
|
+
action: (context, options) => runSetupCommand({
|
|
1224
|
+
...options,
|
|
1225
|
+
noInteractive: context.setupNoInteractive
|
|
1226
|
+
}, context.io),
|
|
1227
|
+
description: "Write alint provider configuration",
|
|
1228
|
+
name: "setup",
|
|
1229
|
+
options: [
|
|
1230
|
+
{
|
|
1231
|
+
description: "Write project-local config",
|
|
1232
|
+
flags: "--local"
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
description: "Disable interactive setup",
|
|
1236
|
+
flags: "-N, --no-interactive"
|
|
1237
|
+
},
|
|
1238
|
+
{
|
|
1239
|
+
description: "Provider endpoint",
|
|
1240
|
+
flags: "--provider-endpoint <endpoint>"
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
description: "Provider id",
|
|
1244
|
+
flags: "--provider-id <id>"
|
|
1245
|
+
},
|
|
1246
|
+
{
|
|
1247
|
+
description: "Provider model",
|
|
1248
|
+
flags: "--provider-model <model>"
|
|
1249
|
+
},
|
|
1250
|
+
{
|
|
1251
|
+
description: "Provider header",
|
|
1252
|
+
flags: "--provider-header <Key=Value>"
|
|
1253
|
+
}
|
|
1254
|
+
]
|
|
1255
|
+
});
|
|
1256
|
+
function createSetupConfig(providerId, providerEndpoint, options) {
|
|
1257
|
+
const models = toArray(options.providerModel).map((model) => ({
|
|
1258
|
+
id: model,
|
|
1259
|
+
name: model
|
|
1260
|
+
}));
|
|
1261
|
+
return {
|
|
1262
|
+
providers: [{
|
|
1263
|
+
endpoint: providerEndpoint,
|
|
1264
|
+
headers: parseHeaderList(toArray(options.providerHeader)),
|
|
1265
|
+
id: providerId,
|
|
1266
|
+
models,
|
|
1267
|
+
type: "openai-compatible"
|
|
1268
|
+
}],
|
|
1269
|
+
version: 1
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
async function runSetupCommand(options, io) {
|
|
1273
|
+
if (!options.providerEndpoint) {
|
|
1274
|
+
if (options.noInteractive !== true) return runInteractiveSetup({
|
|
1275
|
+
...io,
|
|
1276
|
+
stdin: io.stdin ?? process.stdin
|
|
1277
|
+
});
|
|
1278
|
+
io.stderr.write("setup requires --provider-endpoint in --no-interactive mode.\n");
|
|
1279
|
+
return 2;
|
|
1280
|
+
}
|
|
1281
|
+
if (!options.providerId) {
|
|
1282
|
+
io.stderr.write("setup requires --provider-id in --no-interactive mode.\n");
|
|
1283
|
+
return 2;
|
|
1284
|
+
}
|
|
1285
|
+
const setupConfigPath = options.local ? getProjectSetupConfigPath(io.cwd) : getGlobalSetupConfigPath(io.env ?? process.env);
|
|
1286
|
+
await writeSetupConfig(setupConfigPath, mergeSetupConfigs(await loadSetupConfig(setupConfigPath), createSetupConfig(options.providerId, options.providerEndpoint, options)));
|
|
1287
|
+
return 0;
|
|
1093
1288
|
}
|
|
1094
1289
|
function toArray(value) {
|
|
1095
1290
|
if (value === void 0) return [];
|
|
1096
1291
|
return (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
|
|
1097
1292
|
}
|
|
1098
1293
|
//#endregion
|
|
1294
|
+
//#region src/cli/commands/index.ts
|
|
1295
|
+
const commandTree = [
|
|
1296
|
+
setup,
|
|
1297
|
+
config,
|
|
1298
|
+
lint
|
|
1299
|
+
];
|
|
1300
|
+
//#endregion
|
|
1301
|
+
//#region src/cli/cli.ts
|
|
1302
|
+
async function executeCli(argv, io) {
|
|
1303
|
+
const cli = cac("alint");
|
|
1304
|
+
const setupNoInteractive = argv.includes("-N") || argv.includes("--no-interactive");
|
|
1305
|
+
let pendingResult;
|
|
1306
|
+
const setPendingResult = (result) => {
|
|
1307
|
+
pendingResult = result;
|
|
1308
|
+
return result;
|
|
1309
|
+
};
|
|
1310
|
+
cli.option("--no-cache", "Disable cache for this run").option("--cache-location <path>", "Path to the alint cache file or directory").option("--config <path>", "Path to alint config file").option("--file-concurrency <count>", "Number of files to lint concurrently").option("--format <format>", "Reporter format", { default: "stylish" }).option("--model <model>", "Force a model override").option("--progress", "Show run progress").option("--rule-concurrency <count>", "Number of rules to run concurrently within a file").option("--timeout-ms <ms>", "Rule execution timeout in milliseconds").help();
|
|
1311
|
+
registerCommandTree(cli, commandTree, {
|
|
1312
|
+
interceptConsoleOutput,
|
|
1313
|
+
io,
|
|
1314
|
+
setupNoInteractive
|
|
1315
|
+
}, setPendingResult);
|
|
1316
|
+
const restoreConsole = interceptConsoleOutput(shouldCaptureHelp(argv) ? io.stdout : io.stderr);
|
|
1317
|
+
try {
|
|
1318
|
+
cli.parse(argv);
|
|
1319
|
+
return await (pendingResult ?? Promise.resolve(0));
|
|
1320
|
+
} finally {
|
|
1321
|
+
restoreConsole();
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
function interceptConsoleOutput(stdout) {
|
|
1325
|
+
const cliConsole = globalThis.console;
|
|
1326
|
+
const originalConsoleDebug = cliConsole.debug;
|
|
1327
|
+
const originalConsoleDir = cliConsole.dir;
|
|
1328
|
+
const originalConsoleInfo = console.info;
|
|
1329
|
+
const originalConsoleLog = cliConsole.log;
|
|
1330
|
+
const writeConsoleLine = (...args) => {
|
|
1331
|
+
stdout.write(`${args.map(String).join(" ")}\n`);
|
|
1332
|
+
};
|
|
1333
|
+
const writeConsoleDir = (item, options) => {
|
|
1334
|
+
stdout.write(`${inspect(item, options)}\n`);
|
|
1335
|
+
};
|
|
1336
|
+
cliConsole.debug = writeConsoleLine;
|
|
1337
|
+
cliConsole.dir = writeConsoleDir;
|
|
1338
|
+
console.info = writeConsoleLine;
|
|
1339
|
+
cliConsole.log = writeConsoleLine;
|
|
1340
|
+
return () => {
|
|
1341
|
+
cliConsole.debug = originalConsoleDebug;
|
|
1342
|
+
cliConsole.dir = originalConsoleDir;
|
|
1343
|
+
console.info = originalConsoleInfo;
|
|
1344
|
+
cliConsole.log = originalConsoleLog;
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
function shouldCaptureHelp(argv) {
|
|
1348
|
+
return argv.includes("--help") || argv.includes("-h");
|
|
1349
|
+
}
|
|
1350
|
+
//#endregion
|
|
1099
1351
|
export { formatJson as i, formatDiagnostics as n, formatStylish as r, executeCli as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Diagnostic, RunResult } from "@alint-js/core";
|
|
2
2
|
|
|
3
|
-
//#region src/cli/
|
|
3
|
+
//#region src/cli/types.d.ts
|
|
4
4
|
interface CliIo {
|
|
5
5
|
cwd: string;
|
|
6
6
|
env?: NodeJS.ProcessEnv;
|
|
@@ -15,6 +15,8 @@ interface CliWritable {
|
|
|
15
15
|
isTTY?: boolean;
|
|
16
16
|
write: (chunk: string) => unknown;
|
|
17
17
|
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/cli/cli.d.ts
|
|
18
20
|
declare function executeCli(argv: string[], io: CliIo): Promise<number>;
|
|
19
21
|
//#endregion
|
|
20
22
|
//#region src/cli/reporters/index.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-
|
|
1
|
+
import { i as formatJson, n as formatDiagnostics, r as formatStylish, t as executeCli } from "./cli-C4PnKXoK.mjs";
|
|
2
2
|
export { executeCli, formatDiagnostics, formatJson, formatStylish };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
"cac": "^7.0.0",
|
|
22
22
|
"cli-spinners": "^3.4.0",
|
|
23
23
|
"gitignore-fs": "^2.2.3",
|
|
24
|
+
"minimatch": "^10.2.5",
|
|
24
25
|
"pathe": "^2.0.3",
|
|
25
26
|
"table": "^6.9.0",
|
|
26
27
|
"tinyrainbow": "^3.1.0",
|
|
27
|
-
"@alint-js/config": "0.0.
|
|
28
|
-
"@alint-js/core": "0.0.
|
|
28
|
+
"@alint-js/config": "0.0.6",
|
|
29
|
+
"@alint-js/core": "0.0.6"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/node": "^26.0.1",
|