slopless 0.2.0 → 0.2.2
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/LICENSE +21 -0
- package/README.md +145 -17
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -1
- package/package.json +4 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 websmasher
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
# slopless
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Install
|
|
3
|
+
Install:
|
|
6
4
|
|
|
7
5
|
```bash
|
|
8
6
|
npm install -D slopless
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Check Markdown files:
|
|
9
|
+
Run:
|
|
14
10
|
|
|
15
11
|
```bash
|
|
16
12
|
npx slopless
|
|
17
13
|
```
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
Run on a specific path:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx slopless "docs/**/*.md"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Save JSON:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx slopless "docs/**/*.md" > slopless.json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Npm Script
|
|
28
|
+
|
|
29
|
+
Add this to `package.json`:
|
|
20
30
|
|
|
21
31
|
```json
|
|
22
32
|
{
|
|
@@ -26,37 +36,155 @@ Add an npm script:
|
|
|
26
36
|
}
|
|
27
37
|
```
|
|
28
38
|
|
|
29
|
-
Run
|
|
39
|
+
Run:
|
|
30
40
|
|
|
31
41
|
```bash
|
|
32
42
|
npm run lint:prose
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
## What Slopless Is
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
Slopless is a deterministic prose checker for Markdown.
|
|
48
|
+
|
|
49
|
+
It reports concrete writing patterns that often make generated or careless prose feel padded, vague, generic, or formulaic.
|
|
50
|
+
|
|
51
|
+
It is built for local scripts, CI checks, review pipelines, and tools that need structured prose findings without calling an LLM.
|
|
52
|
+
|
|
53
|
+
## What Slopless Is Not
|
|
54
|
+
|
|
55
|
+
Slopless does not rewrite text.
|
|
56
|
+
|
|
57
|
+
Slopless does not check facts.
|
|
58
|
+
|
|
59
|
+
Slopless does not judge taste.
|
|
60
|
+
|
|
61
|
+
Slopless does not replace editing.
|
|
62
|
+
|
|
63
|
+
It reports rule findings. A person or another tool decides what to do with them.
|
|
64
|
+
|
|
65
|
+
## Defaults
|
|
66
|
+
|
|
67
|
+
- Checks `**/*.md` when no path is passed.
|
|
68
|
+
- Emits JSON only.
|
|
69
|
+
- Requires Node.js 20 or newer.
|
|
70
|
+
- Requires no `.textlintrc.json`.
|
|
71
|
+
- Requires no separate `textlint` install.
|
|
72
|
+
|
|
73
|
+
## Exit Codes
|
|
74
|
+
|
|
75
|
+
- `0`: no findings
|
|
76
|
+
- `1`: prose findings were reported
|
|
77
|
+
- `2`: command failure before linting
|
|
40
78
|
|
|
41
79
|
## Output
|
|
42
80
|
|
|
43
|
-
Output is always JSON.
|
|
81
|
+
Output is always textlint JSON.
|
|
82
|
+
|
|
83
|
+
Each result contains the checked file path and its messages. Each message includes the rule ID, line, column, message text, and range data when textlint can provide it.
|
|
84
|
+
|
|
85
|
+
Rule IDs use this shape:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
slopless/<rule-name>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
slopless/semantic-thinness
|
|
95
|
+
slopless/llm-openers
|
|
96
|
+
slopless/hedge-stacking
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## CI Use
|
|
100
|
+
|
|
101
|
+
Run Slopless in CI:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npm ci
|
|
105
|
+
npm run lint:prose
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Save findings as an artifact:
|
|
44
109
|
|
|
45
110
|
```bash
|
|
46
111
|
npx slopless "docs/**/*.md" > slopless.json
|
|
47
112
|
```
|
|
48
113
|
|
|
114
|
+
The command exits `1` when findings exist, so CI fails by default on reported prose issues.
|
|
115
|
+
|
|
116
|
+
## Stdin
|
|
117
|
+
|
|
118
|
+
Check text from stdin:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
cat draft.md | npx slopless --stdin --stdin-filename draft.md
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`--stdin-filename` should end in `.md` so textlint parses the input as Markdown.
|
|
125
|
+
|
|
126
|
+
## Supported Options
|
|
127
|
+
|
|
128
|
+
Slopless forwards normal textlint file and execution options.
|
|
129
|
+
|
|
130
|
+
Useful examples:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx slopless "docs/**/*.md" --quiet
|
|
134
|
+
npx slopless --stdin --stdin-filename draft.md
|
|
135
|
+
npx slopless --no-color
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Unsupported:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npx slopless --format stylish
|
|
142
|
+
npx slopless -f json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`--format` and `-f` are rejected because Slopless always emits JSON.
|
|
146
|
+
|
|
49
147
|
## What It Checks
|
|
50
148
|
|
|
149
|
+
Slopless checks for:
|
|
150
|
+
|
|
51
151
|
- stock AI-style phrasing
|
|
52
152
|
- empty or generic prose patterns
|
|
53
153
|
- rhetorical filler
|
|
54
|
-
- weak
|
|
154
|
+
- weak lead-ins and closers
|
|
55
155
|
- hedge stacking
|
|
56
|
-
- prohibited vocabulary
|
|
156
|
+
- prohibited or overused vocabulary
|
|
157
|
+
- cliches and corporate phrasing
|
|
158
|
+
- fake precision signals
|
|
57
159
|
- readability and sentence metrics
|
|
58
160
|
- Markdown style signals
|
|
59
161
|
|
|
60
|
-
##
|
|
162
|
+
## Why It Exists
|
|
163
|
+
|
|
164
|
+
Generated prose often repeats the same rhetorical moves: vague contrast, empty emotional payoff, overconfident summaries, generic transitions, and formulaic conclusions.
|
|
165
|
+
|
|
166
|
+
General grammar tools are not aimed at those patterns. LLM review can catch them, but it is slower, non-deterministic, and harder to use as a stable CI gate.
|
|
167
|
+
|
|
168
|
+
Slopless keeps that layer deterministic. It gives projects a repeatable JSON report of known prose issues.
|
|
169
|
+
|
|
170
|
+
## Advanced Textlint Use
|
|
171
|
+
|
|
172
|
+
The package also exports a textlint preset for users who already run textlint directly.
|
|
173
|
+
|
|
174
|
+
`.textlintrc.json`:
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"rules": {
|
|
179
|
+
"preset-slopless": true
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Direct textlint use:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npx textlint "docs/**/*.md"
|
|
188
|
+
```
|
|
61
189
|
|
|
62
|
-
|
|
190
|
+
Most users should use `npx slopless` instead.
|
package/dist/cli.js
CHANGED
|
@@ -4,11 +4,62 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { cli } from "textlint/lib/src/cli.js";
|
|
5
5
|
const DEFAULT_TARGET = "**/*.md";
|
|
6
6
|
const FORMAT_FLAGS = new Set(["--format", "-f"]);
|
|
7
|
+
const HELP_FLAGS = new Set(["--help", "-h"]);
|
|
8
|
+
const VERSION_FLAGS = new Set(["--version", "-v"]);
|
|
9
|
+
const VERSION = "0.2.2";
|
|
10
|
+
const HELP_TEXT = `Slopless checks Markdown prose for deterministic slop signals and writes JSON.
|
|
11
|
+
|
|
12
|
+
Install:
|
|
13
|
+
npm install -D slopless
|
|
14
|
+
|
|
15
|
+
Run:
|
|
16
|
+
npx slopless
|
|
17
|
+
npx slopless "docs/**/*.md"
|
|
18
|
+
npx slopless draft.md > slopless.json
|
|
19
|
+
|
|
20
|
+
Package script:
|
|
21
|
+
{
|
|
22
|
+
"scripts": {
|
|
23
|
+
"lint:prose": "slopless"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Default behavior:
|
|
28
|
+
- If no file path is passed, Slopless checks **/*.md.
|
|
29
|
+
- Output is always JSON.
|
|
30
|
+
- Exit 0 means no findings.
|
|
31
|
+
- Exit 1 means Slopless found prose issues.
|
|
32
|
+
- Exit 2 means the command failed before linting.
|
|
33
|
+
- No .textlintrc.json is required.
|
|
34
|
+
- No separate textlint install is required.
|
|
35
|
+
|
|
36
|
+
What it is for:
|
|
37
|
+
Slopless is for deterministic prose checks in CI, local scripts, and review
|
|
38
|
+
pipelines. It catches repeated AI-style phrasing, empty claims, rhetorical
|
|
39
|
+
filler, weak lead-ins and closers, hedge stacking, readability problems, and
|
|
40
|
+
Markdown style signals.
|
|
41
|
+
|
|
42
|
+
What it is not for:
|
|
43
|
+
Slopless does not rewrite text, check facts, judge taste, or replace human
|
|
44
|
+
editing. It reports concrete rule findings that another tool or person can
|
|
45
|
+
review.
|
|
46
|
+
|
|
47
|
+
Useful forms:
|
|
48
|
+
npx slopless --stdin --stdin-filename draft.md
|
|
49
|
+
npx slopless "docs/**/*.md" > slopless.json
|
|
50
|
+
npx slopless "docs/**/*.md" --quiet
|
|
51
|
+
|
|
52
|
+
Unsupported:
|
|
53
|
+
--format and -f are rejected. JSON is the only output format.
|
|
54
|
+
`;
|
|
7
55
|
function hasFormatOverride(args) {
|
|
8
56
|
return args.some((arg, index) => FORMAT_FLAGS.has(arg) ||
|
|
9
57
|
arg.startsWith("--format=") ||
|
|
10
58
|
(index > 0 && FORMAT_FLAGS.has(args[index - 1] ?? "")));
|
|
11
59
|
}
|
|
60
|
+
function hasFlag(args, flags) {
|
|
61
|
+
return args.some((arg) => flags.has(arg));
|
|
62
|
+
}
|
|
12
63
|
function hasFileTarget(args) {
|
|
13
64
|
return args.some((arg) => !arg.startsWith("-"));
|
|
14
65
|
}
|
|
@@ -18,6 +69,14 @@ function packageNodeModules() {
|
|
|
18
69
|
}
|
|
19
70
|
async function main() {
|
|
20
71
|
const userArgs = process.argv.slice(2);
|
|
72
|
+
if (hasFlag(userArgs, HELP_FLAGS)) {
|
|
73
|
+
process.stdout.write(HELP_TEXT);
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
if (hasFlag(userArgs, VERSION_FLAGS)) {
|
|
77
|
+
process.stdout.write(`${VERSION}\n`);
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
21
80
|
if (hasFormatOverride(userArgs)) {
|
|
22
81
|
process.stderr.write("slopless always writes JSON output. Remove --format / -f.\n");
|
|
23
82
|
return 2;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAE9C,MAAM,cAAc,GAAG,SAAS,CAAC;AACjC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopless",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Deterministic textlint rules for detecting slop in prose.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/agent-quality-controls/
|
|
9
|
-
"directory": "packages/textlint-rules"
|
|
8
|
+
"url": "git+https://github.com/agent-quality-controls/Slopless.git"
|
|
10
9
|
},
|
|
11
|
-
"homepage": "https://github.com/agent-quality-controls/
|
|
10
|
+
"homepage": "https://github.com/agent-quality-controls/Slopless#readme",
|
|
12
11
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/agent-quality-controls/
|
|
12
|
+
"url": "https://github.com/agent-quality-controls/Slopless/issues"
|
|
14
13
|
},
|
|
15
14
|
"type": "module",
|
|
16
15
|
"main": "./dist/index.js",
|