clean-code-tools 1.0.1
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 +66 -0
- package/configs/eslint.clean-code.recommended.mjs +211 -0
- package/configs/python.clean-code.pyproject.toml +143 -0
- package/data/clean-code-patterns.jsonl +264 -0
- package/data/vector-record.schema.json +77 -0
- package/docs/README.md +29 -0
- package/docs/eslint-custom-rules.md +74 -0
- package/docs/eslint-recommended-config.md +87 -0
- package/docs/fastmcp-local-server.md +104 -0
- package/docs/publishing.md +125 -0
- package/docs/python-lint-recommended-config.md +57 -0
- package/docs/python-pylint-custom-rules.md +77 -0
- package/docs/semantic-weaviate.md +80 -0
- package/docs/static-trigger-semantic-review.md +97 -0
- package/evals/clean-code-retrieval.jsonl +13 -0
- package/ops/dev/weaviate/README.md +34 -0
- package/ops/dev/weaviate/compose.yaml +34 -0
- package/ops/dev/weaviate/smoke.sh +28 -0
- package/package.json +96 -0
- package/pyproject.toml +303 -0
- package/sample-apps/README.md +40 -0
- package/sample-apps/python-app/pyproject.toml +113 -0
- package/sample-apps/python-app/src/clean_pricing.py +10 -0
- package/sample-apps/python-app/src/smelly_pricing.py +8 -0
- package/sample-apps/ts-backend/eslint.config.mjs +3 -0
- package/sample-apps/ts-backend/package.json +18 -0
- package/sample-apps/ts-backend/src/clean-handler.ts +19 -0
- package/sample-apps/ts-backend/src/smelly-handler.ts +29 -0
- package/sample-apps/ts-backend/tsconfig.json +9 -0
- package/sample-apps/ts-frontend/eslint.config.mjs +3 -0
- package/sample-apps/ts-frontend/package.json +18 -0
- package/sample-apps/ts-frontend/src/CleanWidget.tsx +18 -0
- package/sample-apps/ts-frontend/src/SmellyWidget.tsx +27 -0
- package/sample-apps/ts-frontend/tsconfig.json +10 -0
- package/scripts/_mcp_app.py +21 -0
- package/scripts/check_clean_code_review_candidates.py +302 -0
- package/scripts/check_fastmcp_server.py +106 -0
- package/scripts/check_packages.py +137 -0
- package/scripts/check_python_config.py +130 -0
- package/scripts/check_repo_python_lint.py +46 -0
- package/scripts/check_retrieval_evals.py +132 -0
- package/scripts/check_sample_apps.py +169 -0
- package/scripts/check_semantic_search_tooling.py +102 -0
- package/scripts/clean_code_eslint_triggers.py +272 -0
- package/scripts/clean_code_mcp_server.py +7 -0
- package/scripts/clean_code_python_triggers.py +318 -0
- package/scripts/clean_code_review_candidates.py +291 -0
- package/scripts/clean_code_review_io.py +36 -0
- package/scripts/clean_code_review_models.py +43 -0
- package/scripts/clean_code_semantic.py +27 -0
- package/scripts/set_package_versions.py +82 -0
- package/scripts/weaviate_ingest_clean_code.py +44 -0
- package/scripts/weaviate_search_clean_code.py +51 -0
- package/skills/clean-code-mcp-reviewer/SKILL.md +209 -0
- package/skills/clean-code-mcp-reviewer/evals/evals.json +30 -0
- package/src/js/eslint-plugin-clean-code.mjs +758 -0
- package/src/python/clean_code_tools_pylint/__init__.py +14 -0
- package/src/python/clean_code_tools_pylint/ast_checker.py +122 -0
- package/src/python/clean_code_tools_pylint/comments.py +83 -0
- package/src/python/clean_code_tools_pylint/helpers.py +196 -0
- package/src/python/mcp_server/__init__.py +1 -0
- package/src/python/mcp_server/corpus.py +160 -0
- package/src/python/mcp_server/markdown.py +126 -0
- package/src/python/mcp_server/models.py +73 -0
- package/src/python/mcp_server/ranking.py +125 -0
- package/src/python/mcp_server/ranking_scoring.py +232 -0
- package/src/python/mcp_server/semantic.py +192 -0
- package/src/python/mcp_server/server.py +235 -0
- package/src/python/mcp_server/server_payloads.py +83 -0
- package/src/python/mcp_server/text.py +104 -0
- package/src/python/mcp_server/utils/__init__.py +1 -0
- package/src/python/mcp_server/utils/httpx_loader.py +14 -0
- package/src/python/mcp_server/utils/increment.py +7 -0
- package/src/python/mcp_server/utils/sha256_text.py +8 -0
- package/src/python/mcp_server/utils/unique_strings.py +15 -0
- package/src/python/mcp_server/weaviate.py +182 -0
- package/uv.lock +2012 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "CleanCodePatternVectorRecord",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": [
|
|
7
|
+
"id",
|
|
8
|
+
"title",
|
|
9
|
+
"topic",
|
|
10
|
+
"rule_family",
|
|
11
|
+
"aliases",
|
|
12
|
+
"problem",
|
|
13
|
+
"use_when",
|
|
14
|
+
"avoid_when",
|
|
15
|
+
"good_examples",
|
|
16
|
+
"bad_examples",
|
|
17
|
+
"lint_candidates",
|
|
18
|
+
"lintability",
|
|
19
|
+
"embedding_text",
|
|
20
|
+
"display_text",
|
|
21
|
+
"source"
|
|
22
|
+
],
|
|
23
|
+
"properties": {
|
|
24
|
+
"id": { "type": "string", "pattern": "^CC-[0-9]{3}$" },
|
|
25
|
+
"title": { "type": "string", "minLength": 3 },
|
|
26
|
+
"topic": { "type": "string", "minLength": 3 },
|
|
27
|
+
"rule_family": { "type": "string", "minLength": 3 },
|
|
28
|
+
"aliases": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": { "type": "string", "minLength": 2 },
|
|
31
|
+
"minItems": 3,
|
|
32
|
+
"uniqueItems": true
|
|
33
|
+
},
|
|
34
|
+
"problem": { "type": "string", "minLength": 20 },
|
|
35
|
+
"use_when": { "type": "string", "minLength": 20 },
|
|
36
|
+
"avoid_when": { "type": "string", "minLength": 20 },
|
|
37
|
+
"good_examples": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"additionalProperties": false,
|
|
40
|
+
"required": ["typescript", "python"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"typescript": { "type": "string", "minLength": 5 },
|
|
43
|
+
"python": { "type": "string", "minLength": 5 }
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"bad_examples": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"additionalProperties": false,
|
|
49
|
+
"required": ["typescript", "python"],
|
|
50
|
+
"properties": {
|
|
51
|
+
"typescript": { "type": "string", "minLength": 5 },
|
|
52
|
+
"python": { "type": "string", "minLength": 5 }
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"lint_candidates": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"items": { "type": "string", "minLength": 10 },
|
|
58
|
+
"minItems": 1
|
|
59
|
+
},
|
|
60
|
+
"lintability": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"enum": ["high", "medium", "low", "review_only"]
|
|
63
|
+
},
|
|
64
|
+
"embedding_text": { "type": "string", "minLength": 300 },
|
|
65
|
+
"display_text": { "type": "string", "minLength": 300 },
|
|
66
|
+
"source": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"required": ["kind", "version"],
|
|
70
|
+
"properties": {
|
|
71
|
+
"kind": { "type": "string" },
|
|
72
|
+
"version": { "type": "integer", "minimum": 1 }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Documentation Index
|
|
2
|
+
|
|
3
|
+
Production-facing docs for clean-code lint packages, MCP pattern lookup, and
|
|
4
|
+
release operations.
|
|
5
|
+
|
|
6
|
+
## Package Usage
|
|
7
|
+
|
|
8
|
+
- [ESLint recommended config](./eslint-recommended-config.md): install and use
|
|
9
|
+
the TypeScript ESLint preset from the npm package.
|
|
10
|
+
- [ESLint custom rules](./eslint-custom-rules.md): project-owned TypeScript
|
|
11
|
+
clean-code rules included in the ESLint plugin.
|
|
12
|
+
- [Python recommended config](./python-lint-recommended-config.md): install and
|
|
13
|
+
use the Ruff/Pylint config from the Python package.
|
|
14
|
+
- [Python custom Pylint rules](./python-pylint-custom-rules.md): project-owned
|
|
15
|
+
Python clean-code rules exposed by the Pylint plugin.
|
|
16
|
+
|
|
17
|
+
## Agent And MCP Workflows
|
|
18
|
+
|
|
19
|
+
- [FastMCP local server](./fastmcp-local-server.md): run the local MCP server,
|
|
20
|
+
inspect exposed tools, and query clean-code patterns from an agent.
|
|
21
|
+
- [Semantic Weaviate search](./semantic-weaviate.md): run local Weaviate,
|
|
22
|
+
ingest the pattern corpus, and test semantic retrieval.
|
|
23
|
+
- [Static trigger to semantic review](./static-trigger-semantic-review.md):
|
|
24
|
+
convert deterministic lint output into clean-code MCP review candidates.
|
|
25
|
+
|
|
26
|
+
## Operations
|
|
27
|
+
|
|
28
|
+
- [Publishing](./publishing.md): package registry setup, branch flow, automated
|
|
29
|
+
versioning on `develop`, and publishing on `main`.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# ESLint Custom Clean-Code Rules
|
|
2
|
+
|
|
3
|
+
The local plugin lives at [src/js/eslint-plugin-clean-code.mjs](../src/js/eslint-plugin-clean-code.mjs). These rules cover TypeScript clean-code checks that are not well covered by common ESLint rule sets.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
### `clean-code/todo-format`
|
|
8
|
+
|
|
9
|
+
Requires TODO/FIXME/XXX comments to include an issue-like owner by default:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// TODO(BILL-412): remove fallback after migration.
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Default pattern:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
^(TODO|FIXME|XXX)\([A-Z][A-Z0-9]+-\d+\):\s+\S
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Corpus: `CC-068`
|
|
22
|
+
|
|
23
|
+
### `clean-code/no-commented-out-code`
|
|
24
|
+
|
|
25
|
+
Flags comments that look like disabled JavaScript or TypeScript code.
|
|
26
|
+
|
|
27
|
+
Corpus: `CC-083`
|
|
28
|
+
|
|
29
|
+
### `clean-code/no-boolean-flag-arguments`
|
|
30
|
+
|
|
31
|
+
Flags boolean literals passed at call sites and boolean selector parameters with mode-like names such as `dryRun`, `force`, `skip`, `include`, or `mode`.
|
|
32
|
+
|
|
33
|
+
Corpus: `CC-043`, `CC-208`, `CC-224`
|
|
34
|
+
|
|
35
|
+
### `clean-code/no-output-argument-mutation`
|
|
36
|
+
|
|
37
|
+
Flags assignments, updates, and common mutator calls that mutate function parameters.
|
|
38
|
+
|
|
39
|
+
Corpus: `CC-050`, `CC-207`
|
|
40
|
+
|
|
41
|
+
### `clean-code/no-redundant-comment`
|
|
42
|
+
|
|
43
|
+
Flags comments whose words heavily overlap the following line of code.
|
|
44
|
+
|
|
45
|
+
Corpus: `CC-071`, `CC-073`
|
|
46
|
+
|
|
47
|
+
### `clean-code/no-noisy-comments`
|
|
48
|
+
|
|
49
|
+
Flags separator comments, author/date byline comments, and comments after closing braces.
|
|
50
|
+
|
|
51
|
+
Corpus: `CC-080`, `CC-081`, `CC-082`
|
|
52
|
+
|
|
53
|
+
### `clean-code/no-business-policy-literals`
|
|
54
|
+
|
|
55
|
+
Flags hard-coded policy-looking literals outside named constants and allowlisted calls. The heuristic catches:
|
|
56
|
+
|
|
57
|
+
- numbers other than `-1`, `0`, and `1`
|
|
58
|
+
- all-caps string values
|
|
59
|
+
- ISO date strings
|
|
60
|
+
- common domain statuses such as `active`, `approved`, `draft`, `failed`, `pending`, and `rejected`
|
|
61
|
+
|
|
62
|
+
Corpus: `CC-002`, `CC-018`, `CC-234`
|
|
63
|
+
|
|
64
|
+
### `clean-code/no-train-wrecks`
|
|
65
|
+
|
|
66
|
+
Flags deep property chains beyond a configurable maximum depth.
|
|
67
|
+
|
|
68
|
+
Corpus: `CC-106`, `CC-107`, `CC-245`
|
|
69
|
+
|
|
70
|
+
## Recommended Config
|
|
71
|
+
|
|
72
|
+
The rules are enabled in [configs/eslint.clean-code.recommended.mjs](../configs/eslint.clean-code.recommended.mjs).
|
|
73
|
+
|
|
74
|
+
They are intentionally warnings because each rule is heuristic and should be tuned per repository.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# ESLint Recommended Clean-Code Config
|
|
2
|
+
|
|
3
|
+
This config combines mature existing ESLint rule sets with a small local clean-code plugin for the TypeScript gaps that are not well covered elsewhere.
|
|
4
|
+
|
|
5
|
+
## Target
|
|
6
|
+
|
|
7
|
+
Use [configs/eslint.clean-code.recommended.mjs](../configs/eslint.clean-code.recommended.mjs) in TypeScript projects that already run ESLint flat config.
|
|
8
|
+
|
|
9
|
+
This preset currently targets Node `^22.13.0 || >=24`, matching the tested ESLint 10/plugin stack.
|
|
10
|
+
|
|
11
|
+
Install the npm package with its peer dependencies:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install --save-dev clean-code-tools eslint @eslint/js typescript-eslint eslint-plugin-sonarjs eslint-plugin-unicorn
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then import the preset from the consuming project's `eslint.config.mjs`:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import cleanCode from "clean-code-tools/configs/eslint.clean-code.recommended.mjs";
|
|
21
|
+
|
|
22
|
+
export default cleanCode;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If a project already has a config, spread this preset before project-specific overrides:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import cleanCode from "clean-code-tools/configs/eslint.clean-code.recommended.mjs";
|
|
29
|
+
|
|
30
|
+
export default [
|
|
31
|
+
...cleanCode,
|
|
32
|
+
{
|
|
33
|
+
rules: {
|
|
34
|
+
"max-lines": ["warn", { max: 300, skipBlankLines: true, skipComments: true }],
|
|
35
|
+
"max-lines-per-function": ["warn", { max: 50, skipBlankLines: true, skipComments: true }],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## TypeScript Project Setup
|
|
42
|
+
|
|
43
|
+
The config uses type-aware `typescript-eslint` rules with `projectService: true` for TypeScript files. Linted `*.ts`, `*.tsx`, `*.mts`, and `*.cts` files must be included by the consuming project's `tsconfig.json`.
|
|
44
|
+
|
|
45
|
+
If a project intentionally lints generated files, config files, or one-off scripts outside `tsconfig.json`, add a project-specific override rather than broadening this preset globally.
|
|
46
|
+
|
|
47
|
+
The package declares these peer dependencies:
|
|
48
|
+
|
|
49
|
+
- `eslint@^10.4.0`
|
|
50
|
+
- `@eslint/js@^10.0.0`
|
|
51
|
+
- `typescript-eslint@^8.0.0`
|
|
52
|
+
- `eslint-plugin-sonarjs@^4.0.0`
|
|
53
|
+
- `eslint-plugin-unicorn@^69.0.0`
|
|
54
|
+
|
|
55
|
+
## Existing Rule Coverage
|
|
56
|
+
|
|
57
|
+
| Corpus area | Existing ESLint coverage |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| Small files, functions, and complexity, `CC-033..CC-059`, `CC-137..CC-142`, `CC-206` | `complexity`, `max-depth`, `max-lines`, `max-lines-per-function`, `max-params`, `sonarjs/cognitive-complexity` |
|
|
60
|
+
| Magic numbers and repeated literals, `CC-018`, `CC-234` | `@typescript-eslint/no-magic-numbers`, `sonarjs/no-duplicate-string` |
|
|
61
|
+
| TODO/FIXME visibility, `CC-068` | `clean-code/todo-format` |
|
|
62
|
+
| Duplicate conditions and branches, `CC-160`, `CC-214` | `sonarjs/no-duplicated-branches`, `sonarjs/no-identical-conditions`, `sonarjs/no-identical-functions` |
|
|
63
|
+
| Complex and negative conditionals, `CC-237`, `CC-238` | `no-nested-ternary`, `no-negated-condition`, `sonarjs/no-inverted-boolean-check`, `unicorn/no-negated-condition` |
|
|
64
|
+
| Null avoidance, `CC-118`, `CC-119` | `unicorn/no-null`, `@typescript-eslint/no-unnecessary-condition`, `@typescript-eslint/prefer-nullish-coalescing` |
|
|
65
|
+
| Dead and redundant code, `CC-209`, `CC-218`, `CC-221` | `@typescript-eslint/no-unused-vars`, `no-empty`, `no-useless-return`, `sonarjs/no-dead-store` |
|
|
66
|
+
| Long import lists, `CC-246` | `no-restricted-syntax` custom selector over `ImportDeclaration[specifiers.length>10]` |
|
|
67
|
+
| Naming consistency, `CC-011`, `CC-025`, `CC-249..CC-255` | `@typescript-eslint/naming-convention` |
|
|
68
|
+
| Async precision and type clarity, `CC-235` | `@typescript-eslint/no-floating-promises`, `@typescript-eslint/no-misused-promises`, `@typescript-eslint/switch-exhaustiveness-check`, `eqeqeq` |
|
|
69
|
+
|
|
70
|
+
## Custom Gap Coverage
|
|
71
|
+
|
|
72
|
+
These corpus candidates are implemented by the local clean-code plugin:
|
|
73
|
+
|
|
74
|
+
- commented-out TypeScript code detection: `clean-code/no-commented-out-code`, `CC-083`
|
|
75
|
+
- TODO format such as `TODO(PROJ-123): ...`: `clean-code/todo-format`, `CC-068`
|
|
76
|
+
- boolean literal arguments at call sites and boolean selector parameters: `clean-code/no-boolean-flag-arguments`, `CC-043`, `CC-208`
|
|
77
|
+
- output argument mutation: `clean-code/no-output-argument-mutation`, `CC-207`
|
|
78
|
+
- comments that restate the following line: `clean-code/no-redundant-comment`, `CC-071`, `CC-073`
|
|
79
|
+
- byline/date comments, separator comments, and closing-brace comments: `clean-code/no-noisy-comments`, `CC-080..CC-082`
|
|
80
|
+
- business-policy string/date/status literals: `clean-code/no-business-policy-literals`, `CC-002`, `CC-234`
|
|
81
|
+
- Law of Demeter / train-wreck chains: `clean-code/no-train-wrecks`, `CC-106`, `CC-107`, `CC-245`
|
|
82
|
+
|
|
83
|
+
See [eslint-custom-rules.md](./eslint-custom-rules.md) for rule details.
|
|
84
|
+
|
|
85
|
+
## Python Config
|
|
86
|
+
|
|
87
|
+
Python projects should use the Ruff + Pylint config in [python-lint-recommended-config.md](./python-lint-recommended-config.md).
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# FastMCP Local Server
|
|
2
|
+
|
|
3
|
+
This server exposes clean-code pattern lookup tools through FastMCP. Coding
|
|
4
|
+
agents should use the pattern-first tools for review/refactor decisions and keep
|
|
5
|
+
the lower-level chunk search for diagnostics.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv sync
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Prepare Weaviate
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun run weaviate:dev:start
|
|
17
|
+
bun run weaviate:dev:smoke
|
|
18
|
+
bun run semantic:ingest -- --reset
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If the default port is busy, use the same alternate port for all commands:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
WEAVIATE_HTTP_PORT=38080 WEAVIATE_GRPC_PORT=35051 bun run weaviate:dev:start
|
|
25
|
+
WEAVIATE_HTTP_PORT=38080 bun run weaviate:dev:smoke
|
|
26
|
+
bun run semantic:ingest -- --url http://127.0.0.1:38080 --reset
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Run MCP
|
|
30
|
+
|
|
31
|
+
Stdio:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bun run mcp:stdio
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
HTTP:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun run mcp:http
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The HTTP server defaults to `http://127.0.0.1:8765`.
|
|
44
|
+
|
|
45
|
+
## Exposed Tools
|
|
46
|
+
|
|
47
|
+
- `clean_code_corpus_summary`: returns corpus chunk counts.
|
|
48
|
+
- `clean_code_weaviate_schema`: returns the `CleanCodeChunks` schema payload.
|
|
49
|
+
- `search_clean_code`: low-level compatibility search over populated Weaviate chunks.
|
|
50
|
+
- `search_clean_code_patterns`: pattern-first search for concrete code smells.
|
|
51
|
+
- `get_clean_code_pattern`: full canonical lookup by `CC-###` ID.
|
|
52
|
+
- `recommend_clean_code_lint_rules`: lint-rule candidate guidance for repeated smells.
|
|
53
|
+
- `list_clean_code_facets`: available filter values and counts.
|
|
54
|
+
|
|
55
|
+
Pattern-first search arguments:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"query": "typescript boolean parameter controls behavior",
|
|
60
|
+
"language": "typescript",
|
|
61
|
+
"lintability": ["high", "medium"],
|
|
62
|
+
"limit": 5,
|
|
63
|
+
"weaviate_url": "http://127.0.0.1:8080"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Full pattern lookup:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"pattern_id": "CC-043"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Lint-rule recommendation:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"query": "TODO comments without issue IDs",
|
|
80
|
+
"language": "typescript",
|
|
81
|
+
"targets": ["eslint", "semgrep"]
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Agent Workflow
|
|
86
|
+
|
|
87
|
+
Use the MCP after inspecting code and forming a concrete smell hypothesis. Send
|
|
88
|
+
short queries such as `python function mutates output argument and returns
|
|
89
|
+
status`, not whole files or full diffs.
|
|
90
|
+
|
|
91
|
+
Recommended review loop:
|
|
92
|
+
|
|
93
|
+
1. Read the changed code and nearby tests.
|
|
94
|
+
2. Identify one maintainability concern.
|
|
95
|
+
3. Query `search_clean_code_patterns` with language and narrow filters.
|
|
96
|
+
4. Fetch detail with `get_clean_code_pattern` only for a relevant result.
|
|
97
|
+
5. Use the pattern as support for a local code finding, not as the finding
|
|
98
|
+
itself.
|
|
99
|
+
6. Suppress weak results or framework-idiomatic near-misses.
|
|
100
|
+
|
|
101
|
+
`search_clean_code_patterns` returns `confidence`, `score`, `match_reasons`,
|
|
102
|
+
and top-level `no_strong_match`. Treat `no_strong_match` as a signal to avoid
|
|
103
|
+
surfacing a clean-code recommendation unless the local code evidence is already
|
|
104
|
+
strong.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Publishing
|
|
2
|
+
|
|
3
|
+
This repo publishes two native package shapes from the same source tree.
|
|
4
|
+
|
|
5
|
+
## Registries
|
|
6
|
+
|
|
7
|
+
- npm registry: `clean-code-tools`
|
|
8
|
+
- PyPI: `clean-code-tools-python`
|
|
9
|
+
|
|
10
|
+
These are production registry names. If either name is already taken, rename the
|
|
11
|
+
package in `package.json` or `pyproject.toml` before the first publish.
|
|
12
|
+
|
|
13
|
+
## TypeScript / ESLint
|
|
14
|
+
|
|
15
|
+
The npm package exposes:
|
|
16
|
+
|
|
17
|
+
- `clean-code-tools`
|
|
18
|
+
- `clean-code-tools/eslint-plugin`
|
|
19
|
+
- `clean-code-tools/configs/eslint.clean-code.recommended.mjs`
|
|
20
|
+
- `clean-code-tools/configs/python.clean-code.pyproject.toml`
|
|
21
|
+
|
|
22
|
+
Before publishing:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bun run check:packages
|
|
26
|
+
npm publish --dry-run --provenance
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The package must not set `private: true`; otherwise npm refuses publication. The
|
|
30
|
+
GitHub Actions workflows use npm trusted publishing with provenance, so configure
|
|
31
|
+
the npm package's trusted publisher to allow this repository and these workflow
|
|
32
|
+
files:
|
|
33
|
+
|
|
34
|
+
- `.github/workflows/publish-main.yml`
|
|
35
|
+
|
|
36
|
+
The workflows use Node 24 so the bundled npm supports trusted publishing.
|
|
37
|
+
|
|
38
|
+
## Python / Pylint
|
|
39
|
+
|
|
40
|
+
The PyPI package is `clean-code-tools-python`. It installs:
|
|
41
|
+
|
|
42
|
+
- the `clean_code_tools_pylint` plugin package
|
|
43
|
+
- Ruff and Pylint runtime dependencies
|
|
44
|
+
- the reusable config as package data at
|
|
45
|
+
`clean_code_tools_pylint/configs/python.clean-code.pyproject.toml`
|
|
46
|
+
|
|
47
|
+
Before publishing:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
bun run check:packages
|
|
51
|
+
uv build
|
|
52
|
+
uv publish --dry-run
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Configure PyPI trusted publishers for this repository and these workflow files:
|
|
56
|
+
|
|
57
|
+
- `.github/workflows/publish-main.yml`
|
|
58
|
+
|
|
59
|
+
The workflows use `uv publish --trusted-publishing always`, so no PyPI token is
|
|
60
|
+
stored in GitHub secrets.
|
|
61
|
+
|
|
62
|
+
The package smoke check builds a wheel, installs it into an isolated virtualenv,
|
|
63
|
+
loads the packaged config through `importlib.resources`, then runs Ruff and
|
|
64
|
+
Pylint against a fixture that must trigger the custom `clean-code-*` messages.
|
|
65
|
+
|
|
66
|
+
## Versioning
|
|
67
|
+
|
|
68
|
+
The source manifests keep a stable release base:
|
|
69
|
+
|
|
70
|
+
- `package.json`
|
|
71
|
+
- `pyproject.toml`
|
|
72
|
+
|
|
73
|
+
Use `scripts/set_package_versions.py` to update them together:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
uv run python scripts/set_package_versions.py --release 1.2.3
|
|
77
|
+
uv run python scripts/set_package_versions.py --bump patch --base 1.2.3
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`bun run check:packages` requires exact version parity between npm and Python.
|
|
81
|
+
Packages are never given a development suffix.
|
|
82
|
+
|
|
83
|
+
Every push or merge to `develop` runs `.github/workflows/version-develop.yml`.
|
|
84
|
+
It reads the latest `vX.Y.Z` tag, bumps the patch version, writes that version to
|
|
85
|
+
`package.json` and `pyproject.toml`, runs the full check, then commits the
|
|
86
|
+
version update back to `develop` and creates a matching `vX.Y.Z` tag on that
|
|
87
|
+
develop commit.
|
|
88
|
+
|
|
89
|
+
Publishing happens only from `main`. Merge `develop` into `main` after the
|
|
90
|
+
versioning workflow has created the version commit and tag. A push to `main`
|
|
91
|
+
runs `.github/workflows/publish-main.yml`, verifies that the manifest version has
|
|
92
|
+
a matching `vX.Y.Z` tag reachable from `main`, runs the full check, then
|
|
93
|
+
publishes npm `latest` plus the PyPI final release.
|
|
94
|
+
|
|
95
|
+
If a change needs a minor or major bump, run the version script manually on
|
|
96
|
+
`develop` before merging, or adjust the workflow bump type for that release.
|
|
97
|
+
|
|
98
|
+
## SemVer Policy
|
|
99
|
+
|
|
100
|
+
Publish the Python package and npm package with matching versions when rule
|
|
101
|
+
semantics change. Patch-only documentation or packaging fixes can ship
|
|
102
|
+
independently if the lint behavior is unchanged.
|
|
103
|
+
|
|
104
|
+
The package check enforces version parity between `package.json` and
|
|
105
|
+
`pyproject.toml`, so bump both manifests in the same release change.
|
|
106
|
+
|
|
107
|
+
Use SemVer for both registries:
|
|
108
|
+
|
|
109
|
+
- patch: documentation, packaging, or false-positive tuning that reduces noise
|
|
110
|
+
- minor: new rules, new recommended warnings, or new MCP candidate mappings
|
|
111
|
+
- major: removed rules, renamed public exports, or stricter defaults that create
|
|
112
|
+
a large new failure surface
|
|
113
|
+
|
|
114
|
+
## References
|
|
115
|
+
|
|
116
|
+
- npm publishing and provenance:
|
|
117
|
+
<https://docs.github.com/en/actions/tutorials/publish-packages/publish-nodejs-packages>
|
|
118
|
+
- npm package versions are immutable after publish:
|
|
119
|
+
<https://docs.npmjs.com/cli/v11/commands/npm-publish/>
|
|
120
|
+
- PyPI trusted publishing:
|
|
121
|
+
<https://docs.pypi.org/trusted-publishers/adding-a-publisher/>
|
|
122
|
+
- GitHub OIDC setup for PyPI:
|
|
123
|
+
<https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi>
|
|
124
|
+
- uv publishing with trusted publishers:
|
|
125
|
+
<https://docs.astral.sh/uv/guides/package/>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Python Recommended Clean-Code Config
|
|
2
|
+
|
|
3
|
+
Use [configs/python.clean-code.pyproject.toml](../configs/python.clean-code.pyproject.toml) as a reusable `pyproject.toml` fragment for Python projects that want clean-code-oriented linting.
|
|
4
|
+
|
|
5
|
+
The config intentionally mixes Ruff and Pylint:
|
|
6
|
+
|
|
7
|
+
- Ruff owns fast local checks: syntax/correctness, imports, bug-prone patterns, simple refactors, commented-out code, TODO shape, unused arguments, return-flow cleanup, magic-value comparisons, and Ruff-specific quality checks.
|
|
8
|
+
- Pylint owns broader design pressure: too many module lines, arguments, locals, branches, returns, statements, nested blocks, public methods, instance attributes, duplicate code, cyclic imports, and the custom Python clean-code plugin.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
python -m pip install clean-code-tools-python
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Copy the config into a project root as `pyproject.toml`, or merge its `[tool.ruff]`, `[tool.ruff.lint]`, and `[tool.pylint.*]` sections into an existing `pyproject.toml`.
|
|
17
|
+
|
|
18
|
+
The Python package installs Ruff, Pylint, and the custom Pylint plugin module
|
|
19
|
+
`clean_code_tools_pylint`. The canonical reusable config is packaged as
|
|
20
|
+
`clean_code_tools_pylint/configs/python.clean-code.pyproject.toml`; this repo
|
|
21
|
+
also keeps a copy at [configs/python.clean-code.pyproject.toml](../configs/python.clean-code.pyproject.toml)
|
|
22
|
+
for local and JavaScript-package consumers.
|
|
23
|
+
|
|
24
|
+
Run:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
ruff check .
|
|
28
|
+
pylint .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Clean-Code Coverage
|
|
32
|
+
|
|
33
|
+
| Corpus area | Tool coverage |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| Commented-out code, `CC-083` | Ruff `ERA` |
|
|
36
|
+
| TODO/FIXME visibility and tracking, `CC-068` | Ruff `TD` |
|
|
37
|
+
| Magic numbers / named constants, `CC-018`, `CC-234` | Ruff `PLR2004` |
|
|
38
|
+
| Dead and unused code, `CC-209`, `CC-218`, `CC-221` | Ruff `F`, `ARG`, `B` |
|
|
39
|
+
| Import readability and ordering, `CC-246` | Ruff `I`, `F401` |
|
|
40
|
+
| Return-flow cleanup, `CC-237`, `CC-238` adjacent | Ruff `RET`, `SIM` |
|
|
41
|
+
| File, function, and class size pressure, `CC-033..CC-059`, `CC-137..CC-142`, `CC-206` | Pylint `too-many-lines` plus design messages |
|
|
42
|
+
| Duplication and coupling signals, `CC-004`, `CC-160`, `CC-214` | Pylint `duplicate-code`, `cyclic-import` |
|
|
43
|
+
| Custom clean-code gaps matching the TypeScript plugin, `CC-043`, `CC-050`, `CC-068`, `CC-071`, `CC-073`, `CC-080`, `CC-083`, `CC-106`, `CC-107`, `CC-207`, `CC-208`, `CC-224`, `CC-245` | Pylint plugin `clean-code-*` messages |
|
|
44
|
+
|
|
45
|
+
## Notes
|
|
46
|
+
|
|
47
|
+
Ruff does not currently support project-local custom rule plugins, so the config only uses built-in Ruff rule families. Pylint is included because its design checker still provides useful clean-code pressure that Ruff either does not cover or would duplicate less flexibly.
|
|
48
|
+
|
|
49
|
+
The thresholds are intentionally strict enough to act as early architecture-smell signals: modules warn above 300 lines, functions warn through statement count, and classes warn when public methods or attributes accumulate. Relax them for framework entrypoints, generated code, migrations, tests, and compatibility layers through project-local overrides.
|
|
50
|
+
|
|
51
|
+
## Remaining Custom Candidates
|
|
52
|
+
|
|
53
|
+
The remaining custom candidates are mostly domain-specific allowlists and
|
|
54
|
+
project-specific suppression policies around the `clean-code-*` messages.
|
|
55
|
+
|
|
56
|
+
See [python-pylint-custom-rules.md](./python-pylint-custom-rules.md) for the
|
|
57
|
+
custom rule details.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Python Custom Clean-Code Rules
|
|
2
|
+
|
|
3
|
+
The local Pylint plugin lives at
|
|
4
|
+
[src/python/clean_code_tools_pylint/](../src/python/clean_code_tools_pylint/). These rules
|
|
5
|
+
mirror the project-owned ESLint clean-code rules where Python syntax gives us a
|
|
6
|
+
reasonably precise static signal.
|
|
7
|
+
|
|
8
|
+
## Rules
|
|
9
|
+
|
|
10
|
+
### `clean-code-todo-format`
|
|
11
|
+
|
|
12
|
+
Requires TODO/FIXME/XXX comments to include an issue-like owner by default:
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
# TODO(BILL-412): remove fallback after migration.
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Corpus: `CC-068`
|
|
19
|
+
|
|
20
|
+
### `clean-code-commented-out-code`
|
|
21
|
+
|
|
22
|
+
Flags comments that look like disabled Python code.
|
|
23
|
+
|
|
24
|
+
Corpus: `CC-083`
|
|
25
|
+
|
|
26
|
+
### `clean-code-boolean-flag-argument`
|
|
27
|
+
|
|
28
|
+
Flags boolean literals passed at call sites and boolean selector parameters with
|
|
29
|
+
mode-like names such as `dry_run`, `force`, `skip`, `include`, or `mode`.
|
|
30
|
+
|
|
31
|
+
Corpus: `CC-043`, `CC-208`, `CC-224`
|
|
32
|
+
|
|
33
|
+
### `clean-code-output-argument-mutation`
|
|
34
|
+
|
|
35
|
+
Flags assignments, updates, and common mutator calls that mutate function
|
|
36
|
+
parameters.
|
|
37
|
+
|
|
38
|
+
Corpus: `CC-050`, `CC-207`
|
|
39
|
+
|
|
40
|
+
### `clean-code-redundant-comment`
|
|
41
|
+
|
|
42
|
+
Flags comments whose words heavily overlap the following line of code.
|
|
43
|
+
|
|
44
|
+
Corpus: `CC-071`, `CC-073`
|
|
45
|
+
|
|
46
|
+
### `clean-code-noisy-comment`
|
|
47
|
+
|
|
48
|
+
Flags separator comments and author/date byline comments.
|
|
49
|
+
|
|
50
|
+
Corpus: `CC-080`, `CC-081`
|
|
51
|
+
|
|
52
|
+
### `clean-code-business-policy-literal`
|
|
53
|
+
|
|
54
|
+
Flags hard-coded policy-looking literals outside named constants and allowlisted
|
|
55
|
+
calls. The heuristic catches:
|
|
56
|
+
|
|
57
|
+
- numbers other than `-1`, `0`, and `1`
|
|
58
|
+
- all-caps string values
|
|
59
|
+
- ISO date strings
|
|
60
|
+
- common domain statuses such as `active`, `approved`, `draft`, `failed`,
|
|
61
|
+
`pending`, and `rejected`
|
|
62
|
+
|
|
63
|
+
Corpus: `CC-002`, `CC-018`, `CC-234`
|
|
64
|
+
|
|
65
|
+
### `clean-code-train-wreck`
|
|
66
|
+
|
|
67
|
+
Flags deep attribute chains beyond the default maximum depth.
|
|
68
|
+
|
|
69
|
+
Corpus: `CC-106`, `CC-107`, `CC-245`
|
|
70
|
+
|
|
71
|
+
## Recommended Config
|
|
72
|
+
|
|
73
|
+
The plugin is loaded and these messages are enabled in
|
|
74
|
+
[configs/python.clean-code.pyproject.toml](../configs/python.clean-code.pyproject.toml).
|
|
75
|
+
|
|
76
|
+
They are intentionally warnings/design signals because each rule is heuristic
|
|
77
|
+
and should be tuned per repository.
|