aislop 0.1.2 → 0.1.3

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 CHANGED
@@ -217,8 +217,6 @@ Custom import and path rules defined in `.aislop/rules.yml`.
217
217
 
218
218
  ---
219
219
 
220
- ## Scoring
221
-
222
220
  Every diagnostic contributes a weighted penalty:
223
221
 
224
222
  | Severity | Penalty |
@@ -227,7 +225,7 @@ Every diagnostic contributes a weighted penalty:
227
225
  | Warning | 1.0 |
228
226
  | Info | 0.25 |
229
227
 
230
- Penalties are multiplied by engine weight (configurable, security defaults to 2x). The final score uses logarithmic scaling so a few issues cause a noticeable drop, but the score does not collapse to zero from minor findings.
228
+ Penalties are multiplied by engine weight (configurable, security defaults to 2x). The final score uses logarithmic scaling with issue-density normalization (relative to source file count), so a few issues still matter but a single finding in an otherwise clean project remains proportional.
231
229
 
232
230
  | Score | Label |
233
231
  |---|---|
@@ -356,4 +354,4 @@ See [SECURITY.md](SECURITY.md) for reporting vulnerabilities.
356
354
 
357
355
  ## License
358
356
 
359
- [MIT](LICENSE) -- see the [LICENSE](LICENSE) file.
357
+ [MIT](LICENSE) -- see the [LICENSE](LICENSE) file.
package/dist/cli.js CHANGED
@@ -46,7 +46,8 @@ const DEFAULT_CONFIG = {
46
46
  thresholds: {
47
47
  good: 75,
48
48
  ok: 50
49
- }
49
+ },
50
+ smoothing: 10
50
51
  },
51
52
  ci: {
52
53
  failBelow: 0,
@@ -146,7 +147,8 @@ const ScoringSchema = z.object({
146
147
  thresholds: ThresholdsSchema.default(() => ({
147
148
  good: 75,
148
149
  ok: 50
149
- }))
150
+ })),
151
+ smoothing: z.number().nonnegative().default(10)
150
152
  });
151
153
  const CiSchema = z.object({
152
154
  failBelow: z.number().default(0),
@@ -178,7 +180,8 @@ const AislopConfigSchema = z.object({
178
180
  thresholds: {
179
181
  good: 75,
180
182
  ok: 50
181
- }
183
+ },
184
+ smoothing: 10
182
185
  })),
183
186
  ci: CiSchema.default(() => ({
184
187
  failBelow: 0,
@@ -1279,10 +1282,7 @@ const FUNCTION_PATTERNS = [
1279
1282
  ]
1280
1283
  }
1281
1284
  ];
1282
- const countParams = (paramStr) => {
1283
- if (!paramStr.trim()) return 0;
1284
- return paramStr.split(",").length;
1285
- };
1285
+ const countParams = (p) => p.trim() ? p.split(",").length : 0;
1286
1286
  const matchFunctionOnLine = (line, ext) => {
1287
1287
  for (let i = 0; i < FUNCTION_PATTERNS.length; i++) {
1288
1288
  const pattern = FUNCTION_PATTERNS[i];
@@ -3118,7 +3118,7 @@ const logger = {
3118
3118
  * Application version — injected at build time by tsdown from package.json.
3119
3119
  * The fallback should always match the "version" field in package.json.
3120
3120
  */
3121
- const APP_VERSION = "0.1.2";
3121
+ const APP_VERSION = "0.1.3";
3122
3122
 
3123
3123
  //#endregion
3124
3124
  //#region src/output/layout.ts
@@ -3344,7 +3344,12 @@ var ScanProgressRenderer = class {
3344
3344
  //#endregion
3345
3345
  //#region src/scoring/index.ts
3346
3346
  const PERFECT_SCORE$1 = 100;
3347
- const calculateScore = (diagnostics, weights, thresholds) => {
3347
+ const getEffectiveFileCount = (diagnostics, sourceFileCount) => {
3348
+ if (typeof sourceFileCount === "number" && sourceFileCount > 0) return sourceFileCount;
3349
+ const filesWithDiagnostics = new Set(diagnostics.map((d) => d.filePath)).size;
3350
+ return Math.max(1, filesWithDiagnostics);
3351
+ };
3352
+ const calculateScore = (diagnostics, weights, thresholds, sourceFileCount, smoothing) => {
3348
3353
  if (diagnostics.length === 0) return {
3349
3354
  score: PERFECT_SCORE$1,
3350
3355
  label: "Healthy"
@@ -3355,7 +3360,11 @@ const calculateScore = (diagnostics, weights, thresholds) => {
3355
3360
  const severityPenalty = d.severity === "error" ? 3 : d.severity === "warning" ? 1 : .25;
3356
3361
  deductions += severityPenalty * engineWeight;
3357
3362
  }
3358
- const score = Math.max(0, Math.round(PERFECT_SCORE$1 - PERFECT_SCORE$1 * Math.log1p(deductions) / Math.log1p(PERFECT_SCORE$1 + deductions)));
3363
+ const effectiveFileCount = getEffectiveFileCount(diagnostics, sourceFileCount);
3364
+ const smoothingConstant = typeof smoothing === "number" ? smoothing : 10;
3365
+ const issueDensity = Math.min(1, diagnostics.length / (effectiveFileCount + smoothingConstant));
3366
+ const scaledDeductions = deductions * Math.sqrt(issueDensity);
3367
+ const score = Math.max(0, Math.round(PERFECT_SCORE$1 - PERFECT_SCORE$1 * Math.log1p(scaledDeductions) / Math.log1p(PERFECT_SCORE$1 + scaledDeductions)));
3359
3368
  return {
3360
3369
  score,
3361
3370
  label: score >= thresholds.good ? "Healthy" : score >= thresholds.ok ? "Needs Work" : "Critical"
@@ -3771,7 +3780,7 @@ const scanCommand = async (directory, config, options) => {
3771
3780
  progressRenderer?.stop();
3772
3781
  const allDiagnostics = results.flatMap((r) => r.diagnostics);
3773
3782
  const elapsedMs = performance.now() - startTime;
3774
- const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds);
3783
+ const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds, projectInfo.sourceFileCount, config.scoring.smoothing);
3775
3784
  const exitCode = allDiagnostics.some((d) => d.severity === "error") || scoreResult.score < config.ci.failBelow ? 1 : 0;
3776
3785
  if (!isTelemetryDisabled(config.telemetry?.enabled)) {
3777
3786
  const engineIssues = {};
@@ -3,7 +3,7 @@
3
3
  * Application version — injected at build time by tsdown from package.json.
4
4
  * The fallback should always match the "version" field in package.json.
5
5
  */
6
- const APP_VERSION = "0.1.2";
6
+ const APP_VERSION = "0.1.3";
7
7
 
8
8
  //#endregion
9
9
  //#region src/output/engine-info.ts
package/dist/index.d.ts CHANGED
@@ -30,6 +30,7 @@ declare const AislopConfigSchema: z.ZodObject<{
30
30
  good: z.ZodDefault<z.ZodNumber>;
31
31
  ok: z.ZodDefault<z.ZodNumber>;
32
32
  }, z.core.$strip>>;
33
+ smoothing: z.ZodDefault<z.ZodNumber>;
33
34
  }, z.core.$strip>>;
34
35
  ci: z.ZodDefault<z.ZodObject<{
35
36
  failBelow: z.ZodDefault<z.ZodNumber>;
@@ -114,6 +115,6 @@ interface ScoreResult {
114
115
  declare const calculateScore: (diagnostics: Diagnostic[], weights: Record<string, number>, thresholds: {
115
116
  good: number;
116
117
  ok: number;
117
- }) => ScoreResult;
118
+ }, sourceFileCount?: number, smoothing?: number) => ScoreResult;
118
119
  //#endregion
119
120
  export { type AislopConfig, type Diagnostic, type EngineName, type EngineResult, type Framework, type Language, type ProjectInfo, type ScoreResult, type Severity, calculateScore, discoverProject, doctorCommand, fixCommand, initCommand, loadConfig, scanCommand };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as getEngineLabel, r as APP_VERSION, t as ENGINE_INFO } from "./engine-info-B4Eq4giL.js";
1
+ import { n as getEngineLabel, r as APP_VERSION, t as ENGINE_INFO } from "./engine-info-Bi8pE12U.js";
2
2
  import { n as runSubprocess, t as isToolInstalled } from "./subprocess-99puEEGl.js";
3
3
  import { createRequire } from "node:module";
4
4
  import fs from "node:fs";
@@ -1273,7 +1273,8 @@ const DEFAULT_CONFIG = {
1273
1273
  thresholds: {
1274
1274
  good: 75,
1275
1275
  ok: 50
1276
- }
1276
+ },
1277
+ smoothing: 10
1277
1278
  },
1278
1279
  ci: {
1279
1280
  failBelow: 0,
@@ -1373,7 +1374,8 @@ const ScoringSchema = z.object({
1373
1374
  thresholds: ThresholdsSchema.default(() => ({
1374
1375
  good: 75,
1375
1376
  ok: 50
1376
- }))
1377
+ })),
1378
+ smoothing: z.number().nonnegative().default(10)
1377
1379
  });
1378
1380
  const CiSchema = z.object({
1379
1381
  failBelow: z.number().default(0),
@@ -1405,7 +1407,8 @@ const AislopConfigSchema = z.object({
1405
1407
  thresholds: {
1406
1408
  good: 75,
1407
1409
  ok: 50
1408
- }
1410
+ },
1411
+ smoothing: 10
1409
1412
  })),
1410
1413
  ci: CiSchema.default(() => ({
1411
1414
  failBelow: 0,
@@ -2392,10 +2395,7 @@ const FUNCTION_PATTERNS = [
2392
2395
  ]
2393
2396
  }
2394
2397
  ];
2395
- const countParams = (paramStr) => {
2396
- if (!paramStr.trim()) return 0;
2397
- return paramStr.split(",").length;
2398
- };
2398
+ const countParams = (p) => p.trim() ? p.split(",").length : 0;
2399
2399
  const matchFunctionOnLine = (line, ext) => {
2400
2400
  for (let i = 0; i < FUNCTION_PATTERNS.length; i++) {
2401
2401
  const pattern = FUNCTION_PATTERNS[i];
@@ -3776,7 +3776,12 @@ var ScanProgressRenderer = class {
3776
3776
  //#endregion
3777
3777
  //#region src/scoring/index.ts
3778
3778
  const PERFECT_SCORE$1 = 100;
3779
- const calculateScore = (diagnostics, weights, thresholds) => {
3779
+ const getEffectiveFileCount = (diagnostics, sourceFileCount) => {
3780
+ if (typeof sourceFileCount === "number" && sourceFileCount > 0) return sourceFileCount;
3781
+ const filesWithDiagnostics = new Set(diagnostics.map((d) => d.filePath)).size;
3782
+ return Math.max(1, filesWithDiagnostics);
3783
+ };
3784
+ const calculateScore = (diagnostics, weights, thresholds, sourceFileCount, smoothing) => {
3780
3785
  if (diagnostics.length === 0) return {
3781
3786
  score: PERFECT_SCORE$1,
3782
3787
  label: "Healthy"
@@ -3787,7 +3792,11 @@ const calculateScore = (diagnostics, weights, thresholds) => {
3787
3792
  const severityPenalty = d.severity === "error" ? 3 : d.severity === "warning" ? 1 : .25;
3788
3793
  deductions += severityPenalty * engineWeight;
3789
3794
  }
3790
- const score = Math.max(0, Math.round(PERFECT_SCORE$1 - PERFECT_SCORE$1 * Math.log1p(deductions) / Math.log1p(PERFECT_SCORE$1 + deductions)));
3795
+ const effectiveFileCount = getEffectiveFileCount(diagnostics, sourceFileCount);
3796
+ const smoothingConstant = typeof smoothing === "number" ? smoothing : 10;
3797
+ const issueDensity = Math.min(1, diagnostics.length / (effectiveFileCount + smoothingConstant));
3798
+ const scaledDeductions = deductions * Math.sqrt(issueDensity);
3799
+ const score = Math.max(0, Math.round(PERFECT_SCORE$1 - PERFECT_SCORE$1 * Math.log1p(scaledDeductions) / Math.log1p(PERFECT_SCORE$1 + scaledDeductions)));
3791
3800
  return {
3792
3801
  score,
3793
3802
  label: score >= thresholds.good ? "Healthy" : score >= thresholds.ok ? "Needs Work" : "Critical"
@@ -3971,7 +3980,7 @@ const scanCommand = async (directory, config, options) => {
3971
3980
  progressRenderer?.stop();
3972
3981
  const allDiagnostics = results.flatMap((r) => r.diagnostics);
3973
3982
  const elapsedMs = performance.now() - startTime;
3974
- const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds);
3983
+ const scoreResult = calculateScore(allDiagnostics, config.scoring.weights, config.scoring.thresholds, projectInfo.sourceFileCount, config.scoring.smoothing);
3975
3984
  const exitCode = allDiagnostics.some((d) => d.severity === "error") || scoreResult.score < config.ci.failBelow ? 1 : 0;
3976
3985
  if (!isTelemetryDisabled(config.telemetry?.enabled)) {
3977
3986
  const engineIssues = {};
@@ -3991,7 +4000,7 @@ const scanCommand = async (directory, config, options) => {
3991
4000
  });
3992
4001
  }
3993
4002
  if (options.json) {
3994
- const { buildJsonOutput } = await import("./json-BMSa_G7o.js");
4003
+ const { buildJsonOutput } = await import("./json-66-1kHeg.js");
3995
4004
  const jsonOut = buildJsonOutput(results, scoreResult, projectInfo.sourceFileCount, elapsedMs);
3996
4005
  console.log(JSON.stringify(jsonOut, null, 2));
3997
4006
  return { exitCode };
@@ -1,4 +1,4 @@
1
- import { r as APP_VERSION, t as ENGINE_INFO } from "./engine-info-B4Eq4giL.js";
1
+ import { r as APP_VERSION, t as ENGINE_INFO } from "./engine-info-Bi8pE12U.js";
2
2
 
3
3
  //#region src/output/json.ts
4
4
  const buildJsonOutput = (results, scoreResult, fileCount, elapsedMs) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aislop",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Stop AI slop from shipping. A unified code quality CLI that catches the lazy patterns AI coding tools leave behind.",
5
5
  "type": "module",
6
6
  "bin": {