aislop 0.8.3 → 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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as ENGINE_INFO, r as getEngineLabel, t as APP_VERSION } from "./version-BynHxO1X.js";
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
@@ -5874,60 +5875,348 @@ var LiveRail = class {
5874
5875
  };
5875
5876
 
5876
5877
  //#endregion
5877
- //#region src/utils/telemetry.ts
5878
- const POSTHOG_HOST = "https://eu.i.posthog.com";
5879
- const POSTHOG_KEY = "phc_eY2cOMFva9q24GrWeOuvuVIOhCIdjOALxeAR3ItrqbJ";
5880
- /**
5881
- * Returns true if telemetry should be disabled.
5882
- * Telemetry is opt-out: it runs unless explicitly disabled.
5883
- */
5884
- const isTelemetryDisabled = (configEnabled) => {
5885
- if (process.env.AISLOP_NO_TELEMETRY === "1" || process.env.DO_NOT_TRACK === "1") return true;
5886
- if (process.env.CI === "true" || process.env.CI === "1") return true;
5887
- if (configEnabled === false) return true;
5888
- return false;
5889
- };
5890
- const getScoreBucket = (score) => {
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) => {
5891
5917
  if (score >= 75) return "75-100";
5892
5918
  if (score >= 50) return "50-75";
5893
5919
  if (score >= 25) return "25-50";
5894
5920
  return "0-25";
5895
5921
  };
5896
- const getAnonymousId = () => {
5897
- const raw = `${os.hostname()}-${os.platform()}-${os.arch()}`;
5898
- let hash = 5381;
5899
- for (let i = 0; i < raw.length; i++) hash = hash * 33 ^ raw.charCodeAt(i);
5900
- return `aislop_${(hash >>> 0).toString(36)}`;
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
+ }
5901
5956
  };
5902
- /** Pending telemetry request — kept alive so Node doesn't exit before it completes. */
5903
- let pendingRequest = null;
5904
- const trackEvent = (event) => {
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;
6032
+ };
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 };
5905
6067
  const payload = {
5906
6068
  api_key: POSTHOG_KEY,
5907
- event: `cli_${event.command}`,
5908
- distinct_id: getAnonymousId(),
5909
- properties: {
5910
- version: APP_VERSION,
5911
- node_version: process.version,
5912
- os: os.platform(),
5913
- arch: os.arch(),
5914
- languages: event.languages,
5915
- score_bucket: event.scoreBucket,
5916
- engine_issues: event.engineIssues,
5917
- engine_timings: event.engineTimings,
5918
- elapsed_ms: event.elapsedMs,
5919
- file_count: event.fileCount,
5920
- fix_steps: event.fixSteps,
5921
- fix_resolved: event.fixResolved
5922
- },
6069
+ event: input.event,
6070
+ distinct_id: cachedInstallId,
6071
+ properties: clean,
5923
6072
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
5924
6073
  };
5925
- pendingRequest = fetch(`${POSTHOG_HOST}/capture/`, {
6074
+ const request = fetch(`${POSTHOG_HOST}/capture/`, {
5926
6075
  method: "POST",
5927
6076
  headers: { "Content-Type": "application/json" },
5928
6077
  body: JSON.stringify(payload),
5929
- signal: AbortSignal.timeout(3e3)
5930
- }).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
+ }
5931
6220
  };
5932
6221
 
5933
6222
  //#endregion
@@ -6298,7 +6587,6 @@ const buildScanRender = (input) => {
6298
6587
  }, deps)}`;
6299
6588
  };
6300
6589
  const scanCommand = async (directory, config, options) => {
6301
- const startTime = performance.now();
6302
6590
  const resolvedDir = path.resolve(directory);
6303
6591
  if (!fs.existsSync(resolvedDir)) {
6304
6592
  const msg = `Path does not exist: ${resolvedDir}`;
@@ -6312,9 +6600,18 @@ const scanCommand = async (directory, config, options) => {
6312
6600
  else log.error(msg);
6313
6601
  return { exitCode: 1 };
6314
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();
6315
6613
  const showHeader = options.showHeader !== false;
6316
6614
  const useLiveProgress = !options.json && shouldUseSpinner();
6317
- const projectInfo = await discoverProject(resolvedDir);
6318
6615
  let files;
6319
6616
  if (options.staged) {
6320
6617
  files = filterProjectFiles(resolvedDir, getStagedFiles(resolvedDir), [], config.exclude);
@@ -6381,28 +6678,27 @@ const scanCommand = async (directory, config, options) => {
6381
6678
  const elapsedMs = performance.now() - startTime;
6382
6679
  const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds, projectInfo.sourceFileCount, config.scoring.smoothing);
6383
6680
  const exitCode = allDiagnostics.some((d) => d.severity === "error") || scoreResult.score < config.ci.failBelow ? 1 : 0;
6384
- if (!isTelemetryDisabled(config.telemetry?.enabled)) {
6385
- const engineIssues = {};
6386
- const engineTimings = {};
6387
- for (const r of results) {
6388
- engineIssues[r.engine] = r.diagnostics.length;
6389
- engineTimings[r.engine] = Math.round(r.elapsed);
6390
- }
6391
- trackEvent({
6392
- command: options.command ?? "scan",
6393
- languages: projectInfo.languages,
6394
- scoreBucket: getScoreBucket(scoreResult.score),
6395
- engineIssues,
6396
- engineTimings,
6397
- elapsedMs: Math.round(elapsedMs),
6398
- fileCount: projectInfo.sourceFileCount
6399
- });
6400
- }
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
+ };
6401
6697
  if (options.json) {
6402
- const { buildJsonOutput } = await import("./json-D8h2EZW6.js");
6698
+ const { buildJsonOutput } = await import("./json-DZfGz2xa.js");
6403
6699
  const jsonOut = buildJsonOutput(results, scoreResult, projectInfo.sourceFileCount, elapsedMs);
6404
6700
  console.log(JSON.stringify(jsonOut, null, 2));
6405
- return { exitCode };
6701
+ return completion;
6406
6702
  }
6407
6703
  const projectName = projectInfo.projectName ?? "project";
6408
6704
  const language = projectInfo.languages[0] ?? "unknown";
@@ -6419,7 +6715,7 @@ const scanCommand = async (directory, config, options) => {
6419
6715
  includeHeader: showHeader,
6420
6716
  printBrand: options.printBrand
6421
6717
  }));
6422
- return { exitCode };
6718
+ return completion;
6423
6719
  };
6424
6720
 
6425
6721
  //#endregion
@@ -7764,15 +8060,23 @@ const fixCommand = async (directory, config, options = {
7764
8060
  verbose: false,
7765
8061
  showHeader: true
7766
8062
  }) => {
7767
- const startTime = performance.now();
7768
8063
  const resolvedDir = path.resolve(directory);
7769
8064
  if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {
7770
8065
  const msg = !fs.existsSync(resolvedDir) ? `Path does not exist: ${resolvedDir}` : `Not a directory: ${resolvedDir}`;
7771
8066
  log.error(msg);
7772
8067
  return;
7773
8068
  }
7774
- const showHeader = options.showHeader !== false;
7775
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;
7776
8080
  const projectName = projectInfo.projectName ?? "project";
7777
8081
  if (showHeader) process.stdout.write(renderHeader({
7778
8082
  version: APP_VERSION,
@@ -7809,12 +8113,6 @@ const fixCommand = async (directory, config, options = {
7809
8113
  await runFormattingStep(pipelineDeps);
7810
8114
  await runForceSteps(pipelineDeps);
7811
8115
  const totalResolved = steps.reduce((sum, s) => sum + s.resolvedIssues, 0);
7812
- if (!isTelemetryDisabled(config.telemetry?.enabled)) trackEvent({
7813
- command: "fix",
7814
- languages: projectInfo.languages,
7815
- fixSteps: steps.length,
7816
- fixResolved: totalResolved
7817
- });
7818
8116
  const configDir = findConfigDir(resolvedDir);
7819
8117
  const rulesPath = configDir ? path.join(configDir, RULES_FILE) : void 0;
7820
8118
  const engineConfig = {
@@ -7837,7 +8135,9 @@ const fixCommand = async (directory, config, options = {
7837
8135
  });
7838
8136
  const allDiagnostics = scanResults.flatMap((r) => r.diagnostics);
7839
8137
  const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds, projectInfo.sourceFileCount, config.scoring.smoothing);
7840
- const remaining = allDiagnostics.filter((d) => d.severity === "error").length + allDiagnostics.filter((d) => d.severity === "warning").length;
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;
7841
8141
  if (steps.length === 0) rail.complete({
7842
8142
  status: "skipped",
7843
8143
  label: "No applicable auto-fixers found"
@@ -7866,12 +8166,31 @@ const fixCommand = async (directory, config, options = {
7866
8166
  }
7867
8167
  if (options.agent) {
7868
8168
  launchAgent(options.agent, resolvedDir, allDiagnostics, scoreResult.score);
7869
- return;
8169
+ return {
8170
+ exitCode: 0,
8171
+ score: scoreResult.score,
8172
+ fixSteps: steps.length,
8173
+ fixResolved: totalResolved
8174
+ };
7870
8175
  }
7871
8176
  if (options.prompt) {
7872
8177
  printPrompt(resolvedDir, allDiagnostics, scoreResult.score);
7873
- return;
8178
+ return {
8179
+ exitCode: 0,
8180
+ score: scoreResult.score,
8181
+ fixSteps: steps.length,
8182
+ fixResolved: totalResolved
8183
+ };
7874
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
+ };
7875
8194
  };
7876
8195
 
7877
8196
  //#endregion
@@ -1,4 +1,4 @@
1
- import { n as ENGINE_INFO, t as APP_VERSION } from "./version-BynHxO1X.js";
1
+ import { n as ENGINE_INFO, t as APP_VERSION } from "./version-D_rqBdyj.js";
2
2
 
3
3
  //#region src/output/json.ts
4
4
  const buildJsonOutput = (results, scoreResult, fileCount, elapsedMs) => {
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as ENGINE_INFO, t as APP_VERSION } from "./cli.js";
2
+ import { r as APP_VERSION, t as ENGINE_INFO } from "./cli.js";
3
3
 
4
4
  //#region src/output/json.ts
5
5
  const buildJsonOutput = (results, scoreResult, fileCount, elapsedMs) => {