crapkit 0.4.12__tar.gz → 0.4.13__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.13}/PKG-INFO +6 -5
- {crapkit-0.4.12 → crapkit-0.4.13}/README.md +5 -4
- {crapkit-0.4.12 → crapkit-0.4.13}/pyproject.toml +1 -1
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/__init__.py +1 -1
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/mcp_server.py +97 -20
- {crapkit-0.4.12 → crapkit-0.4.13/src/crapkit.egg-info}/PKG-INFO +6 -5
- {crapkit-0.4.12 → crapkit-0.4.13}/LICENSE +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/setup.cfg +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/__main__.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/_pygdefer.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/analyze.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cache.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/churn.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/churn_cache.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/churn_log.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/__init__.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/_shared.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/admin.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/analyses.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/claude_hook.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/parser.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/queue.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/ratchet_cmds.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/reports.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/scoring.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/cli/verifying.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/config.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/coupling.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/coupling_cache.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/coverage_istanbul.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/coverage_py.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/covstream.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/diffparse.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/digest.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/discover.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/doctor.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/dup.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/errors.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/gitio.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/hook.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/invocation.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/junitparse.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/keys.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/lanes.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/lizardcognitive.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/lizardpowershell.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/lizardrust.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/lizardshell.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/merge.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/mutate.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/mutate_pool.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/override.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/packet.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/procs.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/ratchet.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/ratchet_report.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/report.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/sarif.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/sarifio.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/scaffold.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/score.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/snapshot.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/store.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/uncovered.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/universe.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/verify.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/watch.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit/worklist.py +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit.egg-info/SOURCES.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit.egg-info/dependency_links.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit.egg-info/entry_points.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/src/crapkit.egg-info/requires.txt +0 -0
- {crapkit-0.4.12 → crapkit-0.4.13}/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.13
|
|
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
|
|
@@ -43,6 +43,7 @@ Dynamic: license-file
|
|
|
43
43
|
[](https://pypi.org/project/crapkit/)
|
|
44
44
|
[](https://pypi.org/project/crapkit/)
|
|
45
45
|
[](https://github.com/JeanFrancoisGagne/crapkit/blob/main/LICENSE)
|
|
46
|
+
[](https://glama.ai/mcp/servers/JeanFrancoisGagne/crapkit)
|
|
46
47
|
|
|
47
48
|

|
|
48
49
|
|
|
@@ -165,7 +166,7 @@ leaves the box
|
|
|
165
166
|
|
|
166
167
|
```
|
|
167
168
|
$ crapkit --version
|
|
168
|
-
crapkit 0.4.
|
|
169
|
+
crapkit 0.4.13
|
|
169
170
|
```
|
|
170
171
|
|
|
171
172
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -395,7 +396,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
395
396
|
repos:
|
|
396
397
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
397
398
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
398
|
-
rev: v0.4.
|
|
399
|
+
rev: v0.4.13
|
|
399
400
|
hooks:
|
|
400
401
|
- id: crapkit-gate
|
|
401
402
|
```
|
|
@@ -501,7 +502,7 @@ to a workflow, and every input has a default:
|
|
|
501
502
|
- uses: actions/checkout@v4
|
|
502
503
|
with:
|
|
503
504
|
fetch-depth: 0
|
|
504
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
505
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.13
|
|
505
506
|
```
|
|
506
507
|
|
|
507
508
|
The whole job those four lines sit in:
|
|
@@ -521,7 +522,7 @@ jobs:
|
|
|
521
522
|
with:
|
|
522
523
|
python-version: "3.12" # the interpreter the install below lands in
|
|
523
524
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
524
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
525
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.13
|
|
525
526
|
with:
|
|
526
527
|
gate: "false"
|
|
527
528
|
```
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://pypi.org/project/crapkit/)
|
|
5
5
|
[](https://pypi.org/project/crapkit/)
|
|
6
6
|
[](https://github.com/JeanFrancoisGagne/crapkit/blob/main/LICENSE)
|
|
7
|
+
[](https://glama.ai/mcp/servers/JeanFrancoisGagne/crapkit)
|
|
7
8
|
|
|
8
9
|

|
|
9
10
|
|
|
@@ -126,7 +127,7 @@ leaves the box
|
|
|
126
127
|
|
|
127
128
|
```
|
|
128
129
|
$ crapkit --version
|
|
129
|
-
crapkit 0.4.
|
|
130
|
+
crapkit 0.4.13
|
|
130
131
|
```
|
|
131
132
|
|
|
132
133
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -356,7 +357,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
356
357
|
repos:
|
|
357
358
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
358
359
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
359
|
-
rev: v0.4.
|
|
360
|
+
rev: v0.4.13
|
|
360
361
|
hooks:
|
|
361
362
|
- id: crapkit-gate
|
|
362
363
|
```
|
|
@@ -462,7 +463,7 @@ to a workflow, and every input has a default:
|
|
|
462
463
|
- uses: actions/checkout@v4
|
|
463
464
|
with:
|
|
464
465
|
fetch-depth: 0
|
|
465
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
466
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.13
|
|
466
467
|
```
|
|
467
468
|
|
|
468
469
|
The whole job those four lines sit in:
|
|
@@ -482,7 +483,7 @@ jobs:
|
|
|
482
483
|
with:
|
|
483
484
|
python-version: "3.12" # the interpreter the install below lands in
|
|
484
485
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
485
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
486
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.13
|
|
486
487
|
with:
|
|
487
488
|
gate: "false"
|
|
488
489
|
```
|
|
@@ -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.13"
|
|
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.13"
|
|
@@ -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.13
|
|
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
|
|
@@ -43,6 +43,7 @@ Dynamic: license-file
|
|
|
43
43
|
[](https://pypi.org/project/crapkit/)
|
|
44
44
|
[](https://pypi.org/project/crapkit/)
|
|
45
45
|
[](https://github.com/JeanFrancoisGagne/crapkit/blob/main/LICENSE)
|
|
46
|
+
[](https://glama.ai/mcp/servers/JeanFrancoisGagne/crapkit)
|
|
46
47
|
|
|
47
48
|

|
|
48
49
|
|
|
@@ -165,7 +166,7 @@ leaves the box
|
|
|
165
166
|
|
|
166
167
|
```
|
|
167
168
|
$ crapkit --version
|
|
168
|
-
crapkit 0.4.
|
|
169
|
+
crapkit 0.4.13
|
|
169
170
|
```
|
|
170
171
|
|
|
171
172
|
`python -m crapkit` works identically to the console script and is what to use from a
|
|
@@ -395,7 +396,7 @@ crapkit ships a `.pre-commit-hooks.yaml` declaring `id: crapkit-gate`. In your
|
|
|
395
396
|
repos:
|
|
396
397
|
- repo: https://github.com/JeanFrancoisGagne/crapkit
|
|
397
398
|
# crapkit's release step rewrites this line to the tag it just cut
|
|
398
|
-
rev: v0.4.
|
|
399
|
+
rev: v0.4.13
|
|
399
400
|
hooks:
|
|
400
401
|
- id: crapkit-gate
|
|
401
402
|
```
|
|
@@ -501,7 +502,7 @@ to a workflow, and every input has a default:
|
|
|
501
502
|
- uses: actions/checkout@v4
|
|
502
503
|
with:
|
|
503
504
|
fetch-depth: 0
|
|
504
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
505
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.13
|
|
505
506
|
```
|
|
506
507
|
|
|
507
508
|
The whole job those four lines sit in:
|
|
@@ -521,7 +522,7 @@ jobs:
|
|
|
521
522
|
with:
|
|
522
523
|
python-version: "3.12" # the interpreter the install below lands in
|
|
523
524
|
- run: pip install -e ".[dev]" # whatever your lanes need to run
|
|
524
|
-
- uses: JeanFrancoisGagne/crapkit@v0.4.
|
|
525
|
+
- uses: JeanFrancoisGagne/crapkit@v0.4.13
|
|
525
526
|
with:
|
|
526
527
|
gate: "false"
|
|
527
528
|
```
|
|
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
|