aislop 0.8.2 → 0.9.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/dist/cli.js +558 -128
- package/dist/index.js +419 -77
- package/dist/{json-DxLkV8n2.js → json-DZfGz2xa.js} +1 -1
- package/dist/{json-BbMwrgyd.js → json-OIzja7OM.js} +1 -1
- package/dist/mcp.js +273 -10
- package/dist/{typecheck-B1MXNAy-.js → typecheck-wVSohmOX.js} +1 -1
- package/dist/{version-G3ekYjY1.js → version-D_rqBdyj.js} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as ENGINE_INFO, r as getEngineLabel, t as APP_VERSION } from "./version-
|
|
1
|
+
import { n as ENGINE_INFO, r as getEngineLabel, t as APP_VERSION } from "./version-D_rqBdyj.js";
|
|
2
2
|
import { n as runSubprocess, t as isToolInstalled } from "./subprocess-CQUJDGgn.js";
|
|
3
3
|
import { r as runGenericLinter, t as fixRubyLint } from "./generic-BrcWMW7E.js";
|
|
4
4
|
import { n as runExpoDoctor } from "./expo-doctor-Bz0LZhQ6.js";
|
|
@@ -15,6 +15,7 @@ import { fileURLToPath } from "node:url";
|
|
|
15
15
|
import { performance } from "node:perf_hooks";
|
|
16
16
|
import os from "node:os";
|
|
17
17
|
import ts from "typescript";
|
|
18
|
+
import { randomUUID } from "node:crypto";
|
|
18
19
|
import { isCancel, multiselect, select, text } from "@clack/prompts";
|
|
19
20
|
|
|
20
21
|
//#region src/config/defaults.ts
|
|
@@ -1994,6 +1995,27 @@ const collectJsDeps = (rootDir, jsDeps) => {
|
|
|
1994
1995
|
collectNestedManifests(rootDir, jsDeps);
|
|
1995
1996
|
return true;
|
|
1996
1997
|
};
|
|
1998
|
+
const TS_CONFIG_FILES = ["tsconfig.json", "jsconfig.json"];
|
|
1999
|
+
const buildAliasMatcher = (key) => {
|
|
2000
|
+
const starIdx = key.indexOf("*");
|
|
2001
|
+
if (starIdx === -1) return (spec) => spec === key;
|
|
2002
|
+
const before = key.slice(0, starIdx);
|
|
2003
|
+
const after = key.slice(starIdx + 1);
|
|
2004
|
+
return (spec) => spec.length >= before.length + after.length && spec.startsWith(before) && spec.endsWith(after);
|
|
2005
|
+
};
|
|
2006
|
+
const collectAliasMatchersFromConfig = (configPath, matchers) => {
|
|
2007
|
+
const opts = readJson(configPath)?.compilerOptions;
|
|
2008
|
+
if (!opts || typeof opts !== "object") return;
|
|
2009
|
+
const paths = opts.paths;
|
|
2010
|
+
if (!paths || typeof paths !== "object") return;
|
|
2011
|
+
for (const key of Object.keys(paths)) matchers.push(buildAliasMatcher(key));
|
|
2012
|
+
};
|
|
2013
|
+
const collectTsPathAliases = (rootDir) => {
|
|
2014
|
+
const matchers = [];
|
|
2015
|
+
const dirs = [rootDir, ...expandWorkspaceDirs(rootDir, readWorkspaceGlobs(rootDir, readJson(path.join(rootDir, "package.json"))))];
|
|
2016
|
+
for (const dir of dirs) for (const fname of TS_CONFIG_FILES) collectAliasMatchersFromConfig(path.join(dir, fname), matchers);
|
|
2017
|
+
return matchers;
|
|
2018
|
+
};
|
|
1997
2019
|
const addPyDep = (pyDeps, name) => {
|
|
1998
2020
|
const normalized = name.toLowerCase().replace(/_/g, "-");
|
|
1999
2021
|
pyDeps.add(normalized);
|
|
@@ -2151,10 +2173,11 @@ const extractPyImports = (content) => {
|
|
|
2151
2173
|
}
|
|
2152
2174
|
return results;
|
|
2153
2175
|
};
|
|
2154
|
-
const checkJsImport = (spec, manifest) => {
|
|
2176
|
+
const checkJsImport = (spec, manifest, tsAliasMatchers) => {
|
|
2155
2177
|
if (isJsRelativeOrAbsolute(spec)) return null;
|
|
2156
2178
|
if (isJsBuiltin(spec)) return null;
|
|
2157
2179
|
if (isJsVirtualModule(spec)) return null;
|
|
2180
|
+
if (tsAliasMatchers.some((m) => m(spec))) return null;
|
|
2158
2181
|
const pkg = packageNameFromImport(spec);
|
|
2159
2182
|
if (manifest.jsDeps.has(pkg)) return null;
|
|
2160
2183
|
if (pkg.startsWith("@types/")) {
|
|
@@ -2175,6 +2198,7 @@ const checkPyImport = (spec, manifest) => {
|
|
|
2175
2198
|
const detectHallucinatedImports = async (context) => {
|
|
2176
2199
|
const manifest = loadManifest(context.rootDirectory);
|
|
2177
2200
|
if (!manifest.hasJsManifest && !manifest.hasPyManifest) return [];
|
|
2201
|
+
const tsAliasMatchers = manifest.hasJsManifest ? collectTsPathAliases(context.rootDirectory) : [];
|
|
2178
2202
|
const diagnostics = [];
|
|
2179
2203
|
const files = getSourceFiles(context);
|
|
2180
2204
|
for (const filePath of files) {
|
|
@@ -2194,7 +2218,7 @@ const detectHallucinatedImports = async (context) => {
|
|
|
2194
2218
|
const relPath = path.relative(context.rootDirectory, filePath);
|
|
2195
2219
|
const imports = isJs ? extractJsImports(content) : extractPyImports(content);
|
|
2196
2220
|
for (const { spec, line } of imports) {
|
|
2197
|
-
const hallucinated = isJs ? checkJsImport(spec, manifest) : checkPyImport(spec, manifest);
|
|
2221
|
+
const hallucinated = isJs ? checkJsImport(spec, manifest, tsAliasMatchers) : checkPyImport(spec, manifest);
|
|
2198
2222
|
if (!hallucinated) continue;
|
|
2199
2223
|
const manifestLabel = isJs ? "package.json" : "requirements.txt / pyproject.toml / Pipfile";
|
|
2200
2224
|
diagnostics.push({
|
|
@@ -5851,60 +5875,348 @@ var LiveRail = class {
|
|
|
5851
5875
|
};
|
|
5852
5876
|
|
|
5853
5877
|
//#endregion
|
|
5854
|
-
//#region src/
|
|
5855
|
-
const
|
|
5856
|
-
const
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
if (
|
|
5863
|
-
if (
|
|
5864
|
-
if (
|
|
5865
|
-
return
|
|
5866
|
-
|
|
5867
|
-
|
|
5878
|
+
//#region src/telemetry/env.ts
|
|
5879
|
+
const detectPackageManager$1 = (env = process.env) => {
|
|
5880
|
+
const execPath = env.npm_execpath ?? "";
|
|
5881
|
+
if (execPath.includes("npx")) return "npx";
|
|
5882
|
+
const userAgent = env.npm_config_user_agent ?? "";
|
|
5883
|
+
if (userAgent.startsWith("pnpm/")) return "pnpm";
|
|
5884
|
+
if (userAgent.startsWith("yarn/")) return "yarn";
|
|
5885
|
+
if (userAgent.startsWith("bun/")) return "bun";
|
|
5886
|
+
if (userAgent.startsWith("npm/")) return "npm";
|
|
5887
|
+
if (execPath.includes("pnpm")) return "pnpm";
|
|
5888
|
+
if (execPath.includes("yarn")) return "yarn";
|
|
5889
|
+
if (execPath.includes("bun")) return "bun";
|
|
5890
|
+
if (execPath.includes("npm")) return "npm";
|
|
5891
|
+
return "unknown";
|
|
5892
|
+
};
|
|
5893
|
+
const CI_ENV_KEYS = [
|
|
5894
|
+
"CI",
|
|
5895
|
+
"GITHUB_ACTIONS",
|
|
5896
|
+
"GITLAB_CI",
|
|
5897
|
+
"CIRCLECI",
|
|
5898
|
+
"TRAVIS",
|
|
5899
|
+
"BUILDKITE",
|
|
5900
|
+
"DRONE",
|
|
5901
|
+
"TEAMCITY_VERSION",
|
|
5902
|
+
"TF_BUILD"
|
|
5903
|
+
];
|
|
5904
|
+
const isCiEnv = (env = process.env) => CI_ENV_KEYS.some((k) => {
|
|
5905
|
+
const v = env[k];
|
|
5906
|
+
return v === "true" || v === "1" || v != null && v.length > 0 && k !== "CI";
|
|
5907
|
+
}) || env.CI === "true" || env.CI === "1";
|
|
5908
|
+
const fileCountBucket = (count) => {
|
|
5909
|
+
if (count < 10) return "0-10";
|
|
5910
|
+
if (count < 50) return "10-50";
|
|
5911
|
+
if (count < 100) return "50-100";
|
|
5912
|
+
if (count < 500) return "100-500";
|
|
5913
|
+
if (count < 1e3) return "500-1000";
|
|
5914
|
+
return "1000+";
|
|
5915
|
+
};
|
|
5916
|
+
const scoreBucket = (score) => {
|
|
5868
5917
|
if (score >= 75) return "75-100";
|
|
5869
5918
|
if (score >= 50) return "50-75";
|
|
5870
5919
|
if (score >= 25) return "25-50";
|
|
5871
5920
|
return "0-25";
|
|
5872
5921
|
};
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5922
|
+
|
|
5923
|
+
//#endregion
|
|
5924
|
+
//#region src/telemetry/identity.ts
|
|
5925
|
+
const FILE_BASENAME = "install_id";
|
|
5926
|
+
const resolveInstallIdPath = (homedir = os.homedir(), env = process.env) => {
|
|
5927
|
+
if (process.platform === "linux" && env.XDG_STATE_HOME) return path.join(env.XDG_STATE_HOME, "aislop", FILE_BASENAME);
|
|
5928
|
+
return path.join(homedir, ".aislop", FILE_BASENAME);
|
|
5929
|
+
};
|
|
5930
|
+
const ensureInstallId = (idPath = resolveInstallIdPath()) => {
|
|
5931
|
+
if (fs.existsSync(idPath)) {
|
|
5932
|
+
const existing = fs.readFileSync(idPath, "utf-8").trim();
|
|
5933
|
+
if (existing.length > 0) return {
|
|
5934
|
+
installId: existing,
|
|
5935
|
+
created: false
|
|
5936
|
+
};
|
|
5937
|
+
}
|
|
5938
|
+
const dir = path.dirname(idPath);
|
|
5939
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
5940
|
+
const installId = randomUUID();
|
|
5941
|
+
const tmpPath = `${idPath}.${process.pid}.tmp`;
|
|
5942
|
+
fs.writeFileSync(tmpPath, `${installId}\n`, { mode: 384 });
|
|
5943
|
+
try {
|
|
5944
|
+
fs.renameSync(tmpPath, idPath);
|
|
5945
|
+
return {
|
|
5946
|
+
installId,
|
|
5947
|
+
created: true
|
|
5948
|
+
};
|
|
5949
|
+
} catch {
|
|
5950
|
+
fs.rmSync(tmpPath, { force: true });
|
|
5951
|
+
return {
|
|
5952
|
+
installId: fs.readFileSync(idPath, "utf-8").trim(),
|
|
5953
|
+
created: false
|
|
5954
|
+
};
|
|
5955
|
+
}
|
|
5956
|
+
};
|
|
5957
|
+
|
|
5958
|
+
//#endregion
|
|
5959
|
+
//#region src/telemetry/redaction.ts
|
|
5960
|
+
const SAFE_PROPERTY_NAMES = new Set([
|
|
5961
|
+
"aislop_version",
|
|
5962
|
+
"node_version",
|
|
5963
|
+
"os",
|
|
5964
|
+
"arch",
|
|
5965
|
+
"schema_version",
|
|
5966
|
+
"anonymous_install_id",
|
|
5967
|
+
"package_manager",
|
|
5968
|
+
"is_ci",
|
|
5969
|
+
"command",
|
|
5970
|
+
"language_summary",
|
|
5971
|
+
"lang_typescript",
|
|
5972
|
+
"lang_javascript",
|
|
5973
|
+
"lang_python",
|
|
5974
|
+
"lang_java",
|
|
5975
|
+
"file_count_bucket",
|
|
5976
|
+
"exit_code",
|
|
5977
|
+
"duration_ms",
|
|
5978
|
+
"error_kind",
|
|
5979
|
+
"score",
|
|
5980
|
+
"score_bucket",
|
|
5981
|
+
"finding_count",
|
|
5982
|
+
"error_count",
|
|
5983
|
+
"warning_count",
|
|
5984
|
+
"fixable_count",
|
|
5985
|
+
"fix_steps",
|
|
5986
|
+
"fix_resolved",
|
|
5987
|
+
"fix_score_delta",
|
|
5988
|
+
"engine_format_issues",
|
|
5989
|
+
"engine_format_ms",
|
|
5990
|
+
"engine_lint_issues",
|
|
5991
|
+
"engine_lint_ms",
|
|
5992
|
+
"engine_code_quality_issues",
|
|
5993
|
+
"engine_code_quality_ms",
|
|
5994
|
+
"engine_ai_slop_issues",
|
|
5995
|
+
"engine_ai_slop_ms",
|
|
5996
|
+
"engine_architecture_issues",
|
|
5997
|
+
"engine_architecture_ms",
|
|
5998
|
+
"engine_security_issues",
|
|
5999
|
+
"engine_security_ms",
|
|
6000
|
+
"tool",
|
|
6001
|
+
"ok",
|
|
6002
|
+
"agent",
|
|
6003
|
+
"score_delta"
|
|
6004
|
+
]);
|
|
6005
|
+
const redactProperties = (props) => {
|
|
6006
|
+
const clean = {};
|
|
6007
|
+
const dropped = [];
|
|
6008
|
+
for (const [key, value] of Object.entries(props)) {
|
|
6009
|
+
if (value === void 0) continue;
|
|
6010
|
+
if (SAFE_PROPERTY_NAMES.has(key)) clean[key] = value;
|
|
6011
|
+
else dropped.push(key);
|
|
6012
|
+
}
|
|
6013
|
+
return {
|
|
6014
|
+
clean,
|
|
6015
|
+
dropped
|
|
6016
|
+
};
|
|
6017
|
+
};
|
|
6018
|
+
|
|
6019
|
+
//#endregion
|
|
6020
|
+
//#region src/telemetry/client.ts
|
|
6021
|
+
const POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
6022
|
+
const POSTHOG_KEY = "phc_eY2cOMFva9q24GrWeOuvuVIOhCIdjOALxeAR3ItrqbJ";
|
|
6023
|
+
const SCHEMA_VERSION = "v2";
|
|
6024
|
+
const REQUEST_TIMEOUT_MS = 3e3;
|
|
6025
|
+
const isTelemetryDisabled = (config) => {
|
|
6026
|
+
const env = process.env;
|
|
6027
|
+
if (env.AISLOP_NO_TELEMETRY === "1" || env.DO_NOT_TRACK === "1") return true;
|
|
6028
|
+
if (config?.enabled === false) return true;
|
|
6029
|
+
if (config?.enabled === true) return false;
|
|
6030
|
+
if (env.CI === "true" || env.CI === "1") return true;
|
|
6031
|
+
return false;
|
|
5878
6032
|
};
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
6033
|
+
const isDebug = () => process.env.AISLOP_TELEMETRY_DEBUG === "1";
|
|
6034
|
+
const pendingRequests = /* @__PURE__ */ new Set();
|
|
6035
|
+
let cachedInstallId = null;
|
|
6036
|
+
let installCreated = false;
|
|
6037
|
+
const baseProperties = (installId) => ({
|
|
6038
|
+
aislop_version: APP_VERSION,
|
|
6039
|
+
node_version: process.version,
|
|
6040
|
+
os: os.platform(),
|
|
6041
|
+
arch: os.arch(),
|
|
6042
|
+
schema_version: SCHEMA_VERSION,
|
|
6043
|
+
anonymous_install_id: installId,
|
|
6044
|
+
package_manager: detectPackageManager$1(),
|
|
6045
|
+
is_ci: isCiEnv()
|
|
6046
|
+
});
|
|
6047
|
+
const track = (input) => {
|
|
6048
|
+
if (isTelemetryDisabled(input.config)) return { installCreated: false };
|
|
6049
|
+
if (cachedInstallId == null) {
|
|
6050
|
+
const ensured = ensureInstallId(resolveInstallIdPath());
|
|
6051
|
+
cachedInstallId = ensured.installId;
|
|
6052
|
+
installCreated = ensured.created;
|
|
6053
|
+
}
|
|
6054
|
+
const { clean, dropped } = redactProperties({
|
|
6055
|
+
...baseProperties(cachedInstallId),
|
|
6056
|
+
...input.properties
|
|
6057
|
+
});
|
|
6058
|
+
if (isDebug()) {
|
|
6059
|
+
const compact = JSON.stringify({
|
|
6060
|
+
event: input.event,
|
|
6061
|
+
properties: clean
|
|
6062
|
+
});
|
|
6063
|
+
process.stderr.write(`[telemetry] ${compact}\n`);
|
|
6064
|
+
if (dropped.length > 0) for (const key of dropped) process.stderr.write(`[telemetry] dropped non-allowlisted property: ${key}\n`);
|
|
6065
|
+
}
|
|
6066
|
+
if (process.env.AISLOP_TELEMETRY_DRY_RUN === "1") return { installCreated };
|
|
5882
6067
|
const payload = {
|
|
5883
6068
|
api_key: POSTHOG_KEY,
|
|
5884
|
-
event:
|
|
5885
|
-
distinct_id:
|
|
5886
|
-
properties:
|
|
5887
|
-
version: APP_VERSION,
|
|
5888
|
-
node_version: process.version,
|
|
5889
|
-
os: os.platform(),
|
|
5890
|
-
arch: os.arch(),
|
|
5891
|
-
languages: event.languages,
|
|
5892
|
-
score_bucket: event.scoreBucket,
|
|
5893
|
-
engine_issues: event.engineIssues,
|
|
5894
|
-
engine_timings: event.engineTimings,
|
|
5895
|
-
elapsed_ms: event.elapsedMs,
|
|
5896
|
-
file_count: event.fileCount,
|
|
5897
|
-
fix_steps: event.fixSteps,
|
|
5898
|
-
fix_resolved: event.fixResolved
|
|
5899
|
-
},
|
|
6069
|
+
event: input.event,
|
|
6070
|
+
distinct_id: cachedInstallId,
|
|
6071
|
+
properties: clean,
|
|
5900
6072
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5901
6073
|
};
|
|
5902
|
-
|
|
6074
|
+
const request = fetch(`${POSTHOG_HOST}/capture/`, {
|
|
5903
6075
|
method: "POST",
|
|
5904
6076
|
headers: { "Content-Type": "application/json" },
|
|
5905
6077
|
body: JSON.stringify(payload),
|
|
5906
|
-
signal: AbortSignal.timeout(
|
|
5907
|
-
}).then(() => {}).catch(() => {})
|
|
6078
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
6079
|
+
}).then(() => {}).catch(() => {}).finally(() => {
|
|
6080
|
+
pendingRequests.delete(request);
|
|
6081
|
+
});
|
|
6082
|
+
pendingRequests.add(request);
|
|
6083
|
+
return { installCreated };
|
|
6084
|
+
};
|
|
6085
|
+
const flushTelemetry = async () => {
|
|
6086
|
+
if (pendingRequests.size === 0) return;
|
|
6087
|
+
await Promise.all(pendingRequests);
|
|
6088
|
+
};
|
|
6089
|
+
|
|
6090
|
+
//#endregion
|
|
6091
|
+
//#region src/telemetry/language.ts
|
|
6092
|
+
const ALL_LANGUAGES = [
|
|
6093
|
+
"typescript",
|
|
6094
|
+
"javascript",
|
|
6095
|
+
"python",
|
|
6096
|
+
"java"
|
|
6097
|
+
];
|
|
6098
|
+
const buildLanguageProperties = (detected) => {
|
|
6099
|
+
const present = new Set(detected);
|
|
6100
|
+
const summary = [...present].filter((l) => ALL_LANGUAGES.includes(l));
|
|
6101
|
+
summary.sort();
|
|
6102
|
+
return {
|
|
6103
|
+
language_summary: summary.join(","),
|
|
6104
|
+
lang_typescript: present.has("typescript"),
|
|
6105
|
+
lang_javascript: present.has("javascript"),
|
|
6106
|
+
lang_python: present.has("python"),
|
|
6107
|
+
lang_java: present.has("java")
|
|
6108
|
+
};
|
|
6109
|
+
};
|
|
6110
|
+
|
|
6111
|
+
//#endregion
|
|
6112
|
+
//#region src/telemetry/events.ts
|
|
6113
|
+
const buildCommandStartedProps = (input) => {
|
|
6114
|
+
const props = { command: input.command };
|
|
6115
|
+
if (input.languages) Object.assign(props, buildLanguageProperties(input.languages));
|
|
6116
|
+
if (typeof input.fileCount === "number") props.file_count_bucket = fileCountBucket(input.fileCount);
|
|
6117
|
+
return props;
|
|
6118
|
+
};
|
|
6119
|
+
const ENGINE_KEY_MAP = {
|
|
6120
|
+
format: "engine_format",
|
|
6121
|
+
lint: "engine_lint",
|
|
6122
|
+
"code-quality": "engine_code_quality",
|
|
6123
|
+
"ai-slop": "engine_ai_slop",
|
|
6124
|
+
architecture: "engine_architecture",
|
|
6125
|
+
security: "engine_security"
|
|
6126
|
+
};
|
|
6127
|
+
const flattenEngineStats = (issues, timings) => {
|
|
6128
|
+
const out = {};
|
|
6129
|
+
for (const [engine, count] of Object.entries(issues)) {
|
|
6130
|
+
const key = ENGINE_KEY_MAP[engine];
|
|
6131
|
+
if (key != null && typeof count === "number") out[`${key}_issues`] = count;
|
|
6132
|
+
}
|
|
6133
|
+
for (const [engine, ms] of Object.entries(timings)) {
|
|
6134
|
+
const key = ENGINE_KEY_MAP[engine];
|
|
6135
|
+
if (key != null && typeof ms === "number") out[`${key}_ms`] = Math.round(ms);
|
|
6136
|
+
}
|
|
6137
|
+
return out;
|
|
6138
|
+
};
|
|
6139
|
+
const buildCommandCompletedProps = (input) => {
|
|
6140
|
+
const props = {
|
|
6141
|
+
...input.startProps,
|
|
6142
|
+
exit_code: input.exitCode,
|
|
6143
|
+
duration_ms: Math.round(input.durationMs)
|
|
6144
|
+
};
|
|
6145
|
+
if (input.errorKind) props.error_kind = input.errorKind;
|
|
6146
|
+
if (typeof input.score === "number") {
|
|
6147
|
+
props.score = input.score;
|
|
6148
|
+
props.score_bucket = scoreBucket(input.score);
|
|
6149
|
+
}
|
|
6150
|
+
if (typeof input.findingCount === "number") props.finding_count = input.findingCount;
|
|
6151
|
+
if (typeof input.errorCount === "number") props.error_count = input.errorCount;
|
|
6152
|
+
if (typeof input.warningCount === "number") props.warning_count = input.warningCount;
|
|
6153
|
+
if (typeof input.fixableCount === "number") props.fixable_count = input.fixableCount;
|
|
6154
|
+
if (input.engineIssues && input.engineTimings) Object.assign(props, flattenEngineStats(input.engineIssues, input.engineTimings));
|
|
6155
|
+
if (typeof input.fixSteps === "number") props.fix_steps = input.fixSteps;
|
|
6156
|
+
if (typeof input.fixResolved === "number") props.fix_resolved = input.fixResolved;
|
|
6157
|
+
if (typeof input.fixScoreDelta === "number") props.fix_score_delta = input.fixScoreDelta;
|
|
6158
|
+
return props;
|
|
6159
|
+
};
|
|
6160
|
+
const errorKindFromException = (error) => {
|
|
6161
|
+
const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
6162
|
+
if (message.includes("timeout") || message.includes("timed out")) return "timeout";
|
|
6163
|
+
if (message.includes("invalid config") || message.includes("config_invalid")) return "config_invalid";
|
|
6164
|
+
if (message.includes("engine") && message.includes("crash")) return "engine_crash";
|
|
6165
|
+
return "unknown";
|
|
6166
|
+
};
|
|
6167
|
+
|
|
6168
|
+
//#endregion
|
|
6169
|
+
//#region src/telemetry/lifecycle.ts
|
|
6170
|
+
const withCommandLifecycle = async (start, run) => {
|
|
6171
|
+
const startProps = buildCommandStartedProps({
|
|
6172
|
+
command: start.command,
|
|
6173
|
+
languages: start.languages,
|
|
6174
|
+
fileCount: start.fileCount
|
|
6175
|
+
});
|
|
6176
|
+
track({
|
|
6177
|
+
event: "cli_command_started",
|
|
6178
|
+
properties: startProps,
|
|
6179
|
+
config: start.config
|
|
6180
|
+
});
|
|
6181
|
+
const startedAt = performance.now();
|
|
6182
|
+
try {
|
|
6183
|
+
const result = await run();
|
|
6184
|
+
const durationMs = performance.now() - startedAt;
|
|
6185
|
+
track({
|
|
6186
|
+
event: "cli_command_completed",
|
|
6187
|
+
properties: buildCommandCompletedProps({
|
|
6188
|
+
startProps,
|
|
6189
|
+
exitCode: result.exitCode,
|
|
6190
|
+
durationMs,
|
|
6191
|
+
score: result.score,
|
|
6192
|
+
findingCount: result.findingCount,
|
|
6193
|
+
errorCount: result.errorCount,
|
|
6194
|
+
warningCount: result.warningCount,
|
|
6195
|
+
fixableCount: result.fixableCount,
|
|
6196
|
+
engineIssues: result.engineIssues,
|
|
6197
|
+
engineTimings: result.engineTimings,
|
|
6198
|
+
fixSteps: result.fixSteps,
|
|
6199
|
+
fixResolved: result.fixResolved,
|
|
6200
|
+
fixScoreDelta: result.fixScoreDelta
|
|
6201
|
+
}),
|
|
6202
|
+
config: start.config
|
|
6203
|
+
});
|
|
6204
|
+
await flushTelemetry();
|
|
6205
|
+
return result;
|
|
6206
|
+
} catch (error) {
|
|
6207
|
+
track({
|
|
6208
|
+
event: "cli_command_completed",
|
|
6209
|
+
properties: buildCommandCompletedProps({
|
|
6210
|
+
startProps,
|
|
6211
|
+
exitCode: 1,
|
|
6212
|
+
durationMs: performance.now() - startedAt,
|
|
6213
|
+
errorKind: errorKindFromException(error)
|
|
6214
|
+
}),
|
|
6215
|
+
config: start.config
|
|
6216
|
+
});
|
|
6217
|
+
await flushTelemetry();
|
|
6218
|
+
throw error;
|
|
6219
|
+
}
|
|
5908
6220
|
};
|
|
5909
6221
|
|
|
5910
6222
|
//#endregion
|
|
@@ -6275,7 +6587,6 @@ const buildScanRender = (input) => {
|
|
|
6275
6587
|
}, deps)}`;
|
|
6276
6588
|
};
|
|
6277
6589
|
const scanCommand = async (directory, config, options) => {
|
|
6278
|
-
const startTime = performance.now();
|
|
6279
6590
|
const resolvedDir = path.resolve(directory);
|
|
6280
6591
|
if (!fs.existsSync(resolvedDir)) {
|
|
6281
6592
|
const msg = `Path does not exist: ${resolvedDir}`;
|
|
@@ -6289,9 +6600,18 @@ const scanCommand = async (directory, config, options) => {
|
|
|
6289
6600
|
else log.error(msg);
|
|
6290
6601
|
return { exitCode: 1 };
|
|
6291
6602
|
}
|
|
6603
|
+
const projectInfo = await discoverProject(resolvedDir);
|
|
6604
|
+
return withCommandLifecycle({
|
|
6605
|
+
command: options.command ?? "scan",
|
|
6606
|
+
config: config.telemetry,
|
|
6607
|
+
languages: projectInfo.languages,
|
|
6608
|
+
fileCount: projectInfo.sourceFileCount
|
|
6609
|
+
}, () => runScanBody(resolvedDir, config, options, projectInfo));
|
|
6610
|
+
};
|
|
6611
|
+
const runScanBody = async (resolvedDir, config, options, projectInfo) => {
|
|
6612
|
+
const startTime = performance.now();
|
|
6292
6613
|
const showHeader = options.showHeader !== false;
|
|
6293
6614
|
const useLiveProgress = !options.json && shouldUseSpinner();
|
|
6294
|
-
const projectInfo = await discoverProject(resolvedDir);
|
|
6295
6615
|
let files;
|
|
6296
6616
|
if (options.staged) {
|
|
6297
6617
|
files = filterProjectFiles(resolvedDir, getStagedFiles(resolvedDir), [], config.exclude);
|
|
@@ -6358,28 +6678,27 @@ const scanCommand = async (directory, config, options) => {
|
|
|
6358
6678
|
const elapsedMs = performance.now() - startTime;
|
|
6359
6679
|
const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds, projectInfo.sourceFileCount, config.scoring.smoothing);
|
|
6360
6680
|
const exitCode = allDiagnostics.some((d) => d.severity === "error") || scoreResult.score < config.ci.failBelow ? 1 : 0;
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
}
|
|
6681
|
+
const engineIssues = {};
|
|
6682
|
+
const engineTimings = {};
|
|
6683
|
+
for (const r of results) {
|
|
6684
|
+
engineIssues[r.engine] = r.diagnostics.length;
|
|
6685
|
+
engineTimings[r.engine] = Math.round(r.elapsed);
|
|
6686
|
+
}
|
|
6687
|
+
const completion = {
|
|
6688
|
+
exitCode,
|
|
6689
|
+
score: scoreResult.score,
|
|
6690
|
+
findingCount: allDiagnostics.length,
|
|
6691
|
+
errorCount: allDiagnostics.filter((d) => d.severity === "error").length,
|
|
6692
|
+
warningCount: allDiagnostics.filter((d) => d.severity === "warning").length,
|
|
6693
|
+
fixableCount: allDiagnostics.filter((d) => d.fixable).length,
|
|
6694
|
+
engineIssues,
|
|
6695
|
+
engineTimings
|
|
6696
|
+
};
|
|
6378
6697
|
if (options.json) {
|
|
6379
|
-
const { buildJsonOutput } = await import("./json-
|
|
6698
|
+
const { buildJsonOutput } = await import("./json-DZfGz2xa.js");
|
|
6380
6699
|
const jsonOut = buildJsonOutput(results, scoreResult, projectInfo.sourceFileCount, elapsedMs);
|
|
6381
6700
|
console.log(JSON.stringify(jsonOut, null, 2));
|
|
6382
|
-
return
|
|
6701
|
+
return completion;
|
|
6383
6702
|
}
|
|
6384
6703
|
const projectName = projectInfo.projectName ?? "project";
|
|
6385
6704
|
const language = projectInfo.languages[0] ?? "unknown";
|
|
@@ -6396,7 +6715,7 @@ const scanCommand = async (directory, config, options) => {
|
|
|
6396
6715
|
includeHeader: showHeader,
|
|
6397
6716
|
printBrand: options.printBrand
|
|
6398
6717
|
}));
|
|
6399
|
-
return
|
|
6718
|
+
return completion;
|
|
6400
6719
|
};
|
|
6401
6720
|
|
|
6402
6721
|
//#endregion
|
|
@@ -7741,15 +8060,23 @@ const fixCommand = async (directory, config, options = {
|
|
|
7741
8060
|
verbose: false,
|
|
7742
8061
|
showHeader: true
|
|
7743
8062
|
}) => {
|
|
7744
|
-
const startTime = performance.now();
|
|
7745
8063
|
const resolvedDir = path.resolve(directory);
|
|
7746
8064
|
if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {
|
|
7747
8065
|
const msg = !fs.existsSync(resolvedDir) ? `Path does not exist: ${resolvedDir}` : `Not a directory: ${resolvedDir}`;
|
|
7748
8066
|
log.error(msg);
|
|
7749
8067
|
return;
|
|
7750
8068
|
}
|
|
7751
|
-
const showHeader = options.showHeader !== false;
|
|
7752
8069
|
const projectInfo = await discoverProject(resolvedDir);
|
|
8070
|
+
await withCommandLifecycle({
|
|
8071
|
+
command: "fix",
|
|
8072
|
+
config: config.telemetry,
|
|
8073
|
+
languages: projectInfo.languages,
|
|
8074
|
+
fileCount: projectInfo.sourceFileCount
|
|
8075
|
+
}, () => runFixBody(resolvedDir, config, options, projectInfo));
|
|
8076
|
+
};
|
|
8077
|
+
const runFixBody = async (resolvedDir, config, options, projectInfo) => {
|
|
8078
|
+
const startTime = performance.now();
|
|
8079
|
+
const showHeader = options.showHeader !== false;
|
|
7753
8080
|
const projectName = projectInfo.projectName ?? "project";
|
|
7754
8081
|
if (showHeader) process.stdout.write(renderHeader({
|
|
7755
8082
|
version: APP_VERSION,
|
|
@@ -7786,12 +8113,6 @@ const fixCommand = async (directory, config, options = {
|
|
|
7786
8113
|
await runFormattingStep(pipelineDeps);
|
|
7787
8114
|
await runForceSteps(pipelineDeps);
|
|
7788
8115
|
const totalResolved = steps.reduce((sum, s) => sum + s.resolvedIssues, 0);
|
|
7789
|
-
if (!isTelemetryDisabled(config.telemetry?.enabled)) trackEvent({
|
|
7790
|
-
command: "fix",
|
|
7791
|
-
languages: projectInfo.languages,
|
|
7792
|
-
fixSteps: steps.length,
|
|
7793
|
-
fixResolved: totalResolved
|
|
7794
|
-
});
|
|
7795
8116
|
const configDir = findConfigDir(resolvedDir);
|
|
7796
8117
|
const rulesPath = configDir ? path.join(configDir, RULES_FILE) : void 0;
|
|
7797
8118
|
const engineConfig = {
|
|
@@ -7814,7 +8135,9 @@ const fixCommand = async (directory, config, options = {
|
|
|
7814
8135
|
});
|
|
7815
8136
|
const allDiagnostics = scanResults.flatMap((r) => r.diagnostics);
|
|
7816
8137
|
const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds, projectInfo.sourceFileCount, config.scoring.smoothing);
|
|
7817
|
-
const
|
|
8138
|
+
const errors = allDiagnostics.filter((d) => d.severity === "error").length;
|
|
8139
|
+
const warnings = allDiagnostics.filter((d) => d.severity === "warning").length;
|
|
8140
|
+
const remaining = errors + warnings;
|
|
7818
8141
|
if (steps.length === 0) rail.complete({
|
|
7819
8142
|
status: "skipped",
|
|
7820
8143
|
label: "No applicable auto-fixers found"
|
|
@@ -7843,12 +8166,31 @@ const fixCommand = async (directory, config, options = {
|
|
|
7843
8166
|
}
|
|
7844
8167
|
if (options.agent) {
|
|
7845
8168
|
launchAgent(options.agent, resolvedDir, allDiagnostics, scoreResult.score);
|
|
7846
|
-
return
|
|
8169
|
+
return {
|
|
8170
|
+
exitCode: 0,
|
|
8171
|
+
score: scoreResult.score,
|
|
8172
|
+
fixSteps: steps.length,
|
|
8173
|
+
fixResolved: totalResolved
|
|
8174
|
+
};
|
|
7847
8175
|
}
|
|
7848
8176
|
if (options.prompt) {
|
|
7849
8177
|
printPrompt(resolvedDir, allDiagnostics, scoreResult.score);
|
|
7850
|
-
return
|
|
8178
|
+
return {
|
|
8179
|
+
exitCode: 0,
|
|
8180
|
+
score: scoreResult.score,
|
|
8181
|
+
fixSteps: steps.length,
|
|
8182
|
+
fixResolved: totalResolved
|
|
8183
|
+
};
|
|
7851
8184
|
}
|
|
8185
|
+
return {
|
|
8186
|
+
exitCode: 0,
|
|
8187
|
+
score: scoreResult.score,
|
|
8188
|
+
findingCount: allDiagnostics.length,
|
|
8189
|
+
errorCount: errors,
|
|
8190
|
+
warningCount: warnings,
|
|
8191
|
+
fixSteps: steps.length,
|
|
8192
|
+
fixResolved: totalResolved
|
|
8193
|
+
};
|
|
7852
8194
|
};
|
|
7853
8195
|
|
|
7854
8196
|
//#endregion
|