stopslop 0.2.0 → 1.1.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/COMPATIBILITY.md +31 -0
- package/README.md +100 -9
- package/context7.json +22 -0
- package/dist/cli.js +30 -3
- package/dist/index.d.ts +32 -1
- package/dist/index.js +1 -1
- package/dist/src.js +0 -0
- package/docs/ci-and-automation.md +100 -0
- package/docs/configuration.md +257 -0
- package/docs/node-api.md +115 -0
- package/docs/score.md +134 -0
- package/docs/thresholds.md +105 -0
- package/llms.txt +27 -0
- package/package.json +48 -8
- package/schema.json +63 -0
package/COMPATIBILITY.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Compatibility
|
|
2
|
+
|
|
3
|
+
Last updated: 1.1.0
|
|
4
|
+
|
|
5
|
+
StopSlop follows Semantic Versioning. Stable surfaces change incompatibly only
|
|
6
|
+
in a major release. Experimental surfaces may change in a minor release; such
|
|
7
|
+
changes are called out in the changelog.
|
|
8
|
+
|
|
9
|
+
| Surface | Tier | Compatibility policy |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| CLI flags and exit codes | Stable | New flags may be added; existing flags and exit code meanings change only in a major release. |
|
|
12
|
+
| Versioned JSON report | Stable | Fields may be added within a `schemaVersion`; removing or changing one increments it and requires a major release. |
|
|
13
|
+
| SARIF 2.1.0 report | Stable | New rules and optional properties may be added; existing required fields remain compatible. |
|
|
14
|
+
| `stopslop.json` schema | Stable | New settings may be added; configuration valid in a 1.x release stays valid in every later 1.x release. |
|
|
15
|
+
| Programmatic Node.js API | Experimental | Exported functions and TypeScript types may change in a minor release. |
|
|
16
|
+
|
|
17
|
+
Findings and scores are not a compatibility surface. Detector fixes, threshold
|
|
18
|
+
calibration, and Knip or Clone Alert updates can change what a release reports
|
|
19
|
+
for the same code; such changes are called out in the changelog. Pin the
|
|
20
|
+
StopSlop version in CI when a gate must not move without a commit.
|
|
21
|
+
|
|
22
|
+
## Runtime support
|
|
23
|
+
|
|
24
|
+
- Node.js 20.19+, 22.12+, and 24.
|
|
25
|
+
- ESM only.
|
|
26
|
+
- Git-base gating requires the `git` executable and a non-shallow checkout that
|
|
27
|
+
contains the requested base revision.
|
|
28
|
+
|
|
29
|
+
## Deprecations
|
|
30
|
+
|
|
31
|
+
None.
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# StopSlop
|
|
2
2
|
|
|
3
|
-
[](https://github.com/BaryshevRS/stopslop) [](https://github.com/BaryshevRS/clone-alert) [](https://github.com/BaryshevRS/stopslop/actions/workflows/ci.yml) [](https://www.npmjs.com/package/stopslop)
|
|
4
|
+
<!-- clone-alert badge: pnpm exec clone-alert --minimum-tokens 100 --files src --format shields --no-fail-on-violation -->
|
|
4
5
|
|
|
5
6
|
**Stop AI-generated code from becoming instant legacy.**
|
|
6
7
|
|
|
@@ -8,9 +9,10 @@ Coding agents are good at making code compile. They are also good at making too
|
|
|
8
9
|
much of it: tangled functions, god files, copied blocks, dead exports, and entire
|
|
9
10
|
features that pass their own tests but are never connected to the application.
|
|
10
11
|
|
|
11
|
-
StopSlop
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
StopSlop is a static analyzer for JavaScript and TypeScript codebases under
|
|
13
|
+
heavy AI-agent change. It catches that structural overproduction before it
|
|
14
|
+
becomes permanent. It complements ESLint, Biome, Oxlint, SonarQube, and
|
|
15
|
+
SonarCloud rather than repeating their style and type rules.
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
npx stopslop .
|
|
@@ -19,9 +21,6 @@ npx stopslop .
|
|
|
19
21
|
It runs locally against JavaScript and TypeScript. No account. No source-code
|
|
20
22
|
upload.
|
|
21
23
|
|
|
22
|
-
> **0.1 preview:** Requires Node.js 20.19+ or 22.12+. Public surfaces and the
|
|
23
|
-
> pre-1.0 change policy are documented in [COMPATIBILITY.md](COMPATIBILITY.md).
|
|
24
|
-
|
|
25
24
|
## What it catches
|
|
26
25
|
|
|
27
26
|
- **Tangled functions** using cognitive complexity from the SonarSource
|
|
@@ -56,6 +55,14 @@ Or pin it in the project so local runs and CI use the same version:
|
|
|
56
55
|
```bash
|
|
57
56
|
npm install --save-dev stopslop
|
|
58
57
|
npx stopslop .
|
|
58
|
+
|
|
59
|
+
# pnpm
|
|
60
|
+
pnpm add -D stopslop
|
|
61
|
+
pnpm exec stopslop .
|
|
62
|
+
|
|
63
|
+
# Yarn
|
|
64
|
+
yarn add --dev stopslop
|
|
65
|
+
yarn stopslop .
|
|
59
66
|
```
|
|
60
67
|
|
|
61
68
|
The default report gives you the full repository score, the signal densities,
|
|
@@ -130,9 +137,12 @@ npx stopslop . \
|
|
|
130
137
|
Commit or publish `stopslop-badge.json`, then add this Markdown:
|
|
131
138
|
|
|
132
139
|
```md
|
|
133
|
-
[](https://github.com/
|
|
140
|
+
[](https://github.com/BaryshevRS/stopslop)
|
|
134
141
|
```
|
|
135
142
|
|
|
143
|
+
Replace `OWNER/REPO` in the image URL with your repository. Keep the outer link
|
|
144
|
+
unchanged: clicking the badge takes readers to StopSlop.
|
|
145
|
+
|
|
136
146
|
Without `--baseline` or `--base`, `clear` requires zero findings across the
|
|
137
147
|
entire scan. With a baseline, it requires zero findings outside the committed
|
|
138
148
|
baseline. The full score is still present in the terminal and JSON reports.
|
|
@@ -167,6 +177,9 @@ For GitHub Code Scanning, emit SARIF before propagating the gate failure:
|
|
|
167
177
|
npx stopslop . --base origin/main --format sarif > stopslop.sarif
|
|
168
178
|
```
|
|
169
179
|
|
|
180
|
+
See [CI and automation](docs/ci-and-automation.md) for a complete workflow that
|
|
181
|
+
uploads SARIF and still preserves StopSlop's exit code.
|
|
182
|
+
|
|
170
183
|
## Send the findings back to the agent
|
|
171
184
|
|
|
172
185
|
The JSON report is stable and versioned. Feed it into the next coding-agent turn
|
|
@@ -239,6 +252,50 @@ See [docs/configuration.md](docs/configuration.md) for every field, default, and
|
|
|
239
252
|
Knip workspace example. See [stopslop.example.json](stopslop.example.json) for a
|
|
240
253
|
complete configuration.
|
|
241
254
|
|
|
255
|
+
### Dead-code configuration
|
|
256
|
+
|
|
257
|
+
Knip settings go under `knip` in `stopslop.json`. A project's own `knip.json`,
|
|
258
|
+
`.knip.json`, `knip.config.*` and `package.json#knip` are never read, so an
|
|
259
|
+
analysis does not change with whatever happens to sit in the directory.
|
|
260
|
+
Everything in [Knip's configuration reference](https://knip.dev/reference/configuration)
|
|
261
|
+
works there unchanged.
|
|
262
|
+
|
|
263
|
+
You do not have to work out what belongs there. Run the analysis and Knip
|
|
264
|
+
reports what its configuration is missing — which workspace it never reached,
|
|
265
|
+
which declared entry point resolved to nothing — under **config hints**, with
|
|
266
|
+
the file count each one accounts for:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
config hints (from Knip)
|
|
270
|
+
packages/core · 12 files
|
|
271
|
+
Add entry and/or refine project files in workspaces["packages/core"] (12 unused files)
|
|
272
|
+
→ Knip settings live under `knip` in stopslop.json (knip.json is not read)
|
|
273
|
+
reference: https://knip.dev/reference/configuration
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Address them, run again, repeat until they are gone. Until then dead code is
|
|
277
|
+
reported but left out of the score, because a run without entry points reports
|
|
278
|
+
live files as unreachable. The same list is in `configHints` of `--format json`.
|
|
279
|
+
|
|
280
|
+
## Node.js API
|
|
281
|
+
|
|
282
|
+
StopSlop ships ESM JavaScript and TypeScript declarations for programmatic use:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
import { analyze, loadConfig } from 'stopslop';
|
|
286
|
+
|
|
287
|
+
const root = process.cwd();
|
|
288
|
+
const result = await analyze(root, loadConfig(root));
|
|
289
|
+
|
|
290
|
+
console.log(result.slop.score, result.findings);
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
The API also exports the resolved defaults, scoring helpers, baseline helpers,
|
|
294
|
+
and report types. See the [Node.js API guide](docs/node-api.md) for Git-base
|
|
295
|
+
analysis, typed configuration, result semantics, and custom analyzers. The API
|
|
296
|
+
is experimental and may change in a minor release; see
|
|
297
|
+
[COMPATIBILITY.md](COMPATIBILITY.md).
|
|
298
|
+
|
|
242
299
|
## Design and limitations
|
|
243
300
|
|
|
244
301
|
- StopSlop supports `.js`, `.jsx`, `.mjs`, `.cjs`, `.ts`, and `.tsx` source.
|
|
@@ -246,19 +303,53 @@ complete configuration.
|
|
|
246
303
|
directories are excluded by default.
|
|
247
304
|
- A high score does not prove poor engineering, and a low score does not prove
|
|
248
305
|
correctness. StopSlop measures structural overproduction, not total quality.
|
|
249
|
-
- Dead-code accuracy depends on Knip knowing the project's entry points
|
|
306
|
+
- Dead-code accuracy depends on Knip knowing the project's entry points; the
|
|
307
|
+
run says so through config hints when it does not.
|
|
250
308
|
- A baseline accepts finding identities. If an accepted function becomes more
|
|
251
309
|
complex without changing identity, the score rises but the gate stays clear.
|
|
252
310
|
|
|
253
311
|
Architecture, research references, and the boundary between published methods
|
|
254
312
|
and StopSlop heuristics are documented in [ARCH.md](ARCH.md).
|
|
255
313
|
|
|
314
|
+
## FAQ
|
|
315
|
+
|
|
316
|
+
### Is StopSlop an AI-generated code detector?
|
|
317
|
+
|
|
318
|
+
No. It does not guess who wrote a line of code. It finds structural waste that
|
|
319
|
+
coding agents often produce—duplicate blocks, over-complex functions, god
|
|
320
|
+
classes and modules, dead code, and orphan features—and reports the same issue
|
|
321
|
+
when a human wrote it.
|
|
322
|
+
|
|
323
|
+
### How is StopSlop different from ESLint, SonarQube, SonarCloud, or Knip?
|
|
324
|
+
|
|
325
|
+
ESLint and similar linters focus on local rules. SonarQube and SonarCloud are
|
|
326
|
+
broad quality platforms. Knip specializes in unused code and dependencies.
|
|
327
|
+
StopSlop is a local, zero-account AI code quality gate focused on structural
|
|
328
|
+
overproduction. It combines several signals into one report and keeps accepted
|
|
329
|
+
legacy visible through its score while blocking only new findings through a
|
|
330
|
+
baseline or Git comparison. Knip and
|
|
331
|
+
[Clone Alert](https://www.npmjs.com/package/clone-alert) power two of those
|
|
332
|
+
signals.
|
|
333
|
+
|
|
334
|
+
### Can I add StopSlop to a legacy repository?
|
|
335
|
+
|
|
336
|
+
Yes. Generate `.stopslop-baseline.json`, review and commit it, then use that same
|
|
337
|
+
file in CI. Existing findings remain in the score and report as accepted debt;
|
|
338
|
+
only unaccepted findings fail the gate.
|
|
339
|
+
|
|
340
|
+
### Does StopSlop support monorepos and CI code scanning?
|
|
341
|
+
|
|
342
|
+
Yes. Configure Knip workspaces under `stopslop.json#knip.workspaces` for accurate
|
|
343
|
+
dead-code analysis in a monorepo. Use SARIF for GitHub Code Scanning, JSON for
|
|
344
|
+
automation and coding agents, or the Shields format for a README status badge.
|
|
345
|
+
|
|
256
346
|
## Development
|
|
257
347
|
|
|
258
348
|
```bash
|
|
259
349
|
pnpm install
|
|
260
350
|
pnpm test
|
|
261
351
|
pnpm typecheck
|
|
352
|
+
pnpm check:clones
|
|
262
353
|
pnpm build
|
|
263
354
|
pnpm test:package
|
|
264
355
|
pnpm release:check
|
package/context7.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://context7.com/schema/context7.json",
|
|
3
|
+
"projectTitle": "StopSlop",
|
|
4
|
+
"description": "Static analysis and CI gate for AI code slop in JavaScript and TypeScript: cognitive complexity, god units, duplicate code, dead code, orphan features, SARIF and baselines.",
|
|
5
|
+
"folders": ["docs"],
|
|
6
|
+
"excludeFolders": [],
|
|
7
|
+
"excludeFiles": ["CHANGELOG.md", "RELEASING.md"],
|
|
8
|
+
"rules": [
|
|
9
|
+
"StopSlop detects structural code patterns; it does not determine whether code was written by a human or AI.",
|
|
10
|
+
"Run StopSlop without installing it with `npx stopslop .`. It requires Node.js ^20.19.0 or >=22.12.0 and analyzes JavaScript, JSX, TypeScript and TSX.",
|
|
11
|
+
"Exit code 0 means no unaccepted findings, 1 means findings were detected, and 2 means analysis or configuration failed.",
|
|
12
|
+
"Adopt an existing repository with `--baseline .stopslop-baseline.json --update-baseline`, commit that file, then use the same `--baseline` option in CI to reject only new findings.",
|
|
13
|
+
"A baseline changes the gate and reported findings but never lowers the full-repository slop score.",
|
|
14
|
+
"Use `--base <git-ref>` to compare against a Git revision without maintaining a baseline file. CI must fetch enough Git history to resolve that ref.",
|
|
15
|
+
"Report formats are text, json, sarif and shields. Use JSON for coding agents, SARIF for code scanning and shields for the binary `AI slop | clear` badge.",
|
|
16
|
+
"StopSlop works without configuration. Put optional overrides in `stopslop.json` and use `$schema: https://unpkg.com/stopslop/schema.json` for editor validation.",
|
|
17
|
+
"Use `--fast` only when intentionally skipping duplicate-code and dead-code analysis; it runs the AST checks for cognitive complexity and god units.",
|
|
18
|
+
"The Node API is ESM and typed: call `resolveConfig()` before `analyze()`, or call `loadConfig()` to read stopslop.json. The slop score always describes the complete analyzed repository.",
|
|
19
|
+
"Clone detection is powered by Clone Alert and dead-code analysis by Knip. Configure Knip only under the `knip` property in stopslop.json.",
|
|
20
|
+
"Knip settings go under `knip` in stopslop.json; a project's own knip.json or package.json#knip is never read. Do not write one up front — run the analysis and follow the `config hints` it prints, which come from Knip and name what is missing."
|
|
21
|
+
]
|
|
22
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { posix } from "node:path";
|
|
2
|
+
import { c as loadConfig, d as fingerprint, f as readBaseline, n as analyzeGitBase, p as writeBaseline, s as configFilePath, t as analyze, u as applyBaseline } from "./src.js";
|
|
3
|
+
import { posix, relative, sep } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
//#region src/report/terminal.ts
|
|
@@ -69,8 +69,29 @@ const LEVEL_COLOR = {
|
|
|
69
69
|
high: pc.red,
|
|
70
70
|
"legacy-grade": pc.red
|
|
71
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* What Knip says is missing from the configuration. This block is the whole
|
|
74
|
+
* setup story: a dead-code run is only as good as its entry points, and Knip
|
|
75
|
+
* is the one that knows which of them came up empty. The last line names the
|
|
76
|
+
* file to edit — the one thing Knip cannot know, and the thing an agent
|
|
77
|
+
* otherwise guesses wrong by writing knip.json, which StopSlop never reads.
|
|
78
|
+
*/
|
|
79
|
+
function renderConfigHints(result) {
|
|
80
|
+
if (result.configHints.length === 0) return [];
|
|
81
|
+
const lines = ["", " " + pc.bold("config hints") + pc.dim(" (from Knip)")];
|
|
82
|
+
for (const hint of result.configHints) {
|
|
83
|
+
const where = hint.workspace && hint.workspace !== hint.identifier ? ` in ${hint.workspace}` : "";
|
|
84
|
+
const size = hint.size === void 0 ? "" : ` · ${hint.size} files`;
|
|
85
|
+
lines.push(` ${pc.yellow(hint.identifier)}${pc.dim(where + size)}`);
|
|
86
|
+
lines.push(" " + pc.dim(hint.message));
|
|
87
|
+
}
|
|
88
|
+
const file = relative(result.root, configFilePath(result.root, result.config)).split(sep).join("/");
|
|
89
|
+
lines.push(" " + pc.dim(`→ Knip settings live under \`knip\` in ${file} (knip.json is not read)`));
|
|
90
|
+
lines.push(" " + pc.dim(" reference: https://knip.dev/reference/configuration"));
|
|
91
|
+
return lines;
|
|
92
|
+
}
|
|
72
93
|
function renderFooter(result) {
|
|
73
|
-
const lines = [""];
|
|
94
|
+
const lines = [...renderConfigHints(result), ""];
|
|
74
95
|
for (const note of result.notes) lines.push(" " + pc.dim(note));
|
|
75
96
|
if (result.config.preliminary) lines.push(" " + pc.yellow("thresholds are preliminary (pre-calibration) — see docs/thresholds.md"));
|
|
76
97
|
if (result.errors.length > 0) lines.push(" " + pc.dim(`${result.errors.length} file(s) skipped on error`));
|
|
@@ -189,6 +210,12 @@ function toJson(result) {
|
|
|
189
210
|
summary: summarize(result),
|
|
190
211
|
findings: result.findings,
|
|
191
212
|
notes: result.notes,
|
|
213
|
+
configHints: result.configHints,
|
|
214
|
+
/** Where Knip settings are read from. Nowhere else is consulted. */
|
|
215
|
+
configFile: {
|
|
216
|
+
path: relative(result.root, configFilePath(result.root, result.config)).split(sep).join("/"),
|
|
217
|
+
property: "knip"
|
|
218
|
+
},
|
|
192
219
|
errors: result.errors
|
|
193
220
|
}, null, 2);
|
|
194
221
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -44,12 +44,35 @@ interface Analyzer {
|
|
|
44
44
|
interface AnalyzeContext {
|
|
45
45
|
config: ResolvedConfig;
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* What Knip reports as missing from its configuration, computed from the run it
|
|
49
|
+
* just did. Knip owns this judgement — it knows which entry pattern matched
|
|
50
|
+
* nothing and which workspace it never reached, and it counts the files that
|
|
51
|
+
* hang off each. StopSlop adds one thing Knip cannot know: where the
|
|
52
|
+
* configuration lives.
|
|
53
|
+
*/
|
|
54
|
+
interface ConfigHint {
|
|
55
|
+
/** Knip's hint type: `workspace-unconfigured`, `package-entry`, `ignore`, … */
|
|
56
|
+
type: string;
|
|
57
|
+
/** What it is about — a workspace key, a path, a dependency name. */
|
|
58
|
+
identifier: string;
|
|
59
|
+
/** Knip's own wording. */
|
|
60
|
+
message: string;
|
|
61
|
+
/** Workspace the hint belongs to — what tells two identical ones apart. */
|
|
62
|
+
workspace?: string;
|
|
63
|
+
/** File the hint is about, relative to the analyzed root. */
|
|
64
|
+
filePath?: string;
|
|
65
|
+
/** Unused files attributable to this hint, where Knip counted them. */
|
|
66
|
+
size?: number;
|
|
67
|
+
}
|
|
47
68
|
interface ProjectContext {
|
|
48
69
|
root: string;
|
|
49
70
|
files: ParsedFile[];
|
|
50
71
|
config: ResolvedConfig;
|
|
51
72
|
/** Non-fatal notes from an engine (e.g. "knip skipped: no package.json"). */
|
|
52
73
|
notes: string[];
|
|
74
|
+
/** Configuration Knip found missing. Empty when it has nothing to say. */
|
|
75
|
+
configHints: ConfigHint[];
|
|
53
76
|
/**
|
|
54
77
|
* What the Stage-2 engines actually measured. An engine that was disabled —
|
|
55
78
|
* or that bailed out at runtime — leaves its entry unset, and the score then
|
|
@@ -147,6 +170,12 @@ interface ResolvedConfig {
|
|
|
147
170
|
ignore: string[];
|
|
148
171
|
/** Whether current thresholds are provisional. False for the calibrated defaults. */
|
|
149
172
|
preliminary: boolean;
|
|
173
|
+
/**
|
|
174
|
+
* The stopslop.json `loadConfig` read — or looked for, when there is none.
|
|
175
|
+
* Unset for an in-memory `resolveConfig()`; the analyzed root's own
|
|
176
|
+
* stopslop.json stands in then.
|
|
177
|
+
*/
|
|
178
|
+
configFile?: string;
|
|
150
179
|
}
|
|
151
180
|
//#endregion
|
|
152
181
|
//#region src/score.d.ts
|
|
@@ -267,6 +296,8 @@ interface AnalyzeResult {
|
|
|
267
296
|
errors: string[];
|
|
268
297
|
/** Non-fatal notes from the Stage-2 engines (skipped checks, and why). */
|
|
269
298
|
notes: string[];
|
|
299
|
+
/** What Knip reports as missing from `stopslop.json#knip`, from this run. */
|
|
300
|
+
configHints: ConfigHint[];
|
|
270
301
|
config: ResolvedConfig;
|
|
271
302
|
elapsedMs: number;
|
|
272
303
|
/**
|
|
@@ -288,4 +319,4 @@ declare function analyze(root: string, config: ResolvedConfig, analyzers?: Analy
|
|
|
288
319
|
/** Gate the current working tree against findings present at a Git revision. */
|
|
289
320
|
declare function analyzeGitBase(root: string, baseRef: string, config: ResolvedConfig, analyzers?: Analyzer[]): Promise<AnalyzeResult>;
|
|
290
321
|
//#endregion
|
|
291
|
-
export { AnalyzeResult, type Analyzer, type BaselineRecord, DEFAULT_CONFIG, type Finding, type ParsedFile, type ResolvedConfig, type SlopLevel, type SlopScore, type StopSlopConfig, analyze, analyzeGitBase, applyBaseline, computeScore, defaultAnalyzers, fingerprint, levelFor, loadConfig, readBaseline, resolveConfig, writeBaseline };
|
|
322
|
+
export { AnalyzeResult, type Analyzer, type BaselineRecord, type ConfigHint, DEFAULT_CONFIG, type Finding, type ParsedFile, type ResolvedConfig, type SlopLevel, type SlopScore, type StopSlopConfig, analyze, analyzeGitBase, applyBaseline, computeScore, defaultAnalyzers, fingerprint, levelFor, loadConfig, readBaseline, resolveConfig, writeBaseline };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as levelFor, c as loadConfig, d as fingerprint, f as readBaseline, i as computeScore, l as resolveConfig, n as analyzeGitBase, o as DEFAULT_CONFIG, p as writeBaseline, r as defaultAnalyzers, t as analyze, u as applyBaseline } from "./src.js";
|
|
2
2
|
export { DEFAULT_CONFIG, analyze, analyzeGitBase, applyBaseline, computeScore, defaultAnalyzers, fingerprint, levelFor, loadConfig, readBaseline, resolveConfig, writeBaseline };
|
package/dist/src.js
CHANGED
|
Binary file
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# CI and automation
|
|
2
|
+
|
|
3
|
+
StopSlop has three stable exit codes: `0` means the gate is clear, `1` means
|
|
4
|
+
findings were detected, and `2` means analysis or configuration failed. Pin the
|
|
5
|
+
package version in `devDependencies` so local runs and CI use the same rules.
|
|
6
|
+
|
|
7
|
+
## Reject new findings with a committed baseline
|
|
8
|
+
|
|
9
|
+
Create the baseline once and review it like source code:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx stopslop . \
|
|
13
|
+
--baseline .stopslop-baseline.json \
|
|
14
|
+
--update-baseline
|
|
15
|
+
git add .stopslop-baseline.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then use the same file in CI:
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
- name: Reject new AI slop
|
|
22
|
+
run: npx stopslop . --baseline .stopslop-baseline.json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The baseline suppresses accepted findings from the gate. It never removes them
|
|
26
|
+
from the full-repository score.
|
|
27
|
+
|
|
28
|
+
## Compare a pull request with its Git base
|
|
29
|
+
|
|
30
|
+
This mode needs the base revision to exist locally:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
- uses: actions/checkout@v7
|
|
34
|
+
with:
|
|
35
|
+
fetch-depth: 0
|
|
36
|
+
|
|
37
|
+
- name: Reject AI slop added by this change
|
|
38
|
+
run: npx stopslop . --base origin/main
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`--base` and `--baseline` are alternative gates. Do not pass them together.
|
|
42
|
+
|
|
43
|
+
## Publish SARIF without hiding the gate failure
|
|
44
|
+
|
|
45
|
+
The scan may exit `1` after writing valid SARIF. Let the upload step run, then
|
|
46
|
+
propagate the original result. The workflow or job needs permission to publish
|
|
47
|
+
code-scanning results:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
permissions:
|
|
51
|
+
contents: read
|
|
52
|
+
security-events: write
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then add the scan, upload, and enforcement steps:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
- name: Scan with StopSlop
|
|
59
|
+
id: stopslop
|
|
60
|
+
continue-on-error: true
|
|
61
|
+
run: npx stopslop . --base origin/main --format sarif > stopslop.sarif
|
|
62
|
+
|
|
63
|
+
- name: Upload StopSlop SARIF
|
|
64
|
+
if: always() && hashFiles('stopslop.sarif') != ''
|
|
65
|
+
uses: github/codeql-action/upload-sarif@v4
|
|
66
|
+
with:
|
|
67
|
+
sarif_file: stopslop.sarif
|
|
68
|
+
|
|
69
|
+
- name: Enforce StopSlop gate
|
|
70
|
+
if: steps.stopslop.outcome == 'failure'
|
|
71
|
+
run: exit 1
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
An exit code of `2` does not emit a report, preventing an incomplete analysis
|
|
75
|
+
from being published as a trustworthy result.
|
|
76
|
+
|
|
77
|
+
## Give structured findings to a coding agent
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx stopslop . --format json > slop-report.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The JSON schema version is included in the document. Findings carry stable
|
|
84
|
+
`kind`, `file`, `symbol`, `line`, `message`, and optional structured `data`
|
|
85
|
+
fields. God-unit data includes responsibility groups; duplicate-code data
|
|
86
|
+
includes clone locations.
|
|
87
|
+
|
|
88
|
+
## Generate a binary Shields badge
|
|
89
|
+
|
|
90
|
+
Use the same baseline as CI:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx stopslop . \
|
|
94
|
+
--baseline .stopslop-baseline.json \
|
|
95
|
+
--format shields > stopslop-badge.json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The badge says `AI slop | clear` when the gate has no unaccepted findings and
|
|
99
|
+
`AI slop | detected` otherwise. Accepted legacy remains visible in the terminal
|
|
100
|
+
and JSON score.
|