crapkit 0.4.12__tar.gz → 0.4.14__tar.gz
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.
- {crapkit-0.4.12/src/crapkit.egg-info → crapkit-0.4.14}/PKG-INFO +9 -5
- {crapkit-0.4.12 → crapkit-0.4.14}/README.md +8 -4
- {crapkit-0.4.12 → crapkit-0.4.14}/pyproject.toml +1 -1
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/__init__.py +1 -1
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/mcp_server.py +97 -20
- {crapkit-0.4.12 → crapkit-0.4.14/src/crapkit.egg-info}/PKG-INFO +9 -5
- {crapkit-0.4.12 → crapkit-0.4.14}/LICENSE +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/setup.cfg +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/__main__.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/_pygdefer.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/analyze.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cache.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/churn.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/churn_cache.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/churn_log.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/__init__.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/_shared.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/admin.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/analyses.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/claude_hook.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/parser.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/queue.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/ratchet_cmds.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/reports.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/scoring.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/cli/verifying.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/config.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/coupling.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/coupling_cache.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/coverage_istanbul.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/coverage_py.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/covstream.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/diffparse.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/digest.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/discover.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/doctor.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/dup.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/errors.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/gitio.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/hook.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/invocation.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/junitparse.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/keys.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/lanes.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/lizardcognitive.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/lizardpowershell.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/lizardrust.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/lizardshell.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/merge.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/mutate.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/mutate_pool.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/override.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/packet.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/procs.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/ratchet.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/ratchet_report.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/report.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/sarif.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/sarifio.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/scaffold.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/score.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/snapshot.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/store.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/uncovered.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/universe.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/verify.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/watch.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit/worklist.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit.egg-info/SOURCES.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit.egg-info/dependency_links.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit.egg-info/entry_points.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit.egg-info/requires.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.14}/src/crapkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crapkit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
4
4
|
Summary: Scores every function on complexity times uncovered risk, ranks the worst, and blocks commits that add more.
|
|
5
5
|
Author: Jean-Francois Gagne
|
|
6
6
|
License: MIT
|
|
@@ -39,10 +39,13 @@ Dynamic: license-file
|
|
|
39
39
|
|
|
40
40
|
# crapkit
|
|
41
41
|
|
|
42
|
+
<!-- mcp-name: io.github.jeanfrancoisgagne/crapkit -->
|
|
43
|
+
|
|
42
44
|
[](https://github.com/JeanFrancoisGagne/crapkit/actions/workflows/ci.yml)
|
|
43
45
|
[](https://pypi.org/project/crapkit/)
|
|
44
46
|
[](https://pypi.org/project/crapkit/)
|
|
45
47
|
[](https://github.com/JeanFrancoisGagne/crapkit/blob/main/LICENSE)
|
|
48
|
+
[](https://glama.ai/mcp/servers/JeanFrancoisGagne/crapkit)
|
|
46
49
|
|
|
47
50
|

|
|
48
51
|
|
|
@@ -165,7 +168,7 @@ leaves the box
|
|
|
165
168
|
|
|
166
169
|
```
|
|
167
170
|
$ crapkit --version
|
|
168
|
-
crapkit 0.4.
|
|
171
|
+
crapkit 0.4.14
|
|
169
172
|
```
|
|
170
173
|
|
|
171
174
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -395,7 +398,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
395
398
|
repos:
|
|
396
399
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
397
400
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
398
|
-
rev: v0.4.
|
|
401
|
+
rev: v0.4.14
|
|
399
402
|
hooks:
|
|
400
403
|
- id: crapkit-gate
|
|
401
404
|
```
|
|
@@ -501,7 +504,7 @@ to a workflow, and every input has a default:
|
|
|
501
504
|
- uses: actions/checkout@v4
|
|
502
505
|
with:
|
|
503
506
|
fetch-depth: 0
|
|
504
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
507
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.14
|
|
505
508
|
```
|
|
506
509
|
|
|
507
510
|
The whole job those four lines sit in:
|
|
@@ -521,7 +524,7 @@ jobs:
|
|
|
521
524
|
with:
|
|
522
525
|
python-version: "3.12" # the interpreter the install below lands in
|
|
523
526
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
524
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
527
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.14
|
|
525
528
|
with:
|
|
526
529
|
gate: "false"
|
|
527
530
|
```
|
|
@@ -1189,6 +1192,7 @@ that block is advisory unless `diff_uncovered_max` is set
|
|
|
1189
1192
|
| [docs/lanes.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/lanes.md) | The lane model, vitest and jest and pytest recipes, artifact reuse, flake retest, containers. |
|
|
1190
1193
|
| [docs/ratchet.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/ratchet.md) | Seeding, pruning, the git merge driver, metric stamps, debt policy, overrides. |
|
|
1191
1194
|
| [docs/agent-json.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/agent-json.md) | The machine surface: `schema`, every payload field, real captured examples. |
|
|
1195
|
+
| [docs/comparison.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/comparison.md) | Where crapkit sits next to radon, xenon, wily, coverage.py and SonarQube, and how they run together. |
|
|
1192
1196
|
| [AGENTS.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/AGENTS.md) | The burn-down loop an agent runs, and the rules for changing crapkit itself. |
|
|
1193
1197
|
| [plugin/](https://github.com/JeanFrancoisGagne/crapkit/tree/main/plugin) | The Claude Code plugin: three skills, the read-side MCP server, and the advisory PostToolUse hook. |
|
|
1194
1198
|
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# crapkit
|
|
2
2
|
|
|
3
|
+
<!-- mcp-name: io.github.jeanfrancoisgagne/crapkit -->
|
|
4
|
+
|
|
3
5
|
[](https://github.com/JeanFrancoisGagne/crapkit/actions/workflows/ci.yml)
|
|
4
6
|
[](https://pypi.org/project/crapkit/)
|
|
5
7
|
[](https://pypi.org/project/crapkit/)
|
|
6
8
|
[](https://github.com/JeanFrancoisGagne/crapkit/blob/main/LICENSE)
|
|
9
|
+
[](https://glama.ai/mcp/servers/JeanFrancoisGagne/crapkit)
|
|
7
10
|
|
|
8
11
|

|
|
9
12
|
|
|
@@ -126,7 +129,7 @@ leaves the box
|
|
|
126
129
|
|
|
127
130
|
```
|
|
128
131
|
$ crapkit --version
|
|
129
|
-
crapkit 0.4.
|
|
132
|
+
crapkit 0.4.14
|
|
130
133
|
```
|
|
131
134
|
|
|
132
135
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -356,7 +359,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
356
359
|
repos:
|
|
357
360
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
358
361
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
359
|
-
rev: v0.4.
|
|
362
|
+
rev: v0.4.14
|
|
360
363
|
hooks:
|
|
361
364
|
- id: crapkit-gate
|
|
362
365
|
```
|
|
@@ -462,7 +465,7 @@ to a workflow, and every input has a default:
|
|
|
462
465
|
- uses: actions/checkout@v4
|
|
463
466
|
with:
|
|
464
467
|
fetch-depth: 0
|
|
465
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
468
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.14
|
|
466
469
|
```
|
|
467
470
|
|
|
468
471
|
The whole job those four lines sit in:
|
|
@@ -482,7 +485,7 @@ jobs:
|
|
|
482
485
|
with:
|
|
483
486
|
python-version: "3.12" # the interpreter the install below lands in
|
|
484
487
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
485
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
488
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.14
|
|
486
489
|
with:
|
|
487
490
|
gate: "false"
|
|
488
491
|
```
|
|
@@ -1150,6 +1153,7 @@ that block is advisory unless `diff_uncovered_max` is set
|
|
|
1150
1153
|
| [docs/lanes.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/lanes.md) | The lane model, vitest and jest and pytest recipes, artifact reuse, flake retest, containers. |
|
|
1151
1154
|
| [docs/ratchet.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/ratchet.md) | Seeding, pruning, the git merge driver, metric stamps, debt policy, overrides. |
|
|
1152
1155
|
| [docs/agent-json.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/agent-json.md) | The machine surface: `schema`, every payload field, real captured examples. |
|
|
1156
|
+
| [docs/comparison.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/comparison.md) | Where crapkit sits next to radon, xenon, wily, coverage.py and SonarQube, and how they run together. |
|
|
1153
1157
|
| [AGENTS.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/AGENTS.md) | The burn-down loop an agent runs, and the rules for changing crapkit itself. |
|
|
1154
1158
|
| [plugin/](https://github.com/JeanFrancoisGagne/crapkit/tree/main/plugin) | The Claude Code plugin: three skills, the read-side MCP server, and the advisory PostToolUse hook. |
|
|
1155
1159
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "crapkit"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.14"
|
|
8
8
|
description = "Scores every function on complexity times uncovered risk, ranks the worst, and blocks commits that add more."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""crapkit: deterministic CRAP-score framework."""
|
|
2
|
-
__version__ = "0.4.
|
|
2
|
+
__version__ = "0.4.14"
|
|
@@ -13,9 +13,13 @@ from pathlib import Path
|
|
|
13
13
|
|
|
14
14
|
from .invocation import _self
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
# Newest first. Everything this server does — tools, annotations, structured
|
|
17
|
+
# results over stdio — is inside the 2025-06-18 revision, and nothing it does
|
|
18
|
+
# was removed from the older two, so any of the three can be spoken verbatim.
|
|
19
|
+
SUPPORTED_PROTOCOLS = ("2025-06-18", "2025-03-26", "2024-11-05")
|
|
17
20
|
|
|
18
|
-
_REPO = {"repo": {"type": "string", "description":
|
|
21
|
+
_REPO = {"repo": {"type": "string", "description": (
|
|
22
|
+
"path to the scored repo's root (default: the repo the server was started in)")}}
|
|
19
23
|
|
|
20
24
|
# brief and explain resolve NAME by one rule, so they describe it with one
|
|
21
25
|
# string. The bare identifier is the long name's leading token, which is all
|
|
@@ -28,45 +32,80 @@ _NAME_DESCRIPTION = ("the bare identifier (classify, or route for a Rust "
|
|
|
28
32
|
TOOLS: tuple[dict, ...] = (
|
|
29
33
|
{"name": "next_item", "argv": ["next-item"], "json_flag": False, "positional": (),
|
|
30
34
|
"flags": {"top": "--top", "exclude": "--exclude"},
|
|
31
|
-
"description": "The highest-risk function
|
|
32
|
-
|
|
35
|
+
"description": "The highest-risk function to refactor next, as one work packet: score, "
|
|
36
|
+
"uncovered lines, effort estimate and the commands that verify the fix. "
|
|
37
|
+
"Reach for it when you want one item to act on; worklist is the same "
|
|
38
|
+
"ranking as a survey.",
|
|
39
|
+
"properties": {"top": {"type": "integer",
|
|
40
|
+
"description": "return the next N packets instead of one (>= 1, default 1)"},
|
|
41
|
+
"exclude": {"type": "array", "items": {"type": "string"},
|
|
42
|
+
"description": "skip items whose path or function name contains "
|
|
43
|
+
"this fragment (repeatable)"}}},
|
|
33
44
|
{"name": "worklist", "argv": ["worklist"], "json_flag": True, "positional": (),
|
|
34
45
|
"flags": {"top": "--top"},
|
|
35
|
-
"description": "
|
|
36
|
-
|
|
46
|
+
"description": "The run's whole risk ranking: every function over its ceiling, then the "
|
|
47
|
+
"queue under it ordered by ccn times recency-weighted churn. Use it to "
|
|
48
|
+
"survey the repo; next_item hands out one packet from the top.",
|
|
49
|
+
"properties": {"top": {"type": "integer",
|
|
50
|
+
"description": "cap the active list (default: the config's worklist_top)"}}},
|
|
37
51
|
{"name": "runs", "argv": ["runs"], "json_flag": True, "positional": (), "flags": {},
|
|
38
|
-
"description": "Run history: id, kind, verdict, commit
|
|
52
|
+
"description": "Run history, newest first: id, kind, verdict, commit and lane set. Use it "
|
|
53
|
+
"to date the store or to check which commit the other tools answer from.",
|
|
54
|
+
"properties": {}},
|
|
39
55
|
{"name": "brief", "argv": ["brief"], "json_flag": True, "positional": ("path", "name"),
|
|
40
56
|
"flags": {},
|
|
41
|
-
"description": "One function's whole context: scored row, ratchet mark,
|
|
42
|
-
"duplication twins, churn and change-coupling partners"
|
|
57
|
+
"description": "One function's whole context in one call: scored row, ratchet mark, "
|
|
58
|
+
"uncovered lines, duplication twins, churn and change-coupling partners. "
|
|
59
|
+
"The deepest single read; explain is the slimmer history-only view.",
|
|
43
60
|
"properties": {"path": {"type": "string", "description": "repo-relative source file"},
|
|
44
61
|
"name": {"type": "string", "description": _NAME_DESCRIPTION}}},
|
|
45
62
|
{"name": "explain", "argv": ["explain"], "json_flag": False, "positional": ("path", "name"),
|
|
46
63
|
"flags": {},
|
|
47
|
-
"description": "One function's score trajectory across runs plus its ratchet mark"
|
|
48
|
-
|
|
64
|
+
"description": "One function's score trajectory across runs plus its ratchet mark. Use it "
|
|
65
|
+
"to see whether a function is improving or decaying; brief adds the full "
|
|
66
|
+
"context around the newest score.",
|
|
67
|
+
"properties": {"path": {"type": "string", "description": "repo-relative source file"},
|
|
49
68
|
"name": {"type": "string", "description": _NAME_DESCRIPTION}}},
|
|
50
69
|
{"name": "doctor", "argv": ["doctor"], "json_flag": False, "positional": (), "flags": {},
|
|
51
|
-
"description": "Config
|
|
70
|
+
"description": "Config and repo agreement check: typo keys, empty scopes, missing lane "
|
|
71
|
+
"cwds, unresolvable runners. Run it first when any other tool answers "
|
|
72
|
+
"strangely or an expected file is missing from the ranking.",
|
|
52
73
|
"properties": {}},
|
|
53
74
|
{"name": "coupling", "argv": ["coupling"], "json_flag": True, "positional": (),
|
|
54
75
|
"flags": {"min_support": "--min-support", "min_confidence": "--min-confidence"},
|
|
55
|
-
"description": "File pairs that keep landing in the same commits
|
|
56
|
-
|
|
76
|
+
"description": "File pairs that keep landing in the same commits: dependencies no import "
|
|
77
|
+
"statement reveals. Use it to learn what else an edit usually drags along "
|
|
78
|
+
"before touching a file.",
|
|
79
|
+
"properties": {"min_support": {"type": "integer",
|
|
80
|
+
"description": "minimum shared commits before a pair counts (default 5)"},
|
|
81
|
+
"min_confidence": {"type": "number",
|
|
82
|
+
"description": "minimum P(pair changes together), 0 to 1 (default 0.5)"}}},
|
|
57
83
|
{"name": "duplication", "argv": ["duplication"], "json_flag": True, "positional": (),
|
|
58
84
|
"flags": {"similarity": "--similarity"},
|
|
59
|
-
"description": "Near-duplicate
|
|
60
|
-
|
|
85
|
+
"description": "Near-duplicate function pairs by normalized line shingles, with the "
|
|
86
|
+
"containment percent. Use it before a refactor so twins get folded "
|
|
87
|
+
"together instead of one copy getting fixed alone.",
|
|
88
|
+
"properties": {"similarity": {"type": "number",
|
|
89
|
+
"description": "containment threshold, shared over smaller, "
|
|
90
|
+
"0 to 1 (default 0.8)"}}},
|
|
61
91
|
{"name": "ratchet_report", "argv": ["ratchet", "report"], "json_flag": True, "positional": (),
|
|
62
92
|
"flags": {},
|
|
63
|
-
"description": "
|
|
93
|
+
"description": "The debt burn-down: every open ratchet mark with its age, plus repayment "
|
|
94
|
+
"velocity from git history. Use it to see whether marked debt is being "
|
|
95
|
+
"paid down or piling up.",
|
|
64
96
|
"properties": {}},
|
|
65
97
|
)
|
|
66
98
|
|
|
99
|
+
# Every tool shells to a read-only CLI command against a store on this machine:
|
|
100
|
+
# nothing writes, reruns answer the same, and no call leaves the repo. Declared
|
|
101
|
+
# once, in the field clients read, so the module docstring's promise reaches the
|
|
102
|
+
# model that plans with these tools.
|
|
103
|
+
_ANNOTATIONS = {"readOnlyHint": True, "idempotentHint": True, "openWorldHint": False}
|
|
104
|
+
|
|
67
105
|
|
|
68
106
|
def tool_listing() -> list[dict]:
|
|
69
107
|
return [{"name": t["name"], "description": t["description"],
|
|
108
|
+
"annotations": dict(_ANNOTATIONS),
|
|
70
109
|
"inputSchema": {"type": "object", "properties": {**_REPO, **t["properties"]}}}
|
|
71
110
|
for t in TOOLS]
|
|
72
111
|
|
|
@@ -116,7 +155,7 @@ def _run_cli(tool: dict, arguments: dict, repo: str) -> dict:
|
|
|
116
155
|
proc = subprocess.run([sys.executable, "-m", "crapkit", *argv],
|
|
117
156
|
capture_output=True, text=True, timeout=600)
|
|
118
157
|
text = proc.stdout if proc.stdout.strip() else proc.stderr
|
|
119
|
-
return _result(text, is_error=proc.returncode != 0)
|
|
158
|
+
return _structured(_result(text, is_error=proc.returncode != 0))
|
|
120
159
|
|
|
121
160
|
|
|
122
161
|
def _call_tool(root: Path, name: str, arguments: dict) -> dict:
|
|
@@ -130,6 +169,43 @@ def _call_tool(root: Path, name: str, arguments: dict) -> dict:
|
|
|
130
169
|
return _run_cli(tool, arguments, repo)
|
|
131
170
|
|
|
132
171
|
|
|
172
|
+
# What a connected model needs before its first call, in the one field the
|
|
173
|
+
# protocol reserves for it. The nine error results a model would otherwise
|
|
174
|
+
# collect from an unmeasured repo teach the same thing nine times, slower.
|
|
175
|
+
_INSTRUCTIONS = (
|
|
176
|
+
"crapkit scores every function as ccn^2 x (1 - coverage)^3 + ccn; these nine tools read "
|
|
177
|
+
"the newest scored run and every one is read-only: nothing here runs a test suite or "
|
|
178
|
+
"writes to the repo. They need a repo measured once (crapkit init, then crapkit "
|
|
179
|
+
"coverage); an unmeasured repo answers with a one-line pointer instead of data. Start "
|
|
180
|
+
"with next_item for one function to fix, worklist for the whole ranking, brief for "
|
|
181
|
+
"everything about one function.")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _negotiated(params: dict) -> str:
|
|
185
|
+
"""The client's revision when this server implements it, else the newest it
|
|
186
|
+
does; the spec leaves proceeding or disconnecting to the client from there."""
|
|
187
|
+
offered = params.get("protocolVersion")
|
|
188
|
+
return offered if offered in SUPPORTED_PROTOCOLS else SUPPORTED_PROTOCOLS[0]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _structured(result: dict) -> dict:
|
|
192
|
+
"""Attach the parsed object beside the text when the text is a JSON object.
|
|
193
|
+
|
|
194
|
+
The --json commands print for machines; a client on the 2025-06-18 revision
|
|
195
|
+
reads structuredContent directly. Prose, JSON arrays and error text stay
|
|
196
|
+
text-only rather than getting wrapped into shapes the tools never promised.
|
|
197
|
+
"""
|
|
198
|
+
if result["isError"]:
|
|
199
|
+
return result
|
|
200
|
+
try:
|
|
201
|
+
parsed = json.loads(result["content"][0]["text"])
|
|
202
|
+
except ValueError:
|
|
203
|
+
return result
|
|
204
|
+
if isinstance(parsed, dict):
|
|
205
|
+
return {**result, "structuredContent": parsed}
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
|
|
133
209
|
def _respond(msg_id, result=None, error=None) -> dict:
|
|
134
210
|
resp = {"jsonrpc": "2.0", "id": msg_id}
|
|
135
211
|
resp["error" if error else "result"] = error if error else result
|
|
@@ -142,9 +218,10 @@ def _handle(root: Path, msg: dict) -> dict | None:
|
|
|
142
218
|
return None # a notification (e.g. notifications/initialized) needs no reply
|
|
143
219
|
if method == "initialize":
|
|
144
220
|
return _respond(msg["id"], {
|
|
145
|
-
"protocolVersion":
|
|
221
|
+
"protocolVersion": _negotiated(msg.get("params", {})),
|
|
146
222
|
"capabilities": {"tools": {}},
|
|
147
|
-
"serverInfo": {"name": "crapkit", "version": _version()}
|
|
223
|
+
"serverInfo": {"name": "crapkit", "version": _version()},
|
|
224
|
+
"instructions": _INSTRUCTIONS})
|
|
148
225
|
if method == "tools/list":
|
|
149
226
|
return _respond(msg["id"], {"tools": tool_listing()})
|
|
150
227
|
if method == "tools/call":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crapkit
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
4
4
|
Summary: Scores every function on complexity times uncovered risk, ranks the worst, and blocks commits that add more.
|
|
5
5
|
Author: Jean-Francois Gagne
|
|
6
6
|
License: MIT
|
|
@@ -39,10 +39,13 @@ Dynamic: license-file
|
|
|
39
39
|
|
|
40
40
|
# crapkit
|
|
41
41
|
|
|
42
|
+
<!-- mcp-name: io.github.jeanfrancoisgagne/crapkit -->
|
|
43
|
+
|
|
42
44
|
[](https://github.com/JeanFrancoisGagne/crapkit/actions/workflows/ci.yml)
|
|
43
45
|
[](https://pypi.org/project/crapkit/)
|
|
44
46
|
[](https://pypi.org/project/crapkit/)
|
|
45
47
|
[](https://github.com/JeanFrancoisGagne/crapkit/blob/main/LICENSE)
|
|
48
|
+
[](https://glama.ai/mcp/servers/JeanFrancoisGagne/crapkit)
|
|
46
49
|
|
|
47
50
|

|
|
48
51
|
|
|
@@ -165,7 +168,7 @@ leaves the box
|
|
|
165
168
|
|
|
166
169
|
```
|
|
167
170
|
$ crapkit --version
|
|
168
|
-
crapkit 0.4.
|
|
171
|
+
crapkit 0.4.14
|
|
169
172
|
```
|
|
170
173
|
|
|
171
174
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -395,7 +398,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
395
398
|
repos:
|
|
396
399
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
397
400
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
398
|
-
rev: v0.4.
|
|
401
|
+
rev: v0.4.14
|
|
399
402
|
hooks:
|
|
400
403
|
- id: crapkit-gate
|
|
401
404
|
```
|
|
@@ -501,7 +504,7 @@ to a workflow, and every input has a default:
|
|
|
501
504
|
- uses: actions/checkout@v4
|
|
502
505
|
with:
|
|
503
506
|
fetch-depth: 0
|
|
504
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
507
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.14
|
|
505
508
|
```
|
|
506
509
|
|
|
507
510
|
The whole job those four lines sit in:
|
|
@@ -521,7 +524,7 @@ jobs:
|
|
|
521
524
|
with:
|
|
522
525
|
python-version: "3.12" # the interpreter the install below lands in
|
|
523
526
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
524
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
527
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.14
|
|
525
528
|
with:
|
|
526
529
|
gate: "false"
|
|
527
530
|
```
|
|
@@ -1189,6 +1192,7 @@ that block is advisory unless `diff_uncovered_max` is set
|
|
|
1189
1192
|
| [docs/lanes.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/lanes.md) | The lane model, vitest and jest and pytest recipes, artifact reuse, flake retest, containers. |
|
|
1190
1193
|
| [docs/ratchet.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/ratchet.md) | Seeding, pruning, the git merge driver, metric stamps, debt policy, overrides. |
|
|
1191
1194
|
| [docs/agent-json.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/agent-json.md) | The machine surface: `schema`, every payload field, real captured examples. |
|
|
1195
|
+
| [docs/comparison.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/docs/comparison.md) | Where crapkit sits next to radon, xenon, wily, coverage.py and SonarQube, and how they run together. |
|
|
1192
1196
|
| [AGENTS.md](https://github.com/JeanFrancoisGagne/crapkit/blob/main/AGENTS.md) | The burn-down loop an agent runs, and the rules for changing crapkit itself. |
|
|
1193
1197
|
| [plugin/](https://github.com/JeanFrancoisGagne/crapkit/tree/main/plugin) | The Claude Code plugin: three skills, the read-side MCP server, and the advisory PostToolUse hook. |
|
|
1194
1198
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|