@alint-js/cli 0.1.4 → 0.2.0
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/README.md +8 -4
- package/dist/bin/index.mjs +1 -1
- package/dist/{cli-DUyZBCTT.mjs → cli-3Ov9-ZVf.mjs} +406 -77
- package/dist/index.mjs +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -184,6 +184,8 @@ alint config inspect src/index.ts
|
|
|
184
184
|
alint config providers list
|
|
185
185
|
alint config providers show openrouter
|
|
186
186
|
alint config models list
|
|
187
|
+
alint config models list --with-speed
|
|
188
|
+
alint config models list --with-speed --with-speed-concurrency openrouter=10 --with-speed-concurrency ollama=1
|
|
187
189
|
alint config models show ollama/qwen
|
|
188
190
|
alint config models probe --endpoint http://localhost:11434/v1
|
|
189
191
|
alint config models rm qwen --provider ollama
|
|
@@ -194,6 +196,8 @@ When a model ID exists under multiple providers, qualify it as `<provider>/<mode
|
|
|
194
196
|
|
|
195
197
|
`models rm` removes one exact configured model. `models prune` probes provider model endpoints and destructively removes configured IDs that are no longer reported. Interactive prune asks for confirmation; scripts must pass `-N --yes`.
|
|
196
198
|
|
|
199
|
+
`models list --with-speed` sends live streamed requests to every configured model. It reports median repeat and non-repeat latency, non-repeat output throughput, and successful attempts. Each model receives one repeat warm-up, three measured repeat requests, and three non-repeat requests. Model jobs run concurrently within independent provider limits: OpenRouter defaults to 20, while CLIProxyAPI and other providers default to 2. Repeat `--with-speed-concurrency <provider-id>=<limit>` to override one or more configured providers. Requests within one model remain serial so its repeat and non-repeat cache measurements do not overlap. An unavailable model is shown as `errored` without preventing the remaining models from running. On a TTY, spinners and a refreshable table show active models, phases, and samples. Each request uses the configured runner timeout, or 60 seconds when none is configured. This command consumes provider tokens and may incur charges.
|
|
200
|
+
|
|
197
201
|
Save machine-readable output and inspect it later without rerunning model calls:
|
|
198
202
|
|
|
199
203
|
```bash
|
|
@@ -339,7 +343,7 @@ Reference the directory through the same static `plugins` table:
|
|
|
339
343
|
```toml
|
|
340
344
|
[[config.group]]
|
|
341
345
|
files = [ "src/**/*.py" ]
|
|
342
|
-
language = "
|
|
346
|
+
language = "plaintext"
|
|
343
347
|
|
|
344
348
|
[config.group.plugins]
|
|
345
349
|
arch = "./rules/architecture"
|
|
@@ -364,7 +368,7 @@ Rule severities follow the familiar lint convention:
|
|
|
364
368
|
- `"warn"` or `1` reports a warning.
|
|
365
369
|
- `"error"` or `2` reports an error.
|
|
366
370
|
|
|
367
|
-
Flat configs can analyze non-JavaScript files by selecting `
|
|
371
|
+
Flat configs can analyze non-JavaScript files by selecting `plaintext`. Language ids follow [VS Code's language identifiers](https://code.visualstudio.com/docs/languages/identifiers), so a plugin that registers a language should use the same id:
|
|
368
372
|
|
|
369
373
|
```ts
|
|
370
374
|
import docsPlugin from '@your-alint-config/docs-rules'
|
|
@@ -374,7 +378,7 @@ import { defineConfig } from '@alint-js/cli'
|
|
|
374
378
|
export default defineConfig([
|
|
375
379
|
{
|
|
376
380
|
files: ['docs/**/*.md', '**/*.txt'],
|
|
377
|
-
language: '
|
|
381
|
+
language: 'plaintext',
|
|
378
382
|
plugins: {
|
|
379
383
|
docs: docsPlugin,
|
|
380
384
|
},
|
|
@@ -522,7 +526,7 @@ defineRule({
|
|
|
522
526
|
| [`@alint-js/agent-pi`](https://github.com/moeru-ai/alint/tree/main/packages/agent-pi) | Pi-backed `AgentAdapter`. |
|
|
523
527
|
| [`@alint-js/plugin-example`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example) | Example TypeScript/JavaScript model-backed rules. |
|
|
524
528
|
| [`@alint-js/plugin-example-agent`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example-agent) | Example plugin for framework-agnostic agentic rules. |
|
|
525
|
-
| [`@alint-js/plugin-example-go`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example-go) | Example semantic Go review plugin using `
|
|
529
|
+
| [`@alint-js/plugin-example-go`](https://github.com/moeru-ai/alint/tree/main/packages/plugin-example-go) | Example semantic Go review plugin using `plaintext`. |
|
|
526
530
|
|
|
527
531
|
## Documentation Automation
|
|
528
532
|
|
package/dist/bin/index.mjs
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
3
|
import { cac } from "cac";
|
|
4
|
-
import { appendFile, mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
4
|
+
import { appendFile, mkdir, opendir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
5
5
|
import { addProviderModels, getGlobalSetupConfigPath, getProjectSetupConfigPath, getStatsDir, installStaticPlugins, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, pruneProviderModels, removeProviderModels, replaceSetupProvider, setProviderEndpoint, setProviderHeader, unsetProviderHeader, writeSetupConfig } from "@alint-js/config";
|
|
6
|
-
import { AlintRunCancelledError, AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForDirectory, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
6
|
+
import { AlintRunCancelledError, AlintRunError, benchmarkModels, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForDirectory, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
7
7
|
import { isAbsolute, join, relative, resolve } from "pathe";
|
|
8
|
-
import { getBorderCharacters, table } from "table";
|
|
9
8
|
import { errorMessageFrom } from "@moeru/std/error";
|
|
9
|
+
import { getBorderCharacters, table } from "table";
|
|
10
10
|
import { createColors } from "tinyrainbow";
|
|
11
11
|
import cliSpinners from "cli-spinners";
|
|
12
|
+
import fastStringWidth from "fast-string-width";
|
|
12
13
|
import { relative as relative$1 } from "node:path";
|
|
14
|
+
import { formatDuration, intervalToDuration } from "date-fns";
|
|
13
15
|
import fastStringTruncatedWidth from "fast-string-truncated-width";
|
|
14
|
-
import fastStringWidth from "fast-string-width";
|
|
15
16
|
import Gitignore from "gitignore-fs";
|
|
16
17
|
import { Minimatch, minimatch } from "minimatch";
|
|
17
18
|
import { errorMessageFrom as errorMessageFrom$1 } from "@moeru/std";
|
|
18
19
|
//#region package.json
|
|
19
|
-
var version = "0.
|
|
20
|
+
var version = "0.2.0";
|
|
20
21
|
//#endregion
|
|
21
22
|
//#region src/cli/output.ts
|
|
22
23
|
function escapeLineValue(value) {
|
|
@@ -218,6 +219,7 @@ function shouldSkipOptionValue(arg) {
|
|
|
218
219
|
"--rule-concurrency",
|
|
219
220
|
"--since",
|
|
220
221
|
"--timeout-ms",
|
|
222
|
+
"--with-speed-concurrency",
|
|
221
223
|
"-c",
|
|
222
224
|
"-f",
|
|
223
225
|
"-l"
|
|
@@ -246,7 +248,43 @@ async function runConfigInspectCommand(path, configPath, io) {
|
|
|
246
248
|
return 0;
|
|
247
249
|
}
|
|
248
250
|
//#endregion
|
|
251
|
+
//#region src/cli/reporters/progress/bar.ts
|
|
252
|
+
const minBarWidth = 4;
|
|
253
|
+
const maxBarWidth = 16;
|
|
254
|
+
const animationThreshold = .4;
|
|
255
|
+
function formatMiniBar(options) {
|
|
256
|
+
if (options.planned <= 0 || options.width < minBarWidth) return "";
|
|
257
|
+
const width = Math.min(Math.max(Math.floor(options.width), minBarWidth), maxBarWidth);
|
|
258
|
+
const ratio = Math.min(Math.max(options.completed / options.planned, 0), 1);
|
|
259
|
+
const completeCells = Math.min(Math.floor(ratio * width), width);
|
|
260
|
+
if (width - completeCells === 0) return `[${"█".repeat(width)}]`;
|
|
261
|
+
if (ratio < animationThreshold) return formatStaticBar(completeCells, width);
|
|
262
|
+
const frontierIndex = completeCells;
|
|
263
|
+
const phase = positiveModulo(options.tick, frontierIndex + 2);
|
|
264
|
+
if (phase === frontierIndex + 1) return formatStaticBar(completeCells, width);
|
|
265
|
+
return `[${Array.from({ length: width }, (_, index) => {
|
|
266
|
+
if (phase === 0) {
|
|
267
|
+
if (index === 0) return "▓";
|
|
268
|
+
if (index <= frontierIndex) return "█";
|
|
269
|
+
return "░";
|
|
270
|
+
}
|
|
271
|
+
if (index < phase) return "█";
|
|
272
|
+
if (index === phase) return "▓";
|
|
273
|
+
if (index === phase + 1 && index <= frontierIndex) return "░";
|
|
274
|
+
if (index <= frontierIndex) return "█";
|
|
275
|
+
return "░";
|
|
276
|
+
}).join("")}]`;
|
|
277
|
+
}
|
|
278
|
+
function formatStaticBar(completeCells, width) {
|
|
279
|
+
return `[${"█".repeat(completeCells)}${"░".repeat(width - completeCells)}]`;
|
|
280
|
+
}
|
|
281
|
+
function positiveModulo(value, divisor) {
|
|
282
|
+
return (Math.floor(value) % divisor + divisor) % divisor;
|
|
283
|
+
}
|
|
284
|
+
//#endregion
|
|
249
285
|
//#region src/cli/provider-registry.ts
|
|
286
|
+
const colors$4 = createColors({ force: true });
|
|
287
|
+
const defaultBenchmarkConcurrency = 2;
|
|
250
288
|
function formatDuplicateModelIdentity(identity) {
|
|
251
289
|
return [
|
|
252
290
|
`model "${escapeLineValue(identity)}" is configured more than once.`,
|
|
@@ -256,6 +294,7 @@ function formatDuplicateModelIdentity(identity) {
|
|
|
256
294
|
}
|
|
257
295
|
const providerSetupSources = [
|
|
258
296
|
{
|
|
297
|
+
benchmarkConcurrency: 2,
|
|
259
298
|
defaultEndpoint: "http://127.0.0.1:8317/v1",
|
|
260
299
|
defaultProviderId: "CLIProxyAPI",
|
|
261
300
|
label: "CLIProxyAPI",
|
|
@@ -263,11 +302,21 @@ const providerSetupSources = [
|
|
|
263
302
|
value: "cliProxyApi"
|
|
264
303
|
},
|
|
265
304
|
{
|
|
305
|
+
benchmarkConcurrency: 2,
|
|
266
306
|
label: "Custom OpenAI-compatible provider",
|
|
267
307
|
probeModels: true,
|
|
268
308
|
value: "custom"
|
|
269
309
|
},
|
|
270
310
|
{
|
|
311
|
+
benchmarkConcurrency: 20,
|
|
312
|
+
defaultEndpoint: "https://openrouter.ai/api/v1",
|
|
313
|
+
defaultProviderId: "openrouter",
|
|
314
|
+
label: "OpenRouter",
|
|
315
|
+
probeModels: true,
|
|
316
|
+
value: "openrouter"
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
benchmarkConcurrency: 2,
|
|
271
320
|
defaultEndpoint: "https://api.cerebras.ai/v1",
|
|
272
321
|
defaultProviderId: "cerebras",
|
|
273
322
|
label: "Cerebras",
|
|
@@ -275,6 +324,7 @@ const providerSetupSources = [
|
|
|
275
324
|
value: "cerebras"
|
|
276
325
|
},
|
|
277
326
|
{
|
|
327
|
+
benchmarkConcurrency: 2,
|
|
278
328
|
defaultEndpoint: "https://api.groq.com/openai/v1",
|
|
279
329
|
defaultProviderId: "groq",
|
|
280
330
|
label: "Groq",
|
|
@@ -282,12 +332,14 @@ const providerSetupSources = [
|
|
|
282
332
|
value: "groq"
|
|
283
333
|
},
|
|
284
334
|
{
|
|
335
|
+
benchmarkConcurrency: 2,
|
|
285
336
|
defaultEndpoint: "http://localhost:11434/v1",
|
|
286
337
|
label: "Ollama",
|
|
287
338
|
probeModels: true,
|
|
288
339
|
value: "ollama"
|
|
289
340
|
},
|
|
290
341
|
{
|
|
342
|
+
benchmarkConcurrency: 2,
|
|
291
343
|
label: "Manual model entry",
|
|
292
344
|
probeModels: false,
|
|
293
345
|
value: "manual"
|
|
@@ -353,6 +405,88 @@ function formatAmbiguousModels(request, candidates) {
|
|
|
353
405
|
...choices.map((choice) => ` ${escapeLineValue(choice)}`)
|
|
354
406
|
].join("\n")}\n`;
|
|
355
407
|
}
|
|
408
|
+
function formatModelBenchmarkList(config, benchmarks, options = {}) {
|
|
409
|
+
const benchmarksByIdentity = /* @__PURE__ */ new Map();
|
|
410
|
+
for (const benchmark of benchmarks) {
|
|
411
|
+
const identity = `${benchmark.providerId}/${benchmark.modelId}`;
|
|
412
|
+
const matches = benchmarksByIdentity.get(identity) ?? [];
|
|
413
|
+
matches.push(benchmark);
|
|
414
|
+
benchmarksByIdentity.set(identity, matches);
|
|
415
|
+
}
|
|
416
|
+
return formatBenchmarkTable(flattenModels(config).map(({ model, provider }) => {
|
|
417
|
+
const benchmark = benchmarksByIdentity.get(`${provider.id}/${model.id}`)?.shift();
|
|
418
|
+
return benchmark === void 0 ? [
|
|
419
|
+
model.id,
|
|
420
|
+
provider.id,
|
|
421
|
+
model.name ?? model.id,
|
|
422
|
+
"n/a",
|
|
423
|
+
"n/a",
|
|
424
|
+
"n/a",
|
|
425
|
+
"0/0"
|
|
426
|
+
] : benchmarkRow(model.id, model.name ?? model.id, provider.id, benchmark, options.color === true);
|
|
427
|
+
}));
|
|
428
|
+
}
|
|
429
|
+
function formatModelBenchmarkProgressFrame(config, progress, options) {
|
|
430
|
+
const columns = {
|
|
431
|
+
3: {
|
|
432
|
+
truncate: 10,
|
|
433
|
+
width: 10
|
|
434
|
+
},
|
|
435
|
+
4: {
|
|
436
|
+
truncate: 12,
|
|
437
|
+
width: 12
|
|
438
|
+
},
|
|
439
|
+
5: {
|
|
440
|
+
truncate: 16,
|
|
441
|
+
width: 16
|
|
442
|
+
},
|
|
443
|
+
6: {
|
|
444
|
+
truncate: 8,
|
|
445
|
+
width: 8
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
const models = flattenModels(config);
|
|
449
|
+
const modelCapacity = options.maxRows === void 0 ? models.length : Math.max(options.maxRows - 2, 1);
|
|
450
|
+
const activeByModelIndex = new Map(progress.active.map((current) => [current.modelIndex, current]));
|
|
451
|
+
const completed = progress.results.filter((result) => result !== void 0).length;
|
|
452
|
+
const activeIndex = progress.active[0]?.modelIndex ?? completed;
|
|
453
|
+
const start = Math.min(Math.max(activeIndex - Math.floor(modelCapacity / 2), 0), Math.max(models.length - modelCapacity, 0));
|
|
454
|
+
const end = Math.min(start + modelCapacity, models.length);
|
|
455
|
+
const visibleModels = models.slice(start, end);
|
|
456
|
+
const bodyRows = formatBenchmarkTable(visibleModels.map(({ model, provider }, visibleIndex) => {
|
|
457
|
+
const modelIndex = start + visibleIndex;
|
|
458
|
+
const benchmark = progress.results[modelIndex];
|
|
459
|
+
if (benchmark !== void 0) return benchmarkRow(model.id, model.name ?? model.id, provider.id, benchmark, options.color === true);
|
|
460
|
+
const current = activeByModelIndex.get(modelIndex);
|
|
461
|
+
if (current !== void 0) return activeBenchmarkRow(model.id, model.name ?? model.id, provider.id, current, options);
|
|
462
|
+
return [
|
|
463
|
+
model.id,
|
|
464
|
+
provider.id,
|
|
465
|
+
model.name ?? model.id,
|
|
466
|
+
"pending",
|
|
467
|
+
"pending",
|
|
468
|
+
"pending",
|
|
469
|
+
"0/0"
|
|
470
|
+
];
|
|
471
|
+
}), columns).trimEnd().split("\n");
|
|
472
|
+
const range = models.length > visibleModels.length ? ` · showing models ${start + 1}-${end} of ${models.length}` : "";
|
|
473
|
+
const bar = formatMiniBar({
|
|
474
|
+
completed,
|
|
475
|
+
planned: progress.modelsTotal,
|
|
476
|
+
tick: options.tick,
|
|
477
|
+
width: 12
|
|
478
|
+
});
|
|
479
|
+
const running = progress.active.length === 0 ? "" : ` · ${progress.active.length} running`;
|
|
480
|
+
const speedColumn = bodyRows[0]?.indexOf("repeat") ?? -1;
|
|
481
|
+
if (speedColumn < 0) throw new Error("Benchmark progress table is missing its speed columns.");
|
|
482
|
+
return { rows: [...bodyRows.map((row) => ({
|
|
483
|
+
prefix: row.slice(0, speedColumn),
|
|
484
|
+
suffix: row.slice(speedColumn)
|
|
485
|
+
})), {
|
|
486
|
+
prefix: "",
|
|
487
|
+
suffix: `${completed}/${progress.modelsTotal} models complete ${bar}${running}${range}`
|
|
488
|
+
}] };
|
|
489
|
+
}
|
|
356
490
|
function formatModelList(config) {
|
|
357
491
|
return formatTable([[
|
|
358
492
|
"id",
|
|
@@ -426,10 +560,65 @@ async function probeModels(endpoint, headers = {}) {
|
|
|
426
560
|
if (!isRecord$1(body) || !Array.isArray(body.data) || !body.data.every(isModelRecord)) throw new TypeError("Expected OpenAI-compatible models response with data array.");
|
|
427
561
|
return body.data.map((model) => model.id);
|
|
428
562
|
}
|
|
563
|
+
function resolveProviderBenchmarkConcurrency(config, overrides = []) {
|
|
564
|
+
const concurrency = Object.fromEntries(config.providers.map((provider) => [provider.id, findProviderSetupSourceByEndpoint(provider.endpoint)?.benchmarkConcurrency ?? defaultBenchmarkConcurrency]));
|
|
565
|
+
for (const override of overrides) {
|
|
566
|
+
const separatorIndex = override.indexOf("=");
|
|
567
|
+
if (separatorIndex <= 0 || separatorIndex === override.length - 1) throw new Error("Invalid benchmark concurrency override. Expected <provider-id>=<limit>.");
|
|
568
|
+
const providerId = override.slice(0, separatorIndex);
|
|
569
|
+
const value = override.slice(separatorIndex + 1);
|
|
570
|
+
const limit = Number(value);
|
|
571
|
+
if (!(providerId in concurrency)) throw new Error(`Unknown provider "${escapeLineValue(providerId)}" in benchmark concurrency override.`);
|
|
572
|
+
if (!/^\d+$/u.test(value) || !Number.isSafeInteger(limit) || limit < 1) throw new Error(`Benchmark concurrency for provider "${escapeLineValue(providerId)}" must be a positive integer.`);
|
|
573
|
+
concurrency[providerId] = limit;
|
|
574
|
+
}
|
|
575
|
+
return concurrency;
|
|
576
|
+
}
|
|
577
|
+
function activeBenchmarkRow(modelId, modelName, providerId, current, options) {
|
|
578
|
+
const frame = options.color === true ? colors$4.cyan(options.frame) : options.frame;
|
|
579
|
+
const active = current.warmup ? "warm-up" : `${frame} ${current.sample}/${current.samples}`;
|
|
580
|
+
return [
|
|
581
|
+
modelId,
|
|
582
|
+
providerId,
|
|
583
|
+
modelName,
|
|
584
|
+
current.phase === "repeat" ? active : "done",
|
|
585
|
+
current.phase === "non-repeat" ? active : "pending",
|
|
586
|
+
current.phase === "non-repeat" ? "measuring" : "pending",
|
|
587
|
+
`${current.success.completed}/${current.success.attempted}`
|
|
588
|
+
];
|
|
589
|
+
}
|
|
590
|
+
function benchmarkRow(modelId, modelName, providerId, benchmark, color) {
|
|
591
|
+
const errored = color ? colors$4.red("errored") : "errored";
|
|
592
|
+
return [
|
|
593
|
+
modelId,
|
|
594
|
+
providerId,
|
|
595
|
+
modelName,
|
|
596
|
+
benchmark.error === void 0 ? formatDuration$2(benchmark.repeatMs) : errored,
|
|
597
|
+
benchmark.error === void 0 ? formatDuration$2(benchmark.nonRepeatMs) : errored,
|
|
598
|
+
benchmark.error === void 0 ? formatThroughput(benchmark.throughput) : errored,
|
|
599
|
+
`${benchmark.success.completed}/${benchmark.success.attempted}`
|
|
600
|
+
];
|
|
601
|
+
}
|
|
429
602
|
function canonicalIdentity(candidate) {
|
|
430
603
|
return `${candidate.provider.id}/${candidate.model.id}`;
|
|
431
604
|
}
|
|
432
|
-
function
|
|
605
|
+
function formatBenchmarkTable(rows, columns) {
|
|
606
|
+
return formatTable([[
|
|
607
|
+
"id",
|
|
608
|
+
"provider",
|
|
609
|
+
"name",
|
|
610
|
+
"repeat",
|
|
611
|
+
"non-repeat",
|
|
612
|
+
"throughput",
|
|
613
|
+
"success"
|
|
614
|
+
], ...rows], columns);
|
|
615
|
+
}
|
|
616
|
+
function formatDuration$2(durationMs) {
|
|
617
|
+
if (durationMs === void 0) return "n/a";
|
|
618
|
+
if (durationMs < 1e3) return `${Math.round(durationMs)}ms`;
|
|
619
|
+
return `${stripTrailingZeros((durationMs / 1e3).toFixed(2))}s`;
|
|
620
|
+
}
|
|
621
|
+
function formatTable(rows, columns) {
|
|
433
622
|
if (rows.length <= 1) return "";
|
|
434
623
|
return table(rows, {
|
|
435
624
|
border: getBorderCharacters("void"),
|
|
@@ -437,9 +626,13 @@ function formatTable(rows) {
|
|
|
437
626
|
paddingLeft: 0,
|
|
438
627
|
paddingRight: 2
|
|
439
628
|
},
|
|
629
|
+
columns,
|
|
440
630
|
drawHorizontalLine: () => false
|
|
441
631
|
});
|
|
442
632
|
}
|
|
633
|
+
function formatThroughput(throughput) {
|
|
634
|
+
return throughput === void 0 ? "n/a" : `${throughput.toFixed(1)} tok/s`;
|
|
635
|
+
}
|
|
443
636
|
function isModelRecord(value) {
|
|
444
637
|
return isRecord$1(value) && typeof value.id === "string" && value.id.length > 0;
|
|
445
638
|
}
|
|
@@ -449,6 +642,9 @@ function isRecord$1(value) {
|
|
|
449
642
|
function normalizeProviderIdBase(value) {
|
|
450
643
|
return value.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").toLowerCase() || "provider";
|
|
451
644
|
}
|
|
645
|
+
function stripTrailingZeros(value) {
|
|
646
|
+
return String(Number(value));
|
|
647
|
+
}
|
|
452
648
|
//#endregion
|
|
453
649
|
//#region src/cli/commands/config/setup-config.ts
|
|
454
650
|
function formatUnknownProvider(providerId, scope) {
|
|
@@ -471,16 +667,163 @@ async function loadScopedSetupConfig(io, local) {
|
|
|
471
667
|
};
|
|
472
668
|
}
|
|
473
669
|
//#endregion
|
|
670
|
+
//#region src/cli/commands/config/models/benchmark-progress.ts
|
|
671
|
+
/** Keeps the benchmark preview live without mixing transient frames into the final stdout table. */
|
|
672
|
+
function createModelBenchmarkProgressDisplay(options) {
|
|
673
|
+
const frames = cliSpinners.dots.frames;
|
|
674
|
+
let frameIndex = 0;
|
|
675
|
+
let latest;
|
|
676
|
+
let previous;
|
|
677
|
+
let interval;
|
|
678
|
+
const render = () => {
|
|
679
|
+
if (latest === void 0) return;
|
|
680
|
+
const next = formatModelBenchmarkProgressFrame(options.config, latest, {
|
|
681
|
+
color: options.color,
|
|
682
|
+
frame: frames[frameIndex % frames.length] ?? "",
|
|
683
|
+
maxRows: options.output.rows,
|
|
684
|
+
tick: 0
|
|
685
|
+
});
|
|
686
|
+
if (previous === void 0 || !sameLayout(previous, next)) {
|
|
687
|
+
clearFrame(options.output, previous?.rows.length ?? 0);
|
|
688
|
+
options.output.write(`${next.rows.map((row) => `${row.prefix}${row.suffix}`).join("\n")}\r`);
|
|
689
|
+
previous = next;
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
for (const [rowIndex, row] of next.rows.entries()) {
|
|
693
|
+
const previousRow = previous.rows[rowIndex];
|
|
694
|
+
if (previousRow !== void 0 && previousRow.suffix !== row.suffix) patchSuffix(options.output, rowIndex, next.rows.length, fastStringWidth(row.prefix), row.suffix);
|
|
695
|
+
}
|
|
696
|
+
previous = next;
|
|
697
|
+
};
|
|
698
|
+
const start = () => {
|
|
699
|
+
if (interval === void 0) {
|
|
700
|
+
interval = globalThis.setInterval(() => {
|
|
701
|
+
frameIndex += 1;
|
|
702
|
+
render();
|
|
703
|
+
}, cliSpinners.dots.interval);
|
|
704
|
+
interval.unref();
|
|
705
|
+
}
|
|
706
|
+
render();
|
|
707
|
+
};
|
|
708
|
+
/**
|
|
709
|
+
* Applies one core benchmark progress snapshot to the transient TTY table.
|
|
710
|
+
*
|
|
711
|
+
* Triggering workflow:
|
|
712
|
+
*
|
|
713
|
+
* `benchmarkModels` `onProgress`
|
|
714
|
+
* -> `config models list --with-speed`
|
|
715
|
+
* -> `ModelBenchmarkProgressDisplay.update`
|
|
716
|
+
*
|
|
717
|
+
* Upstream:
|
|
718
|
+
* - `benchmarkModels` `onProgress` callback registered by `runListModelsCommand`
|
|
719
|
+
*
|
|
720
|
+
* Downstream:
|
|
721
|
+
* - incremental benchmark table renderer `start` or `render`
|
|
722
|
+
*/
|
|
723
|
+
const update = (progress) => {
|
|
724
|
+
latest = progress;
|
|
725
|
+
if (interval === void 0) {
|
|
726
|
+
start();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
render();
|
|
730
|
+
};
|
|
731
|
+
return {
|
|
732
|
+
finish: () => {
|
|
733
|
+
if (interval !== void 0) {
|
|
734
|
+
globalThis.clearInterval(interval);
|
|
735
|
+
interval = void 0;
|
|
736
|
+
}
|
|
737
|
+
clearFrame(options.output, previous?.rows.length ?? 0);
|
|
738
|
+
previous = void 0;
|
|
739
|
+
},
|
|
740
|
+
update
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function clearFrame(output, rowCount) {
|
|
744
|
+
if (rowCount === 0) return;
|
|
745
|
+
let sequence = "\r\x1B[K";
|
|
746
|
+
for (let row = 1; row < rowCount; row += 1) sequence += "\r\x1B[1A\x1B[K";
|
|
747
|
+
output.write(sequence);
|
|
748
|
+
}
|
|
749
|
+
function patchSuffix(output, rowIndex, rowCount, column, suffix) {
|
|
750
|
+
const rowsUp = rowCount - rowIndex - 1;
|
|
751
|
+
const moveUp = rowsUp === 0 ? "" : `\x1B[${rowsUp}A`;
|
|
752
|
+
const moveDown = rowsUp === 0 ? "" : `\x1B[${rowsUp}B`;
|
|
753
|
+
const moveRight = column === 0 ? "" : `\x1B[${column}C`;
|
|
754
|
+
output.write(`\r${moveUp}${moveRight}\x1B[K${suffix}\r${moveDown}`);
|
|
755
|
+
}
|
|
756
|
+
function sameLayout(previous, next) {
|
|
757
|
+
return previous.rows.length === next.rows.length && previous.rows.every((row, index) => row.prefix === next.rows[index]?.prefix);
|
|
758
|
+
}
|
|
759
|
+
//#endregion
|
|
474
760
|
//#region src/cli/commands/config/models/ls.ts
|
|
475
761
|
const ls$1 = defineCommand({
|
|
476
|
-
|
|
477
|
-
context.io.stdout.write(formatModelList(await loadMergedSetupConfig(context.io)));
|
|
478
|
-
return 0;
|
|
479
|
-
},
|
|
762
|
+
action: runListModelsCommand,
|
|
480
763
|
alias: ["ls"],
|
|
481
764
|
description: "List configured models",
|
|
482
|
-
name: "list"
|
|
765
|
+
name: "list",
|
|
766
|
+
options: [{
|
|
767
|
+
description: "Benchmark configured models with live requests",
|
|
768
|
+
flags: "--with-speed"
|
|
769
|
+
}, {
|
|
770
|
+
description: "Override one provider benchmark concurrency (repeatable)",
|
|
771
|
+
flags: "--with-speed-concurrency <provider-id=limit>"
|
|
772
|
+
}]
|
|
483
773
|
});
|
|
774
|
+
/**
|
|
775
|
+
* Lists configured models and optionally benchmarks each model with live streamed requests.
|
|
776
|
+
*
|
|
777
|
+
* Triggering workflow:
|
|
778
|
+
*
|
|
779
|
+
* {@link defineCommand}
|
|
780
|
+
* -> `config models list`
|
|
781
|
+
* -> {@link runListModelsCommand}
|
|
782
|
+
*
|
|
783
|
+
* Upstream:
|
|
784
|
+
* - `config models list` command dispatch
|
|
785
|
+
*
|
|
786
|
+
* Downstream:
|
|
787
|
+
* - {@link loadMergedSetupConfig}
|
|
788
|
+
* - {@link benchmarkModels}
|
|
789
|
+
* - {@link createModelBenchmarkProgressDisplay}
|
|
790
|
+
* - `context.io.stdout.write`
|
|
791
|
+
*/
|
|
792
|
+
async function runListModelsCommand(context, options) {
|
|
793
|
+
const config = await loadMergedSetupConfig(context.io);
|
|
794
|
+
const concurrencyOverrides = options.withSpeedConcurrency === void 0 ? [] : [options.withSpeedConcurrency].flat();
|
|
795
|
+
if (options.withSpeed !== true) {
|
|
796
|
+
if (concurrencyOverrides.length > 0) {
|
|
797
|
+
context.io.stderr.write("--with-speed-concurrency requires --with-speed.\n");
|
|
798
|
+
return 2;
|
|
799
|
+
}
|
|
800
|
+
context.io.stdout.write(formatModelList(config));
|
|
801
|
+
return 0;
|
|
802
|
+
}
|
|
803
|
+
let providerConcurrency;
|
|
804
|
+
try {
|
|
805
|
+
providerConcurrency = resolveProviderBenchmarkConcurrency(config, concurrencyOverrides);
|
|
806
|
+
} catch (error) {
|
|
807
|
+
context.io.stderr.write(`${errorMessageFrom(error) ?? "Invalid benchmark concurrency override."}\n`);
|
|
808
|
+
return 2;
|
|
809
|
+
}
|
|
810
|
+
const progress = context.io.stderr.isTTY === true ? createModelBenchmarkProgressDisplay({
|
|
811
|
+
color: true,
|
|
812
|
+
config,
|
|
813
|
+
output: context.io.stderr
|
|
814
|
+
}) : void 0;
|
|
815
|
+
let benchmarks;
|
|
816
|
+
try {
|
|
817
|
+
benchmarks = await benchmarkModels(config, {
|
|
818
|
+
onProgress: (snapshot) => progress?.update(snapshot),
|
|
819
|
+
providerConcurrency
|
|
820
|
+
});
|
|
821
|
+
} finally {
|
|
822
|
+
progress?.finish();
|
|
823
|
+
}
|
|
824
|
+
context.io.stdout.write(formatModelBenchmarkList(config, benchmarks, { color: context.io.stdout.isTTY === true }));
|
|
825
|
+
return 0;
|
|
826
|
+
}
|
|
484
827
|
//#endregion
|
|
485
828
|
//#region src/cli/commands/config/probe.ts
|
|
486
829
|
function providerHeadersFromOptions(options) {
|
|
@@ -1794,40 +2137,6 @@ function countDiagnostics(diagnostics, severity) {
|
|
|
1794
2137
|
return diagnostics.filter((diagnostic) => diagnostic.severity === severity).length;
|
|
1795
2138
|
}
|
|
1796
2139
|
//#endregion
|
|
1797
|
-
//#region src/cli/reporters/progress/bar.ts
|
|
1798
|
-
const minBarWidth = 4;
|
|
1799
|
-
const maxBarWidth = 16;
|
|
1800
|
-
const animationThreshold = .4;
|
|
1801
|
-
function formatMiniBar(options) {
|
|
1802
|
-
if (options.planned <= 0 || options.width < minBarWidth) return "";
|
|
1803
|
-
const width = Math.min(Math.max(Math.floor(options.width), minBarWidth), maxBarWidth);
|
|
1804
|
-
const ratio = Math.min(Math.max(options.completed / options.planned, 0), 1);
|
|
1805
|
-
const completeCells = Math.min(Math.floor(ratio * width), width);
|
|
1806
|
-
if (width - completeCells === 0) return `[${"█".repeat(width)}]`;
|
|
1807
|
-
if (ratio < animationThreshold) return formatStaticBar(completeCells, width);
|
|
1808
|
-
const frontierIndex = completeCells;
|
|
1809
|
-
const phase = positiveModulo(options.tick, frontierIndex + 2);
|
|
1810
|
-
if (phase === frontierIndex + 1) return formatStaticBar(completeCells, width);
|
|
1811
|
-
return `[${Array.from({ length: width }, (_, index) => {
|
|
1812
|
-
if (phase === 0) {
|
|
1813
|
-
if (index === 0) return "▓";
|
|
1814
|
-
if (index <= frontierIndex) return "█";
|
|
1815
|
-
return "░";
|
|
1816
|
-
}
|
|
1817
|
-
if (index < phase) return "█";
|
|
1818
|
-
if (index === phase) return "▓";
|
|
1819
|
-
if (index === phase + 1 && index <= frontierIndex) return "░";
|
|
1820
|
-
if (index <= frontierIndex) return "█";
|
|
1821
|
-
return "░";
|
|
1822
|
-
}).join("")}]`;
|
|
1823
|
-
}
|
|
1824
|
-
function formatStaticBar(completeCells, width) {
|
|
1825
|
-
return `[${"█".repeat(completeCells)}${"░".repeat(width - completeCells)}]`;
|
|
1826
|
-
}
|
|
1827
|
-
function positiveModulo(value, divisor) {
|
|
1828
|
-
return (Math.floor(value) % divisor + divisor) % divisor;
|
|
1829
|
-
}
|
|
1830
|
-
//#endregion
|
|
1831
2140
|
//#region src/cli/reporters/progress/summary.ts
|
|
1832
2141
|
const colors$2 = createColors({ force: true });
|
|
1833
2142
|
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
@@ -1896,6 +2205,7 @@ function createSummaryProgressReporter(options) {
|
|
|
1896
2205
|
state: "running"
|
|
1897
2206
|
});
|
|
1898
2207
|
},
|
|
2208
|
+
onPlanningEnd: ({ progress }) => updateProgress(state, progress),
|
|
1899
2209
|
onPrepareStart: ({ startedAt }) => {
|
|
1900
2210
|
state.activeJobs.clear();
|
|
1901
2211
|
state.errorCount = 0;
|
|
@@ -1995,11 +2305,12 @@ function createInitialState() {
|
|
|
1995
2305
|
function createProgress() {
|
|
1996
2306
|
return {
|
|
1997
2307
|
execution: createCounts(),
|
|
2308
|
+
filesPlanned: 0,
|
|
1998
2309
|
filesTotal: 0,
|
|
1999
|
-
final: false,
|
|
2000
2310
|
jobsCompleted: 0,
|
|
2001
2311
|
jobsStarted: 0,
|
|
2002
|
-
jobsTotal: 0
|
|
2312
|
+
jobsTotal: 0,
|
|
2313
|
+
planningComplete: false
|
|
2003
2314
|
};
|
|
2004
2315
|
}
|
|
2005
2316
|
function createRows(state, options, now) {
|
|
@@ -2038,7 +2349,7 @@ function createRuleGroups(state) {
|
|
|
2038
2349
|
}
|
|
2039
2350
|
function estimateEta(durationMs, terminal, planned) {
|
|
2040
2351
|
if (terminal <= 0 || planned <= 0 || durationMs <= 0) return "eta ?";
|
|
2041
|
-
return `eta ~${formatDuration(durationMs * (planned - terminal) / terminal)}`;
|
|
2352
|
+
return `eta ~${formatDuration$1(durationMs * (planned - terminal) / terminal)}`;
|
|
2042
2353
|
}
|
|
2043
2354
|
function fitRow(row, columns) {
|
|
2044
2355
|
if (columns <= 0) return "";
|
|
@@ -2092,18 +2403,23 @@ function formatContentRows(groups, state, options, now, contentBudget) {
|
|
|
2092
2403
|
}
|
|
2093
2404
|
return rows;
|
|
2094
2405
|
}
|
|
2095
|
-
function formatDuration(ms) {
|
|
2096
|
-
|
|
2406
|
+
function formatDuration$1(ms) {
|
|
2407
|
+
const durationMs = Math.max(ms, 0);
|
|
2408
|
+
if (durationMs < 6e4) return `${(durationMs / 1e3).toFixed(1)}s`;
|
|
2409
|
+
return formatDuration(intervalToDuration({
|
|
2410
|
+
end: durationMs,
|
|
2411
|
+
start: 0
|
|
2412
|
+
}));
|
|
2097
2413
|
}
|
|
2098
2414
|
function formatFooters(state, options, now) {
|
|
2099
2415
|
const terminal = terminalCount(state.execution);
|
|
2100
2416
|
const elapsed = state.runStartedAt === void 0 ? 0 : now - state.runStartedAt;
|
|
2101
|
-
const progressBar = state.progress.
|
|
2102
|
-
const eta = state.progress.
|
|
2103
|
-
const projectedTokens = state.progress.
|
|
2104
|
-
const discovering = state.progress.
|
|
2417
|
+
const progressBar = state.progress.planningComplete ? formatMiniBarSegment(terminal, state.execution.planned, state.animationTick, options) : "";
|
|
2418
|
+
const eta = state.progress.planningComplete ? estimateEta(elapsed, terminal, state.execution.planned) : "eta ?";
|
|
2419
|
+
const projectedTokens = state.progress.planningComplete && terminal > 0 && state.execution.planned > 0 ? Math.ceil((state.totalTokens + state.cachedTokens) * state.execution.planned / terminal) : void 0;
|
|
2420
|
+
const discovering = state.progress.planningComplete ? "" : " jobs (discovering)";
|
|
2105
2421
|
return [
|
|
2106
|
-
fitRow(`${terminal}/${state.execution.planned}${discovering}${progressBar} ${formatDuration(elapsed)} -> ${eta === "eta ?" ? "~?" : eta.replace("eta ", "")}`, options.columns),
|
|
2422
|
+
fitRow(`${terminal}/${state.execution.planned}${discovering}${progressBar} ${formatDuration$1(elapsed)} -> ${eta === "eta ?" ? "~?" : eta.replace("eta ", "")}`, options.columns),
|
|
2107
2423
|
fitRow(`${state.execution.running} concurrency / ${state.execution.queued} queued / ${state.execution.cached} cached / ${state.execution.failed} failed`, options.columns),
|
|
2108
2424
|
fitRow(`${state.totalTokens.toLocaleString("en-US")} tokens (${state.cachedTokens.toLocaleString("en-US")} cached) -> ${projectedTokens === void 0 ? "~?" : `~${projectedTokens.toLocaleString("en-US")} tokens`}`, options.columns)
|
|
2109
2425
|
];
|
|
@@ -2134,7 +2450,7 @@ function formatTargetRow(jobState, options, now, last) {
|
|
|
2134
2450
|
const inputPath = options.cwd ? relative$1(options.cwd, jobState.job.inputPath) || "." : jobState.job.inputPath;
|
|
2135
2451
|
const target = jobState.job.target.name ? `${jobState.job.target.kind} ${jobState.job.target.name}` : jobState.job.target.kind;
|
|
2136
2452
|
const startedAt = jobState.retry?.startedAt ?? jobState.startedAt ?? now;
|
|
2137
|
-
return fitRow(`${last ? " └─" : " ├─"} ${inputPath} > ${target} ${jobState.retry ? `${jobState.retry.attempt}/${jobState.retry.maxAttempts} retrying elapsed ${formatDuration(now - startedAt)}` : `running ${formatDuration(now - startedAt)}`}`, options.columns);
|
|
2453
|
+
return fitRow(`${last ? " └─" : " ├─"} ${inputPath} > ${target} ${jobState.retry ? `${jobState.retry.attempt}/${jobState.retry.maxAttempts} retrying elapsed ${formatDuration$1(now - startedAt)}` : `running ${formatDuration$1(now - startedAt)}`}`, options.columns);
|
|
2138
2454
|
}
|
|
2139
2455
|
function styleRow(row, state, warnCount, errorCount, options) {
|
|
2140
2456
|
let styledRow = row;
|
|
@@ -2289,6 +2605,7 @@ function createRenderingProgressReporter(summary, renderer) {
|
|
|
2289
2605
|
//#endregion
|
|
2290
2606
|
//#region src/cli/commands/lint/discovery.ts
|
|
2291
2607
|
const minimatchOptions = { dot: true };
|
|
2608
|
+
const directoryBufferSize = 256;
|
|
2292
2609
|
var NoFilesFoundError = class extends Error {
|
|
2293
2610
|
globInputPaths;
|
|
2294
2611
|
pattern;
|
|
@@ -2376,15 +2693,16 @@ async function resolveInputFiles(options) {
|
|
|
2376
2693
|
})) continue;
|
|
2377
2694
|
directories.push(input);
|
|
2378
2695
|
if (!hasFilePatterns) continue;
|
|
2379
|
-
const directoryFiles =
|
|
2696
|
+
const directoryFiles = [];
|
|
2697
|
+
for await (const file of walkFiles(path, {
|
|
2380
2698
|
cwd: options.cwd,
|
|
2381
2699
|
gitignore: options.gitignore,
|
|
2382
2700
|
ignoredPatterns
|
|
2383
|
-
}))
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
if (hasFilePatterns && matchesDiscoveryFile(relativePath, options.config, { cwd: options.cwd })) candidates.push(relativePath);
|
|
2701
|
+
})) {
|
|
2702
|
+
const relativePath = normalizeRelativePath(options.cwd, file);
|
|
2703
|
+
if (hasFilePatterns && matchesDiscoveryFile(relativePath, options.config, { cwd: options.cwd })) directoryFiles.push(relativePath);
|
|
2387
2704
|
}
|
|
2705
|
+
for (const file of directoryFiles.sort()) candidates.push(file);
|
|
2388
2706
|
continue;
|
|
2389
2707
|
}
|
|
2390
2708
|
if (options.globInputPaths && isGlobPattern(input)) {
|
|
@@ -2397,7 +2715,7 @@ async function resolveInputFiles(options) {
|
|
|
2397
2715
|
pattern: input
|
|
2398
2716
|
});
|
|
2399
2717
|
if (matches.length === 0 && options.errorOnUnmatchedPattern) throw new NoFilesFoundError(input, { globInputPaths: options.globInputPaths });
|
|
2400
|
-
candidates.push(
|
|
2718
|
+
for (const match of matches) candidates.push(match);
|
|
2401
2719
|
continue;
|
|
2402
2720
|
}
|
|
2403
2721
|
if (options.errorOnUnmatchedPattern) throw new NoFilesFoundError(input, { globInputPaths: options.globInputPaths });
|
|
@@ -2412,20 +2730,19 @@ async function searchGlob(options) {
|
|
|
2412
2730
|
const rootStats = await statPath(root);
|
|
2413
2731
|
const pattern = normalizeGlobPattern(options.cwd, options.pattern);
|
|
2414
2732
|
if (!rootStats?.isDirectory()) return [];
|
|
2415
|
-
const
|
|
2733
|
+
const candidates = [];
|
|
2734
|
+
for await (const file of walkFiles(root, {
|
|
2416
2735
|
cwd: options.cwd,
|
|
2417
2736
|
gitignore: options.gitignore,
|
|
2418
2737
|
ignoredPatterns: options.ignoredPatterns
|
|
2419
|
-
}))
|
|
2420
|
-
const candidates = [];
|
|
2421
|
-
for (const file of files) {
|
|
2738
|
+
})) {
|
|
2422
2739
|
const relativePath = normalizeRelativePath(options.cwd, file);
|
|
2423
2740
|
if (matchesGlob(relativePath, pattern) && shouldIncludeGlobCandidate(relativePath, options.config, {
|
|
2424
2741
|
cwd: options.cwd,
|
|
2425
2742
|
hasFilePatterns: options.hasFilePatterns
|
|
2426
2743
|
})) candidates.push(relativePath);
|
|
2427
2744
|
}
|
|
2428
|
-
return candidates;
|
|
2745
|
+
return candidates.sort();
|
|
2429
2746
|
}
|
|
2430
2747
|
function shouldFilterGitignoredFiles(config) {
|
|
2431
2748
|
return normalizeConfig(config).some((item) => item.ignore?.gitignore === true);
|
|
@@ -2446,18 +2763,27 @@ async function statPath(path) {
|
|
|
2446
2763
|
throw error;
|
|
2447
2764
|
}
|
|
2448
2765
|
}
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2766
|
+
/**
|
|
2767
|
+
* Streams directory entries so unmatched trees never accumulate into recursive child arrays.
|
|
2768
|
+
* The consumer owns result ordering because filesystem iteration order is not stable.
|
|
2769
|
+
*/
|
|
2770
|
+
async function* walkFiles(root, options) {
|
|
2771
|
+
const pendingDirectories = [root];
|
|
2772
|
+
while (pendingDirectories.length > 0) {
|
|
2773
|
+
const currentDirectory = pendingDirectories.pop();
|
|
2774
|
+
if (currentDirectory === void 0) continue;
|
|
2775
|
+
const childDirectories = [];
|
|
2776
|
+
const directory = await opendir(currentDirectory, { bufferSize: directoryBufferSize });
|
|
2777
|
+
for await (const entry of directory) {
|
|
2778
|
+
const path = resolve(currentDirectory, entry.name);
|
|
2779
|
+
if (entry.isDirectory()) {
|
|
2780
|
+
if (!await shouldPruneDirectory(path, options)) childDirectories.push(path);
|
|
2781
|
+
continue;
|
|
2782
|
+
}
|
|
2783
|
+
if (entry.isFile()) yield path;
|
|
2457
2784
|
}
|
|
2458
|
-
|
|
2785
|
+
for (const path of childDirectories.reverse()) pendingDirectories.push(path);
|
|
2459
2786
|
}
|
|
2460
|
-
return files;
|
|
2461
2787
|
}
|
|
2462
2788
|
//#endregion
|
|
2463
2789
|
//#region src/cli/commands/lint/errors.ts
|
|
@@ -3007,6 +3333,9 @@ function mergeProgressReporters(base, extra) {
|
|
|
3007
3333
|
onJobStart: (payload) => {
|
|
3008
3334
|
deliverBoth((reporter) => reporter.onJobStart?.(payload));
|
|
3009
3335
|
},
|
|
3336
|
+
onPlanningEnd: (payload) => {
|
|
3337
|
+
deliverBoth((reporter) => reporter.onPlanningEnd?.(payload));
|
|
3338
|
+
},
|
|
3010
3339
|
onPrepareEnd: (payload) => {
|
|
3011
3340
|
deliverBoth((reporter) => reporter.onPrepareEnd?.(payload));
|
|
3012
3341
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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-3Ov9-ZVf.mjs";
|
|
2
2
|
import { ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated } from "@alint-js/config";
|
|
3
3
|
import { defineConfig } from "@alint-js/core";
|
|
4
4
|
export { defineConfig, executeCli, formatDiagnostics, formatJson, formatStylish, ignorePatternsAIAgents, ignorePatternsBuildOutputs, ignorePatternsCaches, ignorePatternsCommon, ignorePatternsEslintDefaults, ignorePatternsGenerated };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alint-js/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"@moeru/std": "^0.1.0-beta.20",
|
|
21
21
|
"cac": "^7.0.0",
|
|
22
22
|
"cli-spinners": "^3.4.0",
|
|
23
|
+
"date-fns": "^4.4.0",
|
|
23
24
|
"fast-string-truncated-width": "^3.0.3",
|
|
24
25
|
"fast-string-width": "^3.0.2",
|
|
25
26
|
"gitignore-fs": "^2.2.3",
|
|
@@ -27,8 +28,8 @@
|
|
|
27
28
|
"pathe": "^2.0.3",
|
|
28
29
|
"table": "^6.9.0",
|
|
29
30
|
"tinyrainbow": "^3.1.0",
|
|
30
|
-
"@alint-js/config": "0.
|
|
31
|
-
"@alint-js/core": "0.
|
|
31
|
+
"@alint-js/config": "0.2.0",
|
|
32
|
+
"@alint-js/core": "0.2.0"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@pnpm/find-workspace-dir": "^1000.1.5",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
41
|
"alint": "node ./dist/bin/index.mjs",
|
|
42
|
+
"bench": "vitest bench --config vitest.config.ts",
|
|
41
43
|
"build": "tsdown",
|
|
42
44
|
"build:binary": "tsdown --config tsdown.binary.config.ts --config-loader unrun",
|
|
43
45
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|