@alint-js/cli 0.0.8 → 0.0.10
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-D7cUTZnE.mjs → cli-D4YC9Jnb.mjs} +570 -29
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
package/dist/bin/index.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
3
|
import { cac } from "cac";
|
|
4
|
-
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
4
|
+
import { getGlobalSetupConfigPath, getProjectSetupConfigPath, getStatsDir, loadAlintConfig, loadSetupConfig, mergeSetupConfigs, writeSetupConfig } from "@alint-js/config";
|
|
5
5
|
import { AlintRunError, hasDiscoveryFilePatterns, matchesDiscoveryFile, normalizeConfig, resolveConfigForFile, runAlint } from "@alint-js/core";
|
|
6
|
-
import { relative, resolve } from "pathe";
|
|
6
|
+
import { isAbsolute, join, relative, resolve } from "pathe";
|
|
7
7
|
import { getBorderCharacters, table } from "table";
|
|
8
8
|
import { errorMessageFrom } from "@moeru/std/error";
|
|
9
|
-
import { readFile, readdir, stat } from "node:fs/promises";
|
|
9
|
+
import { appendFile, mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
|
|
10
10
|
import c, { createColors } from "tinyrainbow";
|
|
11
11
|
import cliSpinners from "cli-spinners";
|
|
12
12
|
import { relative as relative$1 } from "node:path";
|
|
13
13
|
import Gitignore from "gitignore-fs";
|
|
14
|
-
import { minimatch } from "minimatch";
|
|
14
|
+
import { Minimatch, minimatch } from "minimatch";
|
|
15
15
|
import { errorMessageFrom as errorMessageFrom$1 } from "@moeru/std";
|
|
16
16
|
//#region src/cli/commands/command.ts
|
|
17
17
|
function defineCommand(node) {
|
|
@@ -183,8 +183,10 @@ function rewriteUsageSection(sections, path, node) {
|
|
|
183
183
|
function shouldSkipOptionValue(arg) {
|
|
184
184
|
if (arg.includes("=")) return false;
|
|
185
185
|
return [
|
|
186
|
+
"--by",
|
|
186
187
|
"--cache-location",
|
|
187
188
|
"--config",
|
|
189
|
+
"--cwd",
|
|
188
190
|
"--file-concurrency",
|
|
189
191
|
"--format",
|
|
190
192
|
"--model",
|
|
@@ -193,6 +195,7 @@ function shouldSkipOptionValue(arg) {
|
|
|
193
195
|
"--provider-id",
|
|
194
196
|
"--provider-model",
|
|
195
197
|
"--rule-concurrency",
|
|
198
|
+
"--since",
|
|
196
199
|
"--timeout-ms",
|
|
197
200
|
"-f",
|
|
198
201
|
"-l"
|
|
@@ -499,7 +502,7 @@ function formatJson(result) {
|
|
|
499
502
|
}
|
|
500
503
|
//#endregion
|
|
501
504
|
//#region src/cli/reporters/stylish.ts
|
|
502
|
-
const colors$
|
|
505
|
+
const colors$2 = createColors({ force: true });
|
|
503
506
|
function formatStylish(input, options = {}) {
|
|
504
507
|
const diagnostics = Array.isArray(input) ? input : input.diagnostics;
|
|
505
508
|
const totalTokens = Array.isArray(input) ? void 0 : input.usage.totalTokens;
|
|
@@ -541,12 +544,12 @@ function createStyle(color) {
|
|
|
541
544
|
warning: identity
|
|
542
545
|
};
|
|
543
546
|
return {
|
|
544
|
-
error: colors$
|
|
545
|
-
file: colors$
|
|
546
|
-
location: colors$
|
|
547
|
-
ruleId: colors$
|
|
548
|
-
summaryToken: colors$
|
|
549
|
-
warning: colors$
|
|
547
|
+
error: colors$2.red,
|
|
548
|
+
file: colors$2.underline,
|
|
549
|
+
location: colors$2.dim,
|
|
550
|
+
ruleId: colors$2.dim,
|
|
551
|
+
summaryToken: colors$2.cyan,
|
|
552
|
+
warning: colors$2.yellow
|
|
550
553
|
};
|
|
551
554
|
}
|
|
552
555
|
function formatSummary(diagnostics, totalTokens, style) {
|
|
@@ -594,7 +597,7 @@ function countDiagnostics$1(diagnostics, severity) {
|
|
|
594
597
|
}
|
|
595
598
|
//#endregion
|
|
596
599
|
//#region src/cli/reporters/progress/summary.ts
|
|
597
|
-
const colors = createColors({ force: true });
|
|
600
|
+
const colors$1 = createColors({ force: true });
|
|
598
601
|
function createSummaryProgressReporter(options) {
|
|
599
602
|
const now = () => options.clock?.() ?? Date.now();
|
|
600
603
|
const state = {
|
|
@@ -802,8 +805,8 @@ function replaceFirst(row, search, replacement) {
|
|
|
802
805
|
function styleRow(row, state, warnCount, errorCount, options) {
|
|
803
806
|
let styledRow = row;
|
|
804
807
|
const spinner = options.spinnerFrames[state.spinnerIndex] ?? "";
|
|
805
|
-
if (spinner) styledRow = replaceFirst(styledRow, spinner, colors.cyan(spinner));
|
|
806
|
-
styledRow = styledRow.replace(/\|/g, colors.gray("|")).replace(`${warnCount} warn`, colors.yellow(`${warnCount} warn`)).replace(`${errorCount} error`, (errorCount > 0 ? colors.red : colors.gray)(`${errorCount} error`)).replace(/(\d+\/\d+\/\d+\/\d+)/, (match) => state.errored > 0 ? colors.red(match) : colors.gray(match)).replace(/(\d[\d,]* tokens)/g, (match) => colors.cyan(match));
|
|
808
|
+
if (spinner) styledRow = replaceFirst(styledRow, spinner, colors$1.cyan(spinner));
|
|
809
|
+
styledRow = styledRow.replace(/\|/g, colors$1.gray("|")).replace(`${warnCount} warn`, colors$1.yellow(`${warnCount} warn`)).replace(`${errorCount} error`, (errorCount > 0 ? colors$1.red : colors$1.gray)(`${errorCount} error`)).replace(/(\d+\/\d+\/\d+\/\d+)/, (match) => state.errored > 0 ? colors$1.red(match) : colors$1.gray(match)).replace(/(\d[\d,]* tokens)/g, (match) => colors$1.cyan(match));
|
|
807
810
|
return styledRow;
|
|
808
811
|
}
|
|
809
812
|
//#endregion
|
|
@@ -933,9 +936,28 @@ function createRenderingProgressReporter(summary, renderer) {
|
|
|
933
936
|
}
|
|
934
937
|
//#endregion
|
|
935
938
|
//#region src/cli/commands/lint/discovery.ts
|
|
936
|
-
|
|
939
|
+
const minimatchOptions = { dot: true };
|
|
940
|
+
var NoFilesFoundError = class extends Error {
|
|
941
|
+
globInputPaths;
|
|
942
|
+
pattern;
|
|
943
|
+
constructor(pattern, options) {
|
|
944
|
+
super(`No files matching "${pattern}" were found${options.globInputPaths ? "" : " (glob input is disabled)"}.`);
|
|
945
|
+
this.name = "NoFilesFoundError";
|
|
946
|
+
this.globInputPaths = options.globInputPaths;
|
|
947
|
+
this.pattern = pattern;
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
async function findFiles(options) {
|
|
951
|
+
const { config, cwd, errorOnUnmatchedPattern = true, globInputPaths = true, inputs } = options;
|
|
937
952
|
const gitignore = shouldFilterGitignoredFiles(config) ? new Gitignore() : void 0;
|
|
938
|
-
const candidates =
|
|
953
|
+
const candidates = await resolveInputFiles({
|
|
954
|
+
config,
|
|
955
|
+
cwd,
|
|
956
|
+
errorOnUnmatchedPattern,
|
|
957
|
+
gitignore,
|
|
958
|
+
globInputPaths,
|
|
959
|
+
inputs: inputs.length > 0 ? inputs : ["."]
|
|
960
|
+
});
|
|
939
961
|
if (!gitignore || candidates.length === 0) return candidates;
|
|
940
962
|
const lintFiles = [];
|
|
941
963
|
for (const file of candidates) {
|
|
@@ -947,31 +969,122 @@ async function resolveLintFiles(files, config, cwd) {
|
|
|
947
969
|
function collectGlobalIgnorePatterns(config) {
|
|
948
970
|
return normalizeConfig(config).flatMap((item) => isGlobalIgnoreItem(item) ? [...item.ignores] : []);
|
|
949
971
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
}
|
|
957
|
-
|
|
972
|
+
function getGlobParent(input) {
|
|
973
|
+
const segments = input.replaceAll("\\", "/").split("/");
|
|
974
|
+
const parentSegments = [];
|
|
975
|
+
for (const segment of segments) {
|
|
976
|
+
if (isGlobPattern(segment)) break;
|
|
977
|
+
parentSegments.push(segment);
|
|
978
|
+
}
|
|
979
|
+
const parent = parentSegments.join("/");
|
|
980
|
+
return parent === "" ? "." : parent;
|
|
958
981
|
}
|
|
959
982
|
function isGlobalIgnoreItem(item) {
|
|
960
983
|
const keys = Object.keys(item).filter((key) => item[key] !== void 0);
|
|
961
984
|
return item.ignores !== void 0 && keys.every((key) => key === "ignores" || key === "name");
|
|
962
985
|
}
|
|
986
|
+
function isGlobPattern(input) {
|
|
987
|
+
return new Minimatch(input, minimatchOptions).hasMagic();
|
|
988
|
+
}
|
|
989
|
+
function isNodeError$1(error) {
|
|
990
|
+
return error instanceof Error && "code" in error;
|
|
991
|
+
}
|
|
992
|
+
function matchesGlob(filePath, pattern) {
|
|
993
|
+
return minimatch(filePath, pattern.replaceAll("\\", "/"), minimatchOptions);
|
|
994
|
+
}
|
|
963
995
|
function matchesIgnoredDirectory(relativePath, patterns) {
|
|
964
|
-
return patterns.some((pattern) => minimatch(relativePath, pattern,
|
|
996
|
+
return patterns.some((pattern) => minimatch(relativePath, pattern, minimatchOptions) || minimatch(`${relativePath}/`, pattern, minimatchOptions) || minimatch(`${relativePath}/__alint__`, pattern, minimatchOptions));
|
|
997
|
+
}
|
|
998
|
+
function normalizeGlobPattern(cwd, pattern) {
|
|
999
|
+
return isAbsolute(pattern) ? normalizeRelativePath(cwd, pattern) : pattern.replaceAll("\\", "/");
|
|
965
1000
|
}
|
|
966
1001
|
function normalizeRelativePath(cwd, filePath) {
|
|
967
1002
|
return relative(cwd, filePath).replaceAll("\\", "/");
|
|
968
1003
|
}
|
|
1004
|
+
async function resolveInputFiles(options) {
|
|
1005
|
+
const hasFilePatterns = hasDiscoveryFilePatterns(options.config);
|
|
1006
|
+
const ignoredPatterns = collectGlobalIgnorePatterns(options.config);
|
|
1007
|
+
const candidates = [];
|
|
1008
|
+
for (const input of options.inputs) {
|
|
1009
|
+
const path = resolve(options.cwd, input);
|
|
1010
|
+
const stats = await statPath(path);
|
|
1011
|
+
if (stats?.isFile()) {
|
|
1012
|
+
candidates.push(input);
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1015
|
+
if (stats?.isDirectory()) {
|
|
1016
|
+
if (!hasFilePatterns) continue;
|
|
1017
|
+
if (await shouldPruneDirectory(path, {
|
|
1018
|
+
cwd: options.cwd,
|
|
1019
|
+
gitignore: options.gitignore,
|
|
1020
|
+
ignoredPatterns
|
|
1021
|
+
})) continue;
|
|
1022
|
+
const directoryFiles = (await walkFiles(path, {
|
|
1023
|
+
cwd: options.cwd,
|
|
1024
|
+
gitignore: options.gitignore,
|
|
1025
|
+
ignoredPatterns
|
|
1026
|
+
})).sort();
|
|
1027
|
+
for (const directoryFile of directoryFiles) {
|
|
1028
|
+
const relativePath = normalizeRelativePath(options.cwd, directoryFile);
|
|
1029
|
+
if (hasFilePatterns && matchesDiscoveryFile(relativePath, options.config, { cwd: options.cwd })) candidates.push(relativePath);
|
|
1030
|
+
}
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
if (options.globInputPaths && isGlobPattern(input)) {
|
|
1034
|
+
const matches = await searchGlob({
|
|
1035
|
+
config: options.config,
|
|
1036
|
+
cwd: options.cwd,
|
|
1037
|
+
gitignore: options.gitignore,
|
|
1038
|
+
hasFilePatterns,
|
|
1039
|
+
ignoredPatterns,
|
|
1040
|
+
pattern: input
|
|
1041
|
+
});
|
|
1042
|
+
if (matches.length === 0 && options.errorOnUnmatchedPattern) throw new NoFilesFoundError(input, { globInputPaths: options.globInputPaths });
|
|
1043
|
+
candidates.push(...matches);
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
if (options.errorOnUnmatchedPattern) throw new NoFilesFoundError(input, { globInputPaths: options.globInputPaths });
|
|
1047
|
+
}
|
|
1048
|
+
return [...new Set(candidates)];
|
|
1049
|
+
}
|
|
1050
|
+
async function searchGlob(options) {
|
|
1051
|
+
const root = resolve(options.cwd, getGlobParent(options.pattern));
|
|
1052
|
+
const rootStats = await statPath(root);
|
|
1053
|
+
const pattern = normalizeGlobPattern(options.cwd, options.pattern);
|
|
1054
|
+
if (!rootStats?.isDirectory()) return [];
|
|
1055
|
+
const files = (await walkFiles(root, {
|
|
1056
|
+
cwd: options.cwd,
|
|
1057
|
+
gitignore: options.gitignore,
|
|
1058
|
+
ignoredPatterns: options.ignoredPatterns
|
|
1059
|
+
})).sort();
|
|
1060
|
+
const candidates = [];
|
|
1061
|
+
for (const file of files) {
|
|
1062
|
+
const relativePath = normalizeRelativePath(options.cwd, file);
|
|
1063
|
+
if (matchesGlob(relativePath, pattern) && shouldIncludeGlobCandidate(relativePath, options.config, {
|
|
1064
|
+
cwd: options.cwd,
|
|
1065
|
+
hasFilePatterns: options.hasFilePatterns
|
|
1066
|
+
})) candidates.push(relativePath);
|
|
1067
|
+
}
|
|
1068
|
+
return candidates;
|
|
1069
|
+
}
|
|
969
1070
|
function shouldFilterGitignoredFiles(config) {
|
|
970
1071
|
return normalizeConfig(config).some((item) => item.ignore?.gitignore === true);
|
|
971
1072
|
}
|
|
1073
|
+
function shouldIncludeGlobCandidate(filePath, config, options) {
|
|
1074
|
+
if (options.hasFilePatterns) return matchesDiscoveryFile(filePath, config, { cwd: options.cwd });
|
|
1075
|
+
return !resolveConfigForFile(filePath, config, { cwd: options.cwd }).ignored;
|
|
1076
|
+
}
|
|
972
1077
|
async function shouldPruneDirectory(path, options) {
|
|
973
1078
|
if (matchesIgnoredDirectory(normalizeRelativePath(options.cwd, path), options.ignoredPatterns)) return true;
|
|
974
|
-
return await options.gitignore?.ignores(path) === true;
|
|
1079
|
+
return await options.gitignore?.ignores(`${path}/`) === true;
|
|
1080
|
+
}
|
|
1081
|
+
async function statPath(path) {
|
|
1082
|
+
try {
|
|
1083
|
+
return await stat(path);
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
if (isNodeError$1(error) && (error.code === "ENOENT" || error.code === "ENOTDIR")) return;
|
|
1086
|
+
throw error;
|
|
1087
|
+
}
|
|
975
1088
|
}
|
|
976
1089
|
async function walkFiles(root, options) {
|
|
977
1090
|
const entries = await readdir(root, { withFileTypes: true });
|
|
@@ -1011,6 +1124,7 @@ function resolveConfigRunner(config) {
|
|
|
1011
1124
|
}
|
|
1012
1125
|
function resolveRunnerConfig(setupConfig, config, options) {
|
|
1013
1126
|
const cache = resolveRunnerCacheConfig(setupConfig.runner?.cache, config.runner?.cache, options);
|
|
1127
|
+
const stats = resolveRunnerStatsConfig(setupConfig.runner?.stats, config.runner?.stats, options);
|
|
1014
1128
|
const fileConcurrency = parsePositiveIntegerOption(options.fileConcurrency, "--file-concurrency");
|
|
1015
1129
|
const ruleConcurrency = parsePositiveIntegerOption(options.ruleConcurrency, "--rule-concurrency");
|
|
1016
1130
|
const timeoutMs = parsePositiveIntegerOption(options.timeoutMs, "--timeout-ms");
|
|
@@ -1020,6 +1134,7 @@ function resolveRunnerConfig(setupConfig, config, options) {
|
|
|
1020
1134
|
cache,
|
|
1021
1135
|
fileConcurrency: fileConcurrency ?? config.runner?.fileConcurrency ?? setupConfig.runner?.fileConcurrency,
|
|
1022
1136
|
ruleConcurrency: ruleConcurrency ?? config.runner?.ruleConcurrency ?? setupConfig.runner?.ruleConcurrency,
|
|
1137
|
+
stats,
|
|
1023
1138
|
timeoutMs: timeoutMs ?? config.runner?.timeoutMs ?? setupConfig.runner?.timeoutMs
|
|
1024
1139
|
};
|
|
1025
1140
|
return Object.values(runner).some((value) => value !== void 0) ? runner : void 0;
|
|
@@ -1033,6 +1148,15 @@ function mergeRunnerCacheConfig(setupCache, configCache) {
|
|
|
1033
1148
|
};
|
|
1034
1149
|
return configCache;
|
|
1035
1150
|
}
|
|
1151
|
+
function mergeRunnerStatsConfig(setupStats, configStats) {
|
|
1152
|
+
if (configStats === void 0) return setupStats;
|
|
1153
|
+
if (typeof configStats === "boolean") return configStats;
|
|
1154
|
+
if (typeof setupStats === "object") return {
|
|
1155
|
+
...setupStats,
|
|
1156
|
+
...configStats
|
|
1157
|
+
};
|
|
1158
|
+
return configStats;
|
|
1159
|
+
}
|
|
1036
1160
|
function parsePositiveIntegerOption(value, label) {
|
|
1037
1161
|
if (value === void 0) return;
|
|
1038
1162
|
const parsed = Number(value);
|
|
@@ -1048,6 +1172,304 @@ function resolveRunnerCacheConfig(setupCache, configCache, options) {
|
|
|
1048
1172
|
} : { location: options.cacheLocation };
|
|
1049
1173
|
return configuredCache;
|
|
1050
1174
|
}
|
|
1175
|
+
function resolveRunnerStatsConfig(setupStats, configStats, options) {
|
|
1176
|
+
if (options.stats === false) return false;
|
|
1177
|
+
return mergeRunnerStatsConfig(setupStats, configStats);
|
|
1178
|
+
}
|
|
1179
|
+
//#endregion
|
|
1180
|
+
//#region src/cli/stats/ci.ts
|
|
1181
|
+
function isCi(env = process.env) {
|
|
1182
|
+
const ci = env.CI;
|
|
1183
|
+
if (ci !== void 0 && ci !== "" && ci !== "0" && ci !== "false") return true;
|
|
1184
|
+
return Boolean(env.GITHUB_ACTIONS || env.GITLAB_CI || env.CIRCLECI || env.BUILDKITE || env.TF_BUILD);
|
|
1185
|
+
}
|
|
1186
|
+
//#endregion
|
|
1187
|
+
//#region src/cli/stats/since.ts
|
|
1188
|
+
/**
|
|
1189
|
+
* Parse a `--since` time into an inclusive lower-bound timestamp.
|
|
1190
|
+
* This is a tiny helper only to meet the needs.
|
|
1191
|
+
*
|
|
1192
|
+
* Supported formats:
|
|
1193
|
+
* - `Nd`/`Nh` — Now minus N days/hours.
|
|
1194
|
+
* - `YYYY-MM`/`YYYY-MM-DD` — Start of that UTC month/day.
|
|
1195
|
+
*
|
|
1196
|
+
* Edge cases:
|
|
1197
|
+
* - An empty time means "no lower bound".
|
|
1198
|
+
* - An unrecognized time will cause an error to be thrown.
|
|
1199
|
+
*/
|
|
1200
|
+
function parseSince(time, now) {
|
|
1201
|
+
if (time === void 0 || time === "") return;
|
|
1202
|
+
const relative = /^(\d+)([dh])$/u.exec(time);
|
|
1203
|
+
if (relative) return now - Number(relative[1]) * (relative[2] === "d" ? 864e5 : 36e5);
|
|
1204
|
+
const calendar = /^(\d{4})-(\d{2})(?:-(\d{2}))?$/u.exec(time);
|
|
1205
|
+
if (calendar) {
|
|
1206
|
+
const year = Number(calendar[1]);
|
|
1207
|
+
const month = Number(calendar[2]);
|
|
1208
|
+
const day = calendar[3] === void 0 ? 1 : Number(calendar[3]);
|
|
1209
|
+
return Date.UTC(year, month - 1, day);
|
|
1210
|
+
}
|
|
1211
|
+
throw new Error(`Invalid --since "${time}": use e.g. 7d, 24h, 2025-01, or 2025-01-15.`);
|
|
1212
|
+
}
|
|
1213
|
+
//#endregion
|
|
1214
|
+
//#region src/cli/stats/jsonl.ts
|
|
1215
|
+
const DEFAULT_RETENTION_MONTHS = 12;
|
|
1216
|
+
const STATS_FILE_PATTERN = /^stats-(\d{4})-(\d{2})\.jsonl$/u;
|
|
1217
|
+
function createJsonlStatsStore(options) {
|
|
1218
|
+
const now = options.clock ?? Date.now;
|
|
1219
|
+
const retentionMonths = options.retentionMonths ?? DEFAULT_RETENTION_MONTHS;
|
|
1220
|
+
return {
|
|
1221
|
+
query: (filter) => query(options.dir, filter ?? {}, now),
|
|
1222
|
+
record: (input) => record(options.dir, input, now(), retentionMonths)
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function accumulate(rows, key, inTok, outTok, totalTok, countRun) {
|
|
1226
|
+
const row = rows.get(key) ?? {
|
|
1227
|
+
inTok: 0,
|
|
1228
|
+
key,
|
|
1229
|
+
outTok: 0,
|
|
1230
|
+
runs: 0,
|
|
1231
|
+
totalTok: 0
|
|
1232
|
+
};
|
|
1233
|
+
row.inTok += inTok;
|
|
1234
|
+
row.outTok += outTok;
|
|
1235
|
+
row.totalTok += totalTok;
|
|
1236
|
+
if (countRun) row.runs += 1;
|
|
1237
|
+
rows.set(key, row);
|
|
1238
|
+
}
|
|
1239
|
+
function isEnoent(error) {
|
|
1240
|
+
return error instanceof Error && error.code === "ENOENT";
|
|
1241
|
+
}
|
|
1242
|
+
function monthIndexOf(ts) {
|
|
1243
|
+
const date = new Date(ts);
|
|
1244
|
+
return date.getUTCFullYear() * 12 + date.getUTCMonth();
|
|
1245
|
+
}
|
|
1246
|
+
function parseRunLine(line) {
|
|
1247
|
+
try {
|
|
1248
|
+
const value = JSON.parse(line);
|
|
1249
|
+
if (typeof value.ts === "number" && typeof value.cwd === "string" && value.usage != null) return value;
|
|
1250
|
+
return;
|
|
1251
|
+
} catch {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
async function prune(dir, ts, retentionMonths) {
|
|
1256
|
+
if (retentionMonths <= 0) return;
|
|
1257
|
+
const cutoff = monthIndexOf(ts) - (retentionMonths - 1);
|
|
1258
|
+
const files = await statsFiles(dir);
|
|
1259
|
+
for (const { month, name } of files) if (month < cutoff) await rm(join(dir, name));
|
|
1260
|
+
}
|
|
1261
|
+
async function query(dir, filter, now) {
|
|
1262
|
+
const dimension = filter.by ?? "model";
|
|
1263
|
+
const since = parseSince(filter.since, now());
|
|
1264
|
+
const runs = await readRuns(dir);
|
|
1265
|
+
const rows = /* @__PURE__ */ new Map();
|
|
1266
|
+
let totalRuns = 0;
|
|
1267
|
+
let totalIn = 0;
|
|
1268
|
+
let totalOut = 0;
|
|
1269
|
+
let totalTok = 0;
|
|
1270
|
+
for (const run of runs) {
|
|
1271
|
+
if (since !== void 0 && run.ts < since) continue;
|
|
1272
|
+
if (filter.cwd !== void 0 && run.cwd !== filter.cwd) continue;
|
|
1273
|
+
totalRuns += 1;
|
|
1274
|
+
totalIn += run.usage.inTok;
|
|
1275
|
+
totalOut += run.usage.outTok;
|
|
1276
|
+
totalTok += run.usage.totalTok;
|
|
1277
|
+
if (dimension === "dir") {
|
|
1278
|
+
accumulate(rows, run.cwd, run.usage.inTok, run.usage.outTok, run.usage.totalTok, true);
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
1282
|
+
for (const usageRecord of run.usage.records) {
|
|
1283
|
+
const key = recordKey(usageRecord, dimension);
|
|
1284
|
+
accumulate(rows, key, usageRecord.inTok, usageRecord.outTok, usageRecord.totalTok, !seenKeys.has(key));
|
|
1285
|
+
seenKeys.add(key);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return {
|
|
1289
|
+
dimension,
|
|
1290
|
+
rows: [...rows.values()].sort((left, right) => right.totalTok - left.totalTok),
|
|
1291
|
+
totalIn,
|
|
1292
|
+
totalOut,
|
|
1293
|
+
totalRuns,
|
|
1294
|
+
totalTok
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
async function readRuns(dir) {
|
|
1298
|
+
const files = await statsFiles(dir);
|
|
1299
|
+
const runs = [];
|
|
1300
|
+
for (const { name } of files) {
|
|
1301
|
+
const content = await readFile(join(dir, name), "utf8");
|
|
1302
|
+
for (const line of content.split("\n")) {
|
|
1303
|
+
if (line.trim() === "") continue;
|
|
1304
|
+
const run = parseRunLine(line);
|
|
1305
|
+
if (run) runs.push(run);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
return runs;
|
|
1309
|
+
}
|
|
1310
|
+
async function record(dir, input, ts, retentionMonths) {
|
|
1311
|
+
const stat = {
|
|
1312
|
+
ts,
|
|
1313
|
+
...input
|
|
1314
|
+
};
|
|
1315
|
+
await mkdir(dir, { recursive: true });
|
|
1316
|
+
await appendFile(join(dir, statsFileName(ts)), `${JSON.stringify(stat)}\n`, "utf8");
|
|
1317
|
+
await prune(dir, ts, retentionMonths);
|
|
1318
|
+
}
|
|
1319
|
+
function recordKey(record, dimension) {
|
|
1320
|
+
if (dimension === "rule") return record.ruleId;
|
|
1321
|
+
if (dimension === "operation") return record.operation ?? record.ruleId;
|
|
1322
|
+
return `${record.providerId}/${record.modelId}`;
|
|
1323
|
+
}
|
|
1324
|
+
function statsFileName(ts) {
|
|
1325
|
+
const date = new Date(ts);
|
|
1326
|
+
return `stats-${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}.jsonl`;
|
|
1327
|
+
}
|
|
1328
|
+
async function statsFiles(dir) {
|
|
1329
|
+
let entries;
|
|
1330
|
+
try {
|
|
1331
|
+
entries = await readdir(dir);
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
if (isEnoent(error)) return [];
|
|
1334
|
+
throw error;
|
|
1335
|
+
}
|
|
1336
|
+
return entries.map((name) => {
|
|
1337
|
+
const match = STATS_FILE_PATTERN.exec(name);
|
|
1338
|
+
return match ? {
|
|
1339
|
+
month: Number(match[1]) * 12 + (Number(match[2]) - 1),
|
|
1340
|
+
name
|
|
1341
|
+
} : void 0;
|
|
1342
|
+
}).filter((entry) => entry !== void 0).sort((left, right) => left.month - right.month);
|
|
1343
|
+
}
|
|
1344
|
+
//#endregion
|
|
1345
|
+
//#region src/cli/stats/record.ts
|
|
1346
|
+
function createRunStat(input) {
|
|
1347
|
+
return {
|
|
1348
|
+
cwd: input.cwd,
|
|
1349
|
+
durationMs: input.durationMs,
|
|
1350
|
+
ruleCounts: input.ruleCounts,
|
|
1351
|
+
usage: {
|
|
1352
|
+
inTok: input.usage.inputTokens,
|
|
1353
|
+
outTok: input.usage.outputTokens,
|
|
1354
|
+
records: input.usage.records.map(toStatsUsageRecord),
|
|
1355
|
+
totalTok: input.usage.totalTokens
|
|
1356
|
+
}
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function readOperation(metadata) {
|
|
1360
|
+
if (typeof metadata !== "object" || metadata === null || !("operation" in metadata)) return;
|
|
1361
|
+
const operation = metadata.operation;
|
|
1362
|
+
return typeof operation === "string" ? operation : void 0;
|
|
1363
|
+
}
|
|
1364
|
+
function toStatsUsageRecord(record) {
|
|
1365
|
+
return {
|
|
1366
|
+
filePath: record.filePath,
|
|
1367
|
+
inTok: record.inputTokens ?? 0,
|
|
1368
|
+
modelId: record.modelId,
|
|
1369
|
+
operation: readOperation(record.metadata),
|
|
1370
|
+
outTok: record.outputTokens ?? 0,
|
|
1371
|
+
providerId: record.providerId,
|
|
1372
|
+
ruleId: record.ruleId,
|
|
1373
|
+
totalTok: record.totalTokens ?? 0
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
//#endregion
|
|
1377
|
+
//#region src/cli/commands/lint/stats.ts
|
|
1378
|
+
function createStatsCollector() {
|
|
1379
|
+
const counts = {
|
|
1380
|
+
cached: 0,
|
|
1381
|
+
completed: 0,
|
|
1382
|
+
errored: 0,
|
|
1383
|
+
planned: 0
|
|
1384
|
+
};
|
|
1385
|
+
let startedAt;
|
|
1386
|
+
let endedAt;
|
|
1387
|
+
return {
|
|
1388
|
+
counts,
|
|
1389
|
+
durationMs: () => startedAt !== void 0 && endedAt !== void 0 ? endedAt - startedAt : void 0,
|
|
1390
|
+
reporter: {
|
|
1391
|
+
onRunEnd: (payload) => {
|
|
1392
|
+
counts.cached = payload.cached;
|
|
1393
|
+
counts.completed = payload.completed;
|
|
1394
|
+
counts.errored = payload.errored;
|
|
1395
|
+
counts.planned = payload.planned;
|
|
1396
|
+
endedAt = payload.endedAt;
|
|
1397
|
+
},
|
|
1398
|
+
onRunStart: (payload) => {
|
|
1399
|
+
startedAt = payload.startedAt;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
function mergeProgressReporters(base, extra) {
|
|
1405
|
+
if (!base) return extra;
|
|
1406
|
+
if (!extra) return base;
|
|
1407
|
+
return {
|
|
1408
|
+
onDiagnostic: (payload) => {
|
|
1409
|
+
base.onDiagnostic?.(payload);
|
|
1410
|
+
extra.onDiagnostic?.(payload);
|
|
1411
|
+
},
|
|
1412
|
+
onFileEnd: (payload) => {
|
|
1413
|
+
base.onFileEnd?.(payload);
|
|
1414
|
+
extra.onFileEnd?.(payload);
|
|
1415
|
+
},
|
|
1416
|
+
onFileStart: (payload) => {
|
|
1417
|
+
base.onFileStart?.(payload);
|
|
1418
|
+
extra.onFileStart?.(payload);
|
|
1419
|
+
},
|
|
1420
|
+
onRuleEnd: (payload) => {
|
|
1421
|
+
base.onRuleEnd?.(payload);
|
|
1422
|
+
extra.onRuleEnd?.(payload);
|
|
1423
|
+
},
|
|
1424
|
+
onRuleStart: (payload) => {
|
|
1425
|
+
base.onRuleStart?.(payload);
|
|
1426
|
+
extra.onRuleStart?.(payload);
|
|
1427
|
+
},
|
|
1428
|
+
onRunEnd: (payload) => {
|
|
1429
|
+
base.onRunEnd?.(payload);
|
|
1430
|
+
extra.onRunEnd?.(payload);
|
|
1431
|
+
},
|
|
1432
|
+
onRunStart: (payload) => {
|
|
1433
|
+
base.onRunStart?.(payload);
|
|
1434
|
+
extra.onRunStart?.(payload);
|
|
1435
|
+
},
|
|
1436
|
+
onTargetEnd: (payload) => {
|
|
1437
|
+
base.onTargetEnd?.(payload);
|
|
1438
|
+
extra.onTargetEnd?.(payload);
|
|
1439
|
+
},
|
|
1440
|
+
onTargetStart: (payload) => {
|
|
1441
|
+
base.onTargetStart?.(payload);
|
|
1442
|
+
extra.onTargetStart?.(payload);
|
|
1443
|
+
},
|
|
1444
|
+
onUsage: (payload) => {
|
|
1445
|
+
base.onUsage?.(payload);
|
|
1446
|
+
extra.onUsage?.(payload);
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function resolveStatsWrite(stats, env) {
|
|
1451
|
+
if (isCi(env)) return;
|
|
1452
|
+
if (!(stats === false ? false : stats === void 0 || stats === true ? true : stats.enabled !== false)) return;
|
|
1453
|
+
const config = typeof stats === "object" ? stats : void 0;
|
|
1454
|
+
return {
|
|
1455
|
+
dir: config?.location ?? getStatsDir(env),
|
|
1456
|
+
retentionMonths: config?.retentionMonths
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
async function writeRunStats(target, collector, result, cwd) {
|
|
1460
|
+
const store = createJsonlStatsStore({
|
|
1461
|
+
dir: target.dir,
|
|
1462
|
+
retentionMonths: target.retentionMonths
|
|
1463
|
+
});
|
|
1464
|
+
try {
|
|
1465
|
+
await store.record(createRunStat({
|
|
1466
|
+
cwd,
|
|
1467
|
+
durationMs: collector.durationMs(),
|
|
1468
|
+
ruleCounts: collector.counts,
|
|
1469
|
+
usage: result.usage
|
|
1470
|
+
}));
|
|
1471
|
+
} catch {}
|
|
1472
|
+
}
|
|
1051
1473
|
//#endregion
|
|
1052
1474
|
//#region src/cli/commands/lint/index.ts
|
|
1053
1475
|
const lint = defineCommand({
|
|
@@ -1076,7 +1498,22 @@ function isNodeError(error) {
|
|
|
1076
1498
|
async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
1077
1499
|
if (options.config) await assertConfigExists(io.cwd, options.config);
|
|
1078
1500
|
const [setupConfig, config] = await Promise.all([loadMergedSetupConfig(io), loadAlintConfig(io.cwd, options.config)]);
|
|
1079
|
-
|
|
1501
|
+
let lintFiles;
|
|
1502
|
+
try {
|
|
1503
|
+
lintFiles = await findFiles({
|
|
1504
|
+
config,
|
|
1505
|
+
cwd: io.cwd,
|
|
1506
|
+
errorOnUnmatchedPattern: true,
|
|
1507
|
+
globInputPaths: true,
|
|
1508
|
+
inputs: files
|
|
1509
|
+
});
|
|
1510
|
+
} catch (error) {
|
|
1511
|
+
if (error instanceof NoFilesFoundError) {
|
|
1512
|
+
io.stderr.write(`${error.message}\n`);
|
|
1513
|
+
return 2;
|
|
1514
|
+
}
|
|
1515
|
+
throw error;
|
|
1516
|
+
}
|
|
1080
1517
|
const runner = resolveRunnerConfig(setupConfig, { runner: resolveConfigRunner(config) }, options);
|
|
1081
1518
|
const progress = shouldEnableProgress(options, io) ? createCliProgressReporter({
|
|
1082
1519
|
color: io.stderr.isTTY === true,
|
|
@@ -1086,6 +1523,8 @@ async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
|
1086
1523
|
write: (chunk) => io.stderr.write(chunk)
|
|
1087
1524
|
}) : void 0;
|
|
1088
1525
|
const restoreProgressConsole = progress ? interceptConsoleOutput({ write: progress.write }) : void 0;
|
|
1526
|
+
const statsTarget = resolveStatsWrite(runner?.stats, io.env);
|
|
1527
|
+
const statsCollector = statsTarget ? createStatsCollector() : void 0;
|
|
1089
1528
|
let result;
|
|
1090
1529
|
try {
|
|
1091
1530
|
result = await runAlint({
|
|
@@ -1094,7 +1533,7 @@ async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
|
1094
1533
|
files: lintFiles,
|
|
1095
1534
|
modelOverride: options.model,
|
|
1096
1535
|
outputLanguage: options.outputLanguage,
|
|
1097
|
-
progress: progress?.reporter,
|
|
1536
|
+
progress: mergeProgressReporters(progress?.reporter, statsCollector?.reporter),
|
|
1098
1537
|
runner,
|
|
1099
1538
|
setupConfig
|
|
1100
1539
|
});
|
|
@@ -1109,6 +1548,7 @@ async function runLintCommand(files, options, io, interceptConsoleOutput) {
|
|
|
1109
1548
|
}
|
|
1110
1549
|
restoreProgressConsole?.();
|
|
1111
1550
|
progress?.dispose();
|
|
1551
|
+
if (statsTarget && statsCollector) await writeRunStats(statsTarget, statsCollector, result, io.cwd);
|
|
1112
1552
|
io.stdout.write(formatDiagnostics(options.format, result, { color: io.stdout.isTTY === true }));
|
|
1113
1553
|
return result.diagnostics.length > 0 ? 1 : 0;
|
|
1114
1554
|
}
|
|
@@ -1531,11 +1971,112 @@ function toArray(value) {
|
|
|
1531
1971
|
return (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
|
|
1532
1972
|
}
|
|
1533
1973
|
//#endregion
|
|
1974
|
+
//#region src/cli/commands/stats/format.ts
|
|
1975
|
+
const colors = createColors({ force: true });
|
|
1976
|
+
const DIMENSION_LABEL = {
|
|
1977
|
+
dir: "directory",
|
|
1978
|
+
model: "model",
|
|
1979
|
+
operation: "operation",
|
|
1980
|
+
rule: "rule"
|
|
1981
|
+
};
|
|
1982
|
+
function formatStatsAggregate(aggregate, options = {}) {
|
|
1983
|
+
const paint = (text, style) => options.color === true ? style(text) : text;
|
|
1984
|
+
const runLabel = aggregate.totalRuns === 1 ? "run" : "runs";
|
|
1985
|
+
const lines = [`${aggregate.totalRuns} ${runLabel} — ${formatTokens(aggregate.totalIn)} in / ${formatTokens(aggregate.totalOut)} out / ${paint(`${formatTokens(aggregate.totalTok)} total`, colors.cyan)}`, ""];
|
|
1986
|
+
if (aggregate.rows.length === 0) {
|
|
1987
|
+
lines.push("No stats recorded yet.");
|
|
1988
|
+
return `${lines.join("\n")}\n`;
|
|
1989
|
+
}
|
|
1990
|
+
const header = [
|
|
1991
|
+
DIMENSION_LABEL[aggregate.dimension],
|
|
1992
|
+
"runs",
|
|
1993
|
+
"input",
|
|
1994
|
+
"output",
|
|
1995
|
+
"total"
|
|
1996
|
+
];
|
|
1997
|
+
const rows = aggregate.rows.map((row) => [
|
|
1998
|
+
row.key,
|
|
1999
|
+
String(row.runs),
|
|
2000
|
+
formatTokens(row.inTok),
|
|
2001
|
+
formatTokens(row.outTok),
|
|
2002
|
+
formatTokens(row.totalTok)
|
|
2003
|
+
]);
|
|
2004
|
+
const widths = header.map((cell, index) => Math.max(cell.length, ...rows.map((row) => row[index].length)));
|
|
2005
|
+
const renderRow = (cells, isHeader) => cells.map((cell, index) => {
|
|
2006
|
+
const aligned = index === 0 ? cell.padEnd(widths[index]) : cell.padStart(widths[index]);
|
|
2007
|
+
return isHeader ? paint(aligned, colors.bold) : aligned;
|
|
2008
|
+
}).join(" ");
|
|
2009
|
+
lines.push(renderRow(header, true), ...rows.map((row) => renderRow(row, false)));
|
|
2010
|
+
return `${lines.join("\n")}\n`;
|
|
2011
|
+
}
|
|
2012
|
+
function formatTokens(value) {
|
|
2013
|
+
return value.toLocaleString("en-US");
|
|
2014
|
+
}
|
|
2015
|
+
//#endregion
|
|
2016
|
+
//#region src/cli/commands/stats/stats.ts
|
|
2017
|
+
const DIMENSIONS = /* @__PURE__ */ new Set([
|
|
2018
|
+
"dir",
|
|
2019
|
+
"model",
|
|
2020
|
+
"operation",
|
|
2021
|
+
"rule"
|
|
2022
|
+
]);
|
|
2023
|
+
async function runStatsCommand(options, io) {
|
|
2024
|
+
try {
|
|
2025
|
+
const dimension = parseDimension(options.by);
|
|
2026
|
+
const [setupConfig, config] = await Promise.all([loadMergedSetupConfig(io), loadAlintConfig(io.cwd)]);
|
|
2027
|
+
const aggregate = await createJsonlStatsStore({ dir: statsLocation(resolveConfigRunner(config)?.stats) ?? statsLocation(setupConfig.runner?.stats) ?? getStatsDir(io.env) }).query({
|
|
2028
|
+
by: dimension,
|
|
2029
|
+
cwd: options.here === true ? io.cwd : options.cwd,
|
|
2030
|
+
since: options.since
|
|
2031
|
+
});
|
|
2032
|
+
io.stdout.write(options.json === true ? `${JSON.stringify(aggregate, null, 2)}\n` : formatStatsAggregate(aggregate, { color: io.stdout.isTTY === true }));
|
|
2033
|
+
return 0;
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
io.stderr.write(`${errorMessageFrom$1(error) ?? "Failed to read stats."}\n`);
|
|
2036
|
+
return 2;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
function parseDimension(value) {
|
|
2040
|
+
if (value === void 0) return "model";
|
|
2041
|
+
if (DIMENSIONS.has(value)) return value;
|
|
2042
|
+
throw new Error(`Invalid --by "${value}": use rule, operation, model, or dir.`);
|
|
2043
|
+
}
|
|
2044
|
+
function statsLocation(stats) {
|
|
2045
|
+
return typeof stats === "object" ? stats.location : void 0;
|
|
2046
|
+
}
|
|
2047
|
+
//#endregion
|
|
1534
2048
|
//#region src/cli/commands/index.ts
|
|
1535
2049
|
const commandTree = [
|
|
1536
2050
|
setup,
|
|
1537
2051
|
config,
|
|
1538
2052
|
output,
|
|
2053
|
+
defineCommand({
|
|
2054
|
+
action: (context, options) => runStatsCommand(options, context.io),
|
|
2055
|
+
description: "Show recorded run stats",
|
|
2056
|
+
name: "stats",
|
|
2057
|
+
options: [
|
|
2058
|
+
{
|
|
2059
|
+
description: "Group by rule, operation, model, or dir",
|
|
2060
|
+
flags: "--by <dimension>"
|
|
2061
|
+
},
|
|
2062
|
+
{
|
|
2063
|
+
description: "Only include runs since this time (e.g. 7d, 24h, 2025-01)",
|
|
2064
|
+
flags: "--since <time>"
|
|
2065
|
+
},
|
|
2066
|
+
{
|
|
2067
|
+
description: "Only include runs from this directory",
|
|
2068
|
+
flags: "--cwd <path>"
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
description: "Only include runs from the current directory",
|
|
2072
|
+
flags: "--here"
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
description: "Output JSON",
|
|
2076
|
+
flags: "--json"
|
|
2077
|
+
}
|
|
2078
|
+
]
|
|
2079
|
+
}),
|
|
1539
2080
|
lint
|
|
1540
2081
|
];
|
|
1541
2082
|
//#endregion
|
|
@@ -1549,7 +2090,7 @@ async function executeCli(argv, io) {
|
|
|
1549
2090
|
pendingResult = result;
|
|
1550
2091
|
return result;
|
|
1551
2092
|
};
|
|
1552
|
-
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("-l, --lang <language>", "Ask model-backed rules to write diagnostics in this language").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();
|
|
2093
|
+
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("-l, --lang <language>", "Ask model-backed rules to write diagnostics in this language").option("--progress", "Show run progress").option("--rule-concurrency <count>", "Number of rules to run concurrently within a file").option("--no-stats", "Do not record run stats for this run").option("--timeout-ms <ms>", "Rule execution timeout in milliseconds").help();
|
|
1553
2094
|
registerCommandTree(cli, commandTree, {
|
|
1554
2095
|
globalOptions,
|
|
1555
2096
|
interceptConsoleOutput,
|
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-D4YC9Jnb.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.10",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.mts",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"pathe": "^2.0.3",
|
|
26
26
|
"table": "^6.9.0",
|
|
27
27
|
"tinyrainbow": "^3.1.0",
|
|
28
|
-
"@alint-js/core": "0.0.
|
|
29
|
-
"@alint-js/config": "0.0.
|
|
28
|
+
"@alint-js/core": "0.0.10",
|
|
29
|
+
"@alint-js/config": "0.0.10"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^26.0.1",
|