sensez 0.1.4 → 0.1.5
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 +245 -0
- package/package.json +11 -6
package/README.md
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
### Why can't coding agents detect code smells? Because they don't have a `noze`.
|
|
2
|
+
|
|
3
|
+
Coding agents are very good at producing code. They are also very good at
|
|
4
|
+
producing the same helper three times, gently ignoring your architecture notes,
|
|
5
|
+
and using `dict[str, Any]` when you ask for type safety. You ask it to complete
|
|
6
|
+
a task like "a staff software engineer", you ask it to follow SOLID principles
|
|
7
|
+
and use strong type safety. It happily agrees, and starts working on the task.
|
|
8
|
+
The vibes are immaculate. You come back a few minutes later to a slopocalypse
|
|
9
|
+
that looks nothing like what your AGENTS.md says and you spend hours trying to
|
|
10
|
+
understand where to start.
|
|
11
|
+
|
|
12
|
+
Sensez is a suite of Rust CLIs with an MCP server for maintenance before tech debt
|
|
13
|
+
accumulates. It runs beside your linter and type-checker and looks for cross-file
|
|
14
|
+
problems they usually do not own: duplication, dead code, import cycles, boundary
|
|
15
|
+
violations, and design smells. It is designed to give your coding agent the
|
|
16
|
+
`noze` to detect code smells, the `bonez` to respect architectural boundaries,
|
|
17
|
+
and the `spine` to do it fast.
|
|
18
|
+
|
|
19
|
+
Supported language profiles currently include Python, JavaScript, TypeScript, and Rust (for dogfooding primarily).
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
### Python
|
|
23
|
+
```Bash
|
|
24
|
+
# Run a one-off scan with uv
|
|
25
|
+
uvx --from sensez sensez noze .
|
|
26
|
+
|
|
27
|
+
# Add as a project dev dependency; run it with `uv run sensez ...`
|
|
28
|
+
uv add --dev sensez
|
|
29
|
+
uv run sensez init
|
|
30
|
+
|
|
31
|
+
# Install as a global CLI so `sensez ...` works directly
|
|
32
|
+
uv tool install sensez
|
|
33
|
+
sensez init
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### JS/TS
|
|
37
|
+
```Bash
|
|
38
|
+
# Add as a dev dependency
|
|
39
|
+
npm install --save-dev sensez
|
|
40
|
+
# Generate a sensez.toml starter config
|
|
41
|
+
npx sensez init .
|
|
42
|
+
|
|
43
|
+
# Run a one-off scan with npx
|
|
44
|
+
npx sensez noze .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`sensez .` and `sensez noze .` both run the default scan. The verbose form is
|
|
48
|
+
still available as `sensez noze sniff .`.
|
|
49
|
+
|
|
50
|
+
## Performance Snapshot
|
|
51
|
+
|
|
52
|
+
```mermaid
|
|
53
|
+
xychart-beta
|
|
54
|
+
title "pylint benchmark seconds"
|
|
55
|
+
x-axis ["sensez", "vulture", "repowise", "symilar"]
|
|
56
|
+
y-axis "seconds" 0 --> 20
|
|
57
|
+
bar [0.27, 1.29, 17.26, 20]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`sensez` scans all structural pillars in one pass (`0.27s`). `vulture` checks
|
|
61
|
+
Python dead code (`1.29s`). `repowise` uses a custom ranking mechanism, including dead code (`17.26s`).
|
|
62
|
+
`symilar` checks line-based duplication (`234.12s`; chart capped at `20s`).
|
|
63
|
+
|
|
64
|
+
### JS/TS
|
|
65
|
+
|
|
66
|
+
```mermaid
|
|
67
|
+
xychart-beta
|
|
68
|
+
title "zod benchmark seconds"
|
|
69
|
+
x-axis ["sensez", "fallow", "repowise"]
|
|
70
|
+
y-axis "seconds" 0 --> 6
|
|
71
|
+
bar [0.16, 0.48, 5.75]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`sensez` scans all structural pillars in one pass (`0.16s`). `fallow` checks
|
|
75
|
+
JS/TS structural dead-code and dependency findings (`0.48s`). `repowise` checks
|
|
76
|
+
repo intelligence signals, including dead code (`5.75s`).
|
|
77
|
+
|
|
78
|
+
`sensez` tries to lower dead code noise and allows for configuration of what gets reported. It also includes a few more Python and TS/JS opinionated smells, apart from overall structural consistency metrics.
|
|
79
|
+
|
|
80
|
+
## The Problem
|
|
81
|
+
|
|
82
|
+
Coding agents drift. Not due to bad intentions, but because their loop is leaky.
|
|
83
|
+
|
|
84
|
+
1. Context rots.
|
|
85
|
+
You told the agent to respect boundaries, follow SOLID, and think like a
|
|
86
|
+
staff engineer. Six turns later, the context has been summarized twice and
|
|
87
|
+
the agent is confidently rewriting the same csv file parser your colleague
|
|
88
|
+
wrote two weeks ago.
|
|
89
|
+
|
|
90
|
+
2. CI is too late.
|
|
91
|
+
CI is great at saying "absolutely not." It is much worse at saying "hm, this
|
|
92
|
+
duplication is small but suspicious." Non-blocking warnings have a natural
|
|
93
|
+
habitat: ignored forever.
|
|
94
|
+
|
|
95
|
+
3. Slow checks do not fit the turn.
|
|
96
|
+
If a check takes minutes, it should not run every agent turn. If it does not
|
|
97
|
+
run every turn, the slop has time to ferment.
|
|
98
|
+
```text
|
|
99
|
+
[Agent Proposes Turn Finish] ──> [ 👃 Sensez MCP Sniff ] ──> [ Catches Import Cycle / Duplication ]
|
|
100
|
+
│
|
|
101
|
+
└──> (Immediate Agent Feedback: "Loose typing violation on line 40 of code.py. Replace loose collections with dataclass/model.")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Sensez provides short, structured feedback directly to the agent while the edit is still fresh. Less archaeology, more "fix it before it becomes load-bearing."
|
|
105
|
+
|
|
106
|
+
## noze
|
|
107
|
+
|
|
108
|
+
`noze` takes care of the gorgonzola coding agents love so much:
|
|
109
|
+
|
|
110
|
+
| Area | Output key | What it catches |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| Duplication | `duplication` | Structural clones, including local rename copies. |
|
|
113
|
+
| Dead code | `dead_code` | Unreferenced symbols with confidence tiers. |
|
|
114
|
+
| Cycles | `cycles` | Import loops and load-order tangles. |
|
|
115
|
+
| Boundaries | `boundaries` | Imports crossing configured architecture rules. |
|
|
116
|
+
| Smells | `smells` | Design pressure inside functions, classes, modules, and the graph. |
|
|
117
|
+
|
|
118
|
+
Some smell examples:
|
|
119
|
+
|
|
120
|
+
| Smell | Why noze flags it |
|
|
121
|
+
|---|---|
|
|
122
|
+
| `tuple_packing` | Positional tuples hide meaning. `tuple[int, str, int]` is not a data model. |
|
|
123
|
+
| `loose_typing` | `Any` and vague containers erase the contract callers need. |
|
|
124
|
+
| `boolean_blindness` | `do_thing(True, False)` is a guessing game with arguments. |
|
|
125
|
+
| `implicit_schema` | Repeated string-key access usually means a real shape is hiding in a dict. |
|
|
126
|
+
| `mutated_parameter` | You pass a parameter and the function you sent it to returns it all chewed up. Disgusting. |
|
|
127
|
+
| `feature_envy` | A method that mostly uses another object's data may belong somewhere else. |
|
|
128
|
+
| `message_chain` | Long `a.b.c.d` chains couple callers to deep object plumbing. |
|
|
129
|
+
| `god_module` | One module has become the place everything depends on. |
|
|
130
|
+
| `magic_string_default` | Trying to lie to the type checker by adding an `\|\| ""` or `or ""` to hide a string that should be required. |
|
|
131
|
+
| `split_variable` | Multiple reassignments of the same variable within the same scope. Set to 1 to keep them constant within the scope and enforce helper functions for complex assignment logic. |
|
|
132
|
+
| `nested_loops` | [BETA, can be noisy] Nested iterations may blow up exponentially if not handled properly |
|
|
133
|
+
| `n_plus_one_call` | [BETA, can be noisy] Making external calls 1 by 1 (e.g. to a database) instead of using a batched approach. |
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
`noze` is not a formatter, linter, or type-checker. Keep using Ruff, ty, mypy,
|
|
137
|
+
ESLint, TypeScript, rustc, and Clippy. `noze` sits next to them and watches the
|
|
138
|
+
repo-level shape.
|
|
139
|
+
|
|
140
|
+
The default report is intentionally fixable in one screen: each pillar shows
|
|
141
|
+
only its top 5 offenders, each smell kind shows its own total plus top 3
|
|
142
|
+
examples, and dead-code output includes high-confidence findings only. Use
|
|
143
|
+
`--all` to print every finding, or `--max N` to choose a different cap.
|
|
144
|
+
|
|
145
|
+
For CI, filter to the pillars you care about:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
sensez noze . --duplicates
|
|
149
|
+
sensez noze . --duplicates --dead-code --json
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## MCP
|
|
153
|
+
|
|
154
|
+
MCP is the default integration path for agents. Use it when Sensez should run
|
|
155
|
+
repeatedly during a coding session instead of shelling out for one-off scans.
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
sensez mcp serve
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The MCP tools are themed but explicit:
|
|
162
|
+
|
|
163
|
+
| Tool | Use |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `noze_sniff` | Scan the repo for smells and structure issues. |
|
|
166
|
+
| `noze_gate` | End-of-turn diff gate for agent hooks; experimental and can be noisy on short/Q&A turns. |
|
|
167
|
+
| `noze_explain` | Explain a finding category. |
|
|
168
|
+
| `brainz_report` | Summarize local usage and resolution metrics. |
|
|
169
|
+
| `brainz_triage` | Record user-approved debt or false-positive verdicts. |
|
|
170
|
+
| `eyez_search_docs` | [disabled] Search docstrings/comments when `eyez` is enabled. |
|
|
171
|
+
|
|
172
|
+
You can also use the `sensez noze` CLI standalone in GitHub Actions.
|
|
173
|
+
|
|
174
|
+
## brainz
|
|
175
|
+
|
|
176
|
+
`brainz` is local-only memory. It records scans, gate blocks, triage decisions,
|
|
177
|
+
resolved findings, regressions, detector precision, and usage reports.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
sensez brainz report .
|
|
181
|
+
sensez brainz report . --json
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Everything stays under:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
.sensez/local-metrics/
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
No telemetry. No source upload. Disable it per repo:
|
|
191
|
+
|
|
192
|
+
```toml
|
|
193
|
+
[self_improvement]
|
|
194
|
+
enabled = false
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Configuration
|
|
198
|
+
|
|
199
|
+
Sensez reads `sensez.toml` from the project root, or `[tool.sensez]` from
|
|
200
|
+
`pyproject.toml` when `sensez.toml` is absent.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
sensez init . --yes
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Main knobs:
|
|
207
|
+
|
|
208
|
+
- `[duplication]` for clone thresholds
|
|
209
|
+
- `[dead_code]` for dynamic entrypoints
|
|
210
|
+
- `[smells]` for smell toggles and thresholds
|
|
211
|
+
- `[[boundaries.forbidden]]` for architecture contracts
|
|
212
|
+
- `[action]` for how strongly agents/gates treat each pillar
|
|
213
|
+
- `[accept]` for shared accepted findings
|
|
214
|
+
- `[self_improvement]` for local metrics
|
|
215
|
+
|
|
216
|
+
Small example:
|
|
217
|
+
|
|
218
|
+
```toml
|
|
219
|
+
[duplication]
|
|
220
|
+
threshold = 50
|
|
221
|
+
|
|
222
|
+
[dead_code]
|
|
223
|
+
entrypoint_names = ["register", "main", "setup"]
|
|
224
|
+
|
|
225
|
+
[smells.rules.long_function]
|
|
226
|
+
max_lines = 80
|
|
227
|
+
action = "warning"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Project Anatomy
|
|
231
|
+
|
|
232
|
+
- `spine`: file discovery, parsing, shared IR, and dependency graph.
|
|
233
|
+
- `profiles`: language adapters for Python, JS/TS, TSX, and Rust.
|
|
234
|
+
- `noze`: duplication, dead code, cycles, and design smells.
|
|
235
|
+
- `bonez`: architecture boundary auditing. Not yet enabled.
|
|
236
|
+
- `brainz`: local-only metrics and feedback memory.
|
|
237
|
+
- `eyez`: optional doc/comment search. Not yet enabled.
|
|
238
|
+
- `mcp`: JSON-RPC/MCP surface for agent integration.
|
|
239
|
+
- `reporter`: terminal and JSON output.
|
|
240
|
+
- `setup`: `sensez init`, starter config, MCP registration, and hook setup.
|
|
241
|
+
|
|
242
|
+
## Privacy
|
|
243
|
+
|
|
244
|
+
Sensez does not send telemetry or source code anywhere. Local metrics stay under
|
|
245
|
+
`.sensez/local-metrics/`.
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sensez",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Sensez CLI launcher for structural maintainability checks",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"readme": "README.md",
|
|
6
7
|
"type": "module",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
@@ -13,18 +14,22 @@
|
|
|
13
14
|
"sensez": "bin/sensez.js"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
16
|
-
"bin"
|
|
17
|
+
"bin",
|
|
18
|
+
"README.md"
|
|
17
19
|
],
|
|
18
20
|
"optionalDependencies": {
|
|
19
|
-
"sensez-darwin-arm64": "0.1.
|
|
20
|
-
"sensez-darwin-x64": "0.1.
|
|
21
|
-
"sensez-linux-arm64-gnu": "0.1.
|
|
22
|
-
"sensez-linux-x64-gnu": "0.1.
|
|
21
|
+
"sensez-darwin-arm64": "0.1.5",
|
|
22
|
+
"sensez-darwin-x64": "0.1.5",
|
|
23
|
+
"sensez-linux-arm64-gnu": "0.1.5",
|
|
24
|
+
"sensez-linux-x64-gnu": "0.1.5"
|
|
23
25
|
},
|
|
24
26
|
"publishConfig": {
|
|
25
27
|
"provenance": true
|
|
26
28
|
},
|
|
27
29
|
"engines": {
|
|
28
30
|
"node": ">=18"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"prepublishOnly": "node -e \"require('node:fs').copyFileSync('../README.md','README.md')\""
|
|
29
34
|
}
|
|
30
35
|
}
|