@praneeth_54/agentdoctor 0.1.3-beta → 0.2.0-beta
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/CHANGELOG.md +41 -3
- package/README.md +226 -193
- package/dist/cli/commands/doctor.js +1 -1
- package/dist/cli/commands/scan.js +4 -12
- package/dist/cli/program.js +4 -4
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/scanner/scan.d.ts +1 -2
- package/dist/core/scanner/scan.js +8 -5
- package/dist/core/scoring/compute-scores.d.ts +6 -0
- package/dist/core/scoring/compute-scores.js +90 -0
- package/dist/core/scoring/placeholder.d.ts +3 -3
- package/dist/core/scoring/placeholder.js +3 -3
- package/dist/types/index.d.ts +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,9 +9,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Planned
|
|
11
11
|
|
|
12
|
-
- Deterministic readiness scoring
|
|
13
12
|
- Safe automatic fixes
|
|
14
|
-
-
|
|
13
|
+
- Terminal readiness line and GitHub Action score-gate inputs (deferred; see scoring.md v2+)
|
|
14
|
+
|
|
15
|
+
## [0.2.0-beta] — 2026-08-02
|
|
16
|
+
|
|
17
|
+
Minor beta: deterministic readiness scoring and CLI `--min-score` enforcement.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Deterministic readiness scoring (v1): `scan()` populates `scoringAvailable: true` and
|
|
22
|
+
`scores` (`overall`, `categories`, `agents`) from post-dedupe findings
|
|
23
|
+
([docs/scoring.md](docs/scoring.md))
|
|
24
|
+
- CLI `--min-score N` enforcement: exit code `1` when `scores.overall < N`
|
|
25
|
+
- `--ci` without `--min-score` remains report-only (exit `0` on successful scan)
|
|
26
|
+
- Scoring specification and compatibility / exit-code docs updated for shipped behavior
|
|
27
|
+
|
|
28
|
+
### Compatibility
|
|
29
|
+
|
|
30
|
+
- No new JSON top-level fields (`scoringModel` / `scoreExplanation` deferred)
|
|
31
|
+
- Findings, rule IDs, and agent detection unchanged
|
|
32
|
+
- GitHub Action remains `--ci --json` report-only (no score-gate inputs)
|
|
33
|
+
- Default Action `version` input is `0.2.0-beta`
|
|
34
|
+
|
|
35
|
+
## [0.1.4-beta] — 2026-08-02
|
|
36
|
+
|
|
37
|
+
Backward-compatible distribution release: first-class GitHub Action packaging. CLI and scanner behavior are unchanged from 0.1.3-beta.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Composite GitHub Action (`action.yml`) that installs the published `@praneeth_54/agentdoctor` package and emits a workspace-contained JSON report
|
|
42
|
+
- CI `action-smoke` matrix covering normal/nested output paths and rejection of traversal, parent-symlink escape, final-file symlink, and directory output targets
|
|
43
|
+
- README GitHub Action usage section and ROADMAP update for CI packaging
|
|
44
|
+
|
|
45
|
+
### Compatibility
|
|
46
|
+
|
|
47
|
+
- No scanner, rule, or JSON finding-schema changes
|
|
48
|
+
- Scoring remains unavailable (`scoringAvailable: false`)
|
|
49
|
+
- `--min-score` remains accepted but ignored until scoring ships
|
|
50
|
+
- Default Action `version` input is `0.1.4-beta` (exact npm version or `latest` / `beta` dist-tags)
|
|
15
51
|
|
|
16
52
|
## [0.1.3-beta] — 2026-07-29
|
|
17
53
|
|
|
@@ -107,7 +143,9 @@ First public beta.
|
|
|
107
143
|
- Not a complete secret scanner
|
|
108
144
|
- Git “tracked secret” detection deferred
|
|
109
145
|
|
|
110
|
-
[Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v0.
|
|
146
|
+
[Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v0.2.0-beta...HEAD
|
|
147
|
+
[0.2.0-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.2.0-beta
|
|
148
|
+
[0.1.4-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.4-beta
|
|
111
149
|
[0.1.3-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.3-beta
|
|
112
150
|
[0.1.2-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.2-beta
|
|
113
151
|
[0.1.1-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.1-beta
|
package/README.md
CHANGED
|
@@ -1,41 +1,43 @@
|
|
|
1
1
|
# AgentDoctor
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
|
|
4
|
-
[](https://github.com/pranee54/AgentDoctor/stargazers)
|
|
4
|
+
[](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
|
|
6
5
|
[](https://github.com/pranee54/AgentDoctor/actions)
|
|
7
6
|
[](https://nodejs.org)
|
|
8
|
-
[](LICENSE)
|
|
9
8
|
|
|
10
9
|
**Lighthouse for AI coding agents.**
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
Audit coding-agent configuration before it becomes a repository problem.
|
|
12
|
+
|
|
13
|
+
AgentDoctor is a local CLI that inspects project-level AI coding agent setup — Cursor, Claude Code, and Codex — for security, instructions, context, and MCP configuration. Deterministic static analysis. No API key. No code upload by default.
|
|
13
14
|
|
|
14
15
|
```bash
|
|
15
16
|
npx @praneeth_54/agentdoctor
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
| -------------- | ----------------------------------------------------------------------------------- |
|
|
20
|
-
| **What it is** | A CLI health check for agent config in your repo |
|
|
21
|
-
| **Why use it** | Catch misconfigurations, sensitive context exposure, and instruction problems early |
|
|
22
|
-
| **Install** | `npx @praneeth_54/agentdoctor` or `npm install -g @praneeth_54/agentdoctor` |
|
|
23
|
-
| **Requires** | Node.js 20+ |
|
|
19
|
+
Public beta (`0.1.x-beta`). Deterministic readiness scores ship in JSON; automatic fixes are not available yet.
|
|
24
20
|
|
|
25
21
|
---
|
|
26
22
|
|
|
27
|
-
##
|
|
23
|
+
## What you get
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
_Real scan of the included `insecure-agent-project` fixture using AgentDoctor v0.2.0-beta._
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
30
|
$ npx @praneeth_54/agentdoctor
|
|
31
31
|
|
|
32
|
-
AgentDoctor v0.
|
|
32
|
+
🩺 AgentDoctor v0.2.0-beta
|
|
33
|
+
|
|
34
|
+
Scanning repository...
|
|
33
35
|
|
|
34
36
|
Repository
|
|
35
|
-
Framework:
|
|
36
|
-
Language:
|
|
37
|
+
Framework: Node.js
|
|
38
|
+
Language: JavaScript
|
|
37
39
|
Package manager: npm
|
|
38
|
-
Files scanned:
|
|
40
|
+
Files scanned: 7
|
|
39
41
|
|
|
40
42
|
AI Coding Agents
|
|
41
43
|
|
|
@@ -48,59 +50,134 @@ Findings
|
|
|
48
50
|
CRITICAL
|
|
49
51
|
|
|
50
52
|
✗ Sensitive environment file may enter agent context
|
|
51
|
-
.env
|
|
53
|
+
.env
|
|
52
54
|
Affected: Claude Code, Codex
|
|
53
|
-
Fix:
|
|
55
|
+
Fix: Add an agent-specific exclusion (for example .cursorignore or a
|
|
56
|
+
Claude Code Read deny rule), keep the file out of version control,
|
|
57
|
+
and rotate any credentials that may have been exposed.
|
|
58
|
+
|
|
59
|
+
✗ Private key or credential file present in repository
|
|
60
|
+
test-private-key.pem
|
|
61
|
+
Affected: Claude Code, Codex, Cursor
|
|
54
62
|
|
|
55
63
|
WARNING
|
|
56
64
|
|
|
57
|
-
!
|
|
58
|
-
|
|
65
|
+
! Claude Code bypassPermissions mode enabled
|
|
66
|
+
.claude/settings.json
|
|
59
67
|
|
|
60
68
|
Summary
|
|
61
69
|
|
|
62
|
-
|
|
70
|
+
3 critical
|
|
63
71
|
1 warning
|
|
64
72
|
0 info
|
|
65
73
|
|
|
66
|
-
Scoring
|
|
74
|
+
Scoring: not included in this release
|
|
67
75
|
```
|
|
68
76
|
|
|
77
|
+
Abbreviated text example from the same fixture for accessibility and search. Secret values are never printed.
|
|
78
|
+
|
|
69
79
|
---
|
|
70
80
|
|
|
71
|
-
## Why AgentDoctor
|
|
81
|
+
## Why AgentDoctor?
|
|
82
|
+
|
|
83
|
+
Repositories accumulate agent configuration quickly:
|
|
84
|
+
|
|
85
|
+
- Multiple instruction formats (`.cursor/rules`, `CLAUDE.md`, `AGENTS.md`)
|
|
86
|
+
- Stale path references in always-on instructions
|
|
87
|
+
- Ignore differences between `.gitignore`, `.cursorignore`, and agent defaults
|
|
88
|
+
- MCP filesystem scopes that are broader than intended
|
|
89
|
+
- Generated directories and large logs that waste context
|
|
90
|
+
- Credential-like files that may be readable by agents
|
|
91
|
+
- Conflicting assumptions about what each agent can see
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
Manually reviewing all of that across Cursor, Claude Code, and Codex is slow and inconsistent. AgentDoctor provides one deterministic local audit with stable rule IDs, evidence paths, and affected-agent information.
|
|
74
94
|
|
|
75
|
-
|
|
|
95
|
+
| Analogy | Domain |
|
|
76
96
|
| --------------- | -------------------------------- |
|
|
77
97
|
| Lighthouse | Web pages |
|
|
78
98
|
| `npm audit` | Dependencies |
|
|
79
99
|
| ESLint | Source code |
|
|
80
100
|
| **AgentDoctor** | **AI coding agent environments** |
|
|
81
101
|
|
|
82
|
-
AgentDoctor analyzes configuration
|
|
102
|
+
AgentDoctor analyzes configuration. It does not run agents, call an LLM, or modify your repository in this release.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Before / after
|
|
107
|
+
|
|
108
|
+
**Before**
|
|
109
|
+
|
|
110
|
+
A repository may contain:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
.cursor/rules/
|
|
114
|
+
AGENTS.md
|
|
115
|
+
CLAUDE.md
|
|
116
|
+
.claude/settings.json
|
|
117
|
+
.mcp.json
|
|
118
|
+
.env
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Potential problems stay invisible until something leaks into model context, CI, or a teammate’s agent session:
|
|
122
|
+
|
|
123
|
+
- environment or credential-like files reachable by agents
|
|
124
|
+
- stale instruction path references
|
|
125
|
+
- broad MCP filesystem access
|
|
126
|
+
- oversized always-on context
|
|
127
|
+
|
|
128
|
+
**Run**
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx @praneeth_54/agentdoctor
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**After**
|
|
135
|
+
|
|
136
|
+
You get deterministic findings with:
|
|
137
|
+
|
|
138
|
+
- stable rule IDs (for example `security/env-file-exposure`)
|
|
139
|
+
- evidence paths
|
|
140
|
+
- affected agents when exposure claims are supported
|
|
141
|
+
- conservative recommendations
|
|
142
|
+
|
|
143
|
+
Automatic repair is **not** included in this beta. Findings tell you what to review; you decide what to change.
|
|
83
144
|
|
|
84
145
|
---
|
|
85
146
|
|
|
86
|
-
##
|
|
147
|
+
## Quick start
|
|
87
148
|
|
|
88
|
-
### One-shot
|
|
149
|
+
### One-shot (recommended)
|
|
89
150
|
|
|
90
151
|
```bash
|
|
91
|
-
npx @praneeth_54/agentdoctor
|
|
152
|
+
npx @praneeth_54/agentdoctor
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Pin a beta version when you need a fixed install:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
npx @praneeth_54/agentdoctor@0.2.0-beta
|
|
92
159
|
```
|
|
93
160
|
|
|
94
161
|
### Global (optional)
|
|
95
162
|
|
|
96
163
|
```bash
|
|
97
|
-
npm install -g @praneeth_54/agentdoctor
|
|
164
|
+
npm install -g @praneeth_54/agentdoctor
|
|
98
165
|
agentdoctor
|
|
99
166
|
```
|
|
100
167
|
|
|
101
|
-
|
|
168
|
+
### Common commands
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
agentdoctor .
|
|
172
|
+
agentdoctor . --json
|
|
173
|
+
agentdoctor . --verbose
|
|
174
|
+
agentdoctor explain security/env-file-exposure
|
|
175
|
+
agentdoctor doctor
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Package name: `@praneeth_54/agentdoctor` (npm blocks the unscoped name). CLI binary: `agentdoctor`. Requires **Node.js 20+**.
|
|
102
179
|
|
|
103
|
-
###
|
|
180
|
+
### Programmatic API
|
|
104
181
|
|
|
105
182
|
```bash
|
|
106
183
|
npm install @praneeth_54/agentdoctor
|
|
@@ -111,218 +188,164 @@ import { scan } from "@praneeth_54/agentdoctor";
|
|
|
111
188
|
|
|
112
189
|
const result = await scan({ cwd: process.cwd() });
|
|
113
190
|
console.log(result.summary);
|
|
191
|
+
console.log(result.agentSecurityAnalysis); // "full" | "limited"
|
|
114
192
|
```
|
|
115
193
|
|
|
116
194
|
---
|
|
117
195
|
|
|
118
|
-
##
|
|
196
|
+
## Supported agents
|
|
119
197
|
|
|
120
|
-
|
|
121
|
-
# Scan the current directory
|
|
122
|
-
npx @praneeth_54/agentdoctor
|
|
198
|
+
Project-level configuration only (repository files). Global user settings are not scanned.
|
|
123
199
|
|
|
124
|
-
|
|
125
|
-
|
|
200
|
+
| Agent | What AgentDoctor inspects |
|
|
201
|
+
| --------------- | ---------------------------------------------------------------------- |
|
|
202
|
+
| **Cursor** | `.cursor/rules/*.mdc`, `.cursorignore`, Cursor MCP config, `AGENTS.md` |
|
|
203
|
+
| **Claude Code** | `CLAUDE.md`, `.claude/settings*.json`, `.claude/rules`, MCP config |
|
|
204
|
+
| **Codex** | `AGENTS.md` / overrides, project `.codex/` configuration |
|
|
126
205
|
|
|
127
|
-
|
|
128
|
-
npx @praneeth_54/agentdoctor --json
|
|
206
|
+
Additional adapters are planned — see [ROADMAP.md](ROADMAP.md).
|
|
129
207
|
|
|
130
|
-
|
|
131
|
-
npx @praneeth_54/agentdoctor --verbose
|
|
208
|
+
---
|
|
132
209
|
|
|
133
|
-
|
|
134
|
-
npx @praneeth_54/agentdoctor explain security/env-file-exposure
|
|
210
|
+
## Finding categories
|
|
135
211
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
212
|
+
| Category | Examples |
|
|
213
|
+
| ---------------- | --------------------------------------------------------------------- |
|
|
214
|
+
| **Security** | Env-file exposure, private-key filenames, broad MCP filesystem scopes |
|
|
215
|
+
| **Context** | Large instruction files, large logs, unignored generated directories |
|
|
216
|
+
| **Instructions** | Empty instructions, duplicate content, missing path references |
|
|
217
|
+
| **MCP** | Malformed MCP config, high-risk filesystem path arguments |
|
|
139
218
|
|
|
140
|
-
|
|
219
|
+
Full catalog with severities and fixability: [docs/rules.md](docs/rules.md).
|
|
141
220
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
| Capability | Status |
|
|
145
|
-
| ------------------------------------------------------- | ------- |
|
|
146
|
-
| Zero-config first run | ✓ |
|
|
147
|
-
| Works offline / no API key | ✓ |
|
|
148
|
-
| Detects project-level agent configuration | ✓ |
|
|
149
|
-
| Deterministic security / context / instruction findings | ✓ |
|
|
150
|
-
| Inspects supported MCP project configuration | ✓ |
|
|
151
|
-
| Stable JSON output for CI | ✓ |
|
|
152
|
-
| `explain <rule>` documentation | ✓ |
|
|
153
|
-
| Readiness scoring | Planned |
|
|
154
|
-
| Safe automatic fixes | Planned |
|
|
155
|
-
| Official GitHub Action package | Planned |
|
|
156
|
-
|
|
157
|
-
### Feature comparison
|
|
158
|
-
|
|
159
|
-
| Concern | Manual review | Generic linters | AgentDoctor |
|
|
160
|
-
| -------------------------------------------- | ------------- | --------------- | ---------------- |
|
|
161
|
-
| Agent instruction files present and usable | Manual | — | ✓ |
|
|
162
|
-
| Empty or duplicated instructions | Manual | — | ✓ |
|
|
163
|
-
| Sensitive filenames vs agent access patterns | Manual | Partial | ✓ (conservative) |
|
|
164
|
-
| Broad MCP filesystem scopes | Manual | — | ✓ |
|
|
165
|
-
| Large always-on instruction files | Manual | — | ✓ |
|
|
166
|
-
| Uploads repository by default | — | Sometimes | **Never** |
|
|
221
|
+
Explain any rule:
|
|
167
222
|
|
|
168
|
-
|
|
223
|
+
```bash
|
|
224
|
+
npx @praneeth_54/agentdoctor explain security/env-file-exposure
|
|
225
|
+
```
|
|
169
226
|
|
|
170
|
-
|
|
227
|
+
---
|
|
171
228
|
|
|
172
|
-
|
|
229
|
+
## Privacy and trust
|
|
173
230
|
|
|
174
|
-
|
|
175
|
-
| ----------- | ------------------------------------------ |
|
|
176
|
-
| Cursor | Rules, ignore files, MCP, `AGENTS.md` |
|
|
177
|
-
| Claude Code | Instructions, settings, rules, MCP |
|
|
178
|
-
| Codex | `AGENTS.md` / overrides, project `.codex/` |
|
|
231
|
+
**Scans run locally on your machine.**
|
|
179
232
|
|
|
180
|
-
|
|
233
|
+
AgentDoctor:
|
|
181
234
|
|
|
182
|
-
|
|
235
|
+
- does not require an API key
|
|
236
|
+
- does not upload repository contents by default
|
|
237
|
+
- does not call an LLM for core scanning
|
|
238
|
+
- does not execute MCP servers
|
|
239
|
+
- does not execute project code
|
|
240
|
+
- never prints secret values from files it flags by name
|
|
241
|
+
- enforces repository boundary checks for path references and symlink escape
|
|
183
242
|
|
|
184
|
-
|
|
243
|
+
This is still software that reads untrusted repository trees. Treat findings as guidance, not a security certification. AgentDoctor is **not** a complete secret-content scanner.
|
|
185
244
|
|
|
186
245
|
---
|
|
187
246
|
|
|
188
|
-
##
|
|
247
|
+
## CI usage
|
|
189
248
|
|
|
190
|
-
|
|
191
|
-
┌─────────────┐
|
|
192
|
-
│ Discovery │ bounded filesystem walk
|
|
193
|
-
└──────┬──────┘
|
|
194
|
-
▼
|
|
195
|
-
┌─────────────────┐
|
|
196
|
-
│ Project detect │ language / framework / package manager
|
|
197
|
-
└──────┬──────────┘
|
|
198
|
-
▼
|
|
199
|
-
┌─────────────────┐
|
|
200
|
-
│ Agent adapters │ Cursor · Claude Code · Codex
|
|
201
|
-
└──────┬──────────┘
|
|
202
|
-
▼
|
|
203
|
-
┌─────────────────┐
|
|
204
|
-
│ Rule engine │ security · context · instructions · MCP
|
|
205
|
-
└──────┬──────────┘
|
|
206
|
-
▼
|
|
207
|
-
┌─────────────────┐
|
|
208
|
-
│ Findings │ deterministic IDs · deduped · fixability metadata
|
|
209
|
-
└──────┬──────────┘
|
|
210
|
-
▼
|
|
211
|
-
┌─────────────────┐
|
|
212
|
-
│ Reporters │ terminal · JSON
|
|
213
|
-
└─────────────────┘
|
|
214
|
-
```
|
|
249
|
+
### GitHub Action
|
|
215
250
|
|
|
216
|
-
|
|
251
|
+
Run AgentDoctor directly in a workflow:
|
|
217
252
|
|
|
218
|
-
|
|
253
|
+
```yaml
|
|
254
|
+
permissions:
|
|
255
|
+
contents: read
|
|
219
256
|
|
|
220
|
-
|
|
257
|
+
steps:
|
|
258
|
+
- uses: actions/checkout@v4
|
|
221
259
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
260
|
+
- name: Audit coding-agent configuration
|
|
261
|
+
id: agentdoctor
|
|
262
|
+
uses: pranee54/AgentDoctor@v0.2.0-beta
|
|
263
|
+
with:
|
|
264
|
+
path: .
|
|
265
|
+
output-file: agentdoctor-report.json
|
|
225
266
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"primaryLanguage": "typescript",
|
|
232
|
-
"filesScanned": 46
|
|
233
|
-
},
|
|
234
|
-
"agents": [
|
|
235
|
-
{
|
|
236
|
-
"id": "cursor",
|
|
237
|
-
"detected": true,
|
|
238
|
-
"configured": true,
|
|
239
|
-
"status": "configured"
|
|
240
|
-
}
|
|
241
|
-
],
|
|
242
|
-
"findings": [
|
|
243
|
-
{
|
|
244
|
-
"id": "security/env-file-exposure:.env.production",
|
|
245
|
-
"ruleId": "security/env-file-exposure",
|
|
246
|
-
"category": "security",
|
|
247
|
-
"severity": "critical",
|
|
248
|
-
"title": "Sensitive environment file may enter agent context",
|
|
249
|
-
"affectedAgents": ["claude-code", "codex"],
|
|
250
|
-
"fixability": "review"
|
|
251
|
-
}
|
|
252
|
-
],
|
|
253
|
-
"summary": { "critical": 1, "warning": 0, "info": 0, "total": 1 },
|
|
254
|
-
"scoringAvailable": false,
|
|
255
|
-
"scores": null
|
|
256
|
-
}
|
|
267
|
+
- name: Upload AgentDoctor report
|
|
268
|
+
uses: actions/upload-artifact@v4
|
|
269
|
+
with:
|
|
270
|
+
name: agentdoctor-report
|
|
271
|
+
path: ${{ steps.agentdoctor.outputs.report-path }}
|
|
257
272
|
```
|
|
258
273
|
|
|
259
|
-
|
|
274
|
+
The action installs the published `@praneeth_54/agentdoctor@0.2.0-beta` package, runs it with
|
|
275
|
+
`--ci --json`, and writes the report inside the checked-out workspace. It sets up Node.js 20
|
|
276
|
+
for the CLI. The optional `version` input accepts an exact npm version or the `latest` / `beta`
|
|
277
|
+
dist-tag.
|
|
260
278
|
|
|
261
|
-
|
|
279
|
+
### CLI
|
|
262
280
|
|
|
263
|
-
|
|
281
|
+
Use JSON directly in other CI systems:
|
|
264
282
|
|
|
265
|
-
|
|
283
|
+
```bash
|
|
284
|
+
# Report-only (exit 0 even when findings exist; scores still in JSON)
|
|
285
|
+
npx @praneeth_54/agentdoctor --ci --json
|
|
266
286
|
|
|
267
|
-
|
|
287
|
+
# Fail CI when overall readiness is below 70
|
|
288
|
+
npx @praneeth_54/agentdoctor --ci --json --min-score 70
|
|
289
|
+
```
|
|
268
290
|
|
|
269
|
-
-
|
|
270
|
-
-
|
|
271
|
-
|
|
272
|
-
- execute project code
|
|
273
|
-
- start MCP servers
|
|
274
|
-
- enable telemetry by default
|
|
291
|
+
`--ci` runs non-interactively and does **not** apply an implicit score threshold.
|
|
292
|
+
Use `--min-score N` (with or without `--ci`) to fail with exit code `1` when
|
|
293
|
+
`scores.overall < N`.
|
|
275
294
|
|
|
276
|
-
|
|
295
|
+
Exit codes: [docs/exit-codes.md](docs/exit-codes.md). Compatibility promises: [docs/compatibility.md](docs/compatibility.md).
|
|
277
296
|
|
|
278
|
-
|
|
297
|
+
### Readiness scoring
|
|
279
298
|
|
|
280
|
-
|
|
299
|
+
Scans populate `scoringAvailable: true` and a deterministic `scores` object
|
|
300
|
+
(overall, categories, agents). The terminal report does not render a readiness line yet;
|
|
301
|
+
scores are available in JSON (`--json`).
|
|
281
302
|
|
|
282
|
-
|
|
283
|
-
|
|
303
|
+
`--min-score N` is enforced by the CLI. Details (weights, security caps, threshold rules,
|
|
304
|
+
and deferred v2 items): [docs/scoring.md](docs/scoring.md).
|
|
284
305
|
|
|
285
|
-
|
|
286
|
-
No. It uses conservative filename and configuration heuristics. It never prints secret values and does not claim complete coverage.
|
|
306
|
+
---
|
|
287
307
|
|
|
288
|
-
|
|
289
|
-
Not in this release. `agentdoctor fix` is reserved for a future safe-fix mode.
|
|
308
|
+
## Beta limitations
|
|
290
309
|
|
|
291
|
-
|
|
292
|
-
Yes — prefer `--json`. `--min-score` is ignored until readiness scoring ships.
|
|
310
|
+
Honest limits of the current public beta:
|
|
293
311
|
|
|
294
|
-
|
|
312
|
+
| Limitation | Status |
|
|
313
|
+
| ----------------------------------- | --------------------------------------------------------------- |
|
|
314
|
+
| Terminal readiness line | Scores ship in JSON only; terminal does not print N/100 yet |
|
|
315
|
+
| GitHub Action score gates | Action remains `--ci --json` report-only (no `min-score` input) |
|
|
316
|
+
| Automatic fixes (`agentdoctor fix`) | Stub only — does not modify files |
|
|
317
|
+
| Secret-content scanning | Filename / config heuristics only |
|
|
318
|
+
| Detection style | Intentionally conservative; false security findings are avoided |
|
|
319
|
+
| Agent coverage | Cursor, Claude Code, Codex project configs |
|
|
295
320
|
|
|
296
|
-
|
|
297
|
-
npx @praneeth_54/agentdoctor explain <rule-id>
|
|
298
|
-
```
|
|
321
|
+
See [CHANGELOG.md](CHANGELOG.md) and [docs/release-notes-v0.2.0-beta.md](docs/release-notes-v0.2.0-beta.md).
|
|
299
322
|
|
|
300
323
|
---
|
|
301
324
|
|
|
302
|
-
##
|
|
325
|
+
## Architecture
|
|
303
326
|
|
|
304
|
-
|
|
327
|
+
```text
|
|
328
|
+
Discovery → Project detect → Agent adapters → Rule engine → Findings → Scores → Terminal / JSON
|
|
329
|
+
```
|
|
305
330
|
|
|
306
|
-
|
|
307
|
-
| ---------------------------------------------- | --------------------------- |
|
|
308
|
-
| [docs/architecture.md](docs/architecture.md) | Pipeline and package layout |
|
|
309
|
-
| [docs/rules.md](docs/rules.md) | Stable rule IDs |
|
|
310
|
-
| [docs/exit-codes.md](docs/exit-codes.md) | Process exit codes |
|
|
311
|
-
| [docs/compatibility.md](docs/compatibility.md) | Beta compatibility promises |
|
|
312
|
-
| [docs/development.md](docs/development.md) | Local development |
|
|
313
|
-
| [ROADMAP.md](ROADMAP.md) | Near- and medium-term plans |
|
|
314
|
-
| [CHANGELOG.md](CHANGELOG.md) | Release history |
|
|
331
|
+
Details: [docs/architecture.md](docs/architecture.md)
|
|
315
332
|
|
|
316
333
|
---
|
|
317
334
|
|
|
318
|
-
##
|
|
319
|
-
|
|
320
|
-
See [ROADMAP.md](ROADMAP.md). Highlights:
|
|
335
|
+
## Documentation
|
|
321
336
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
337
|
+
| Doc | Contents |
|
|
338
|
+
| ------------------------------------------------------------------ | ------------------------------- |
|
|
339
|
+
| [docs/README.md](docs/README.md) | Documentation index |
|
|
340
|
+
| [docs/architecture.md](docs/architecture.md) | Scan pipeline |
|
|
341
|
+
| [docs/rules.md](docs/rules.md) | Stable rule IDs |
|
|
342
|
+
| [docs/exit-codes.md](docs/exit-codes.md) | Process exit codes |
|
|
343
|
+
| [docs/scoring.md](docs/scoring.md) | Readiness scoring specification |
|
|
344
|
+
| [docs/compatibility.md](docs/compatibility.md) | Beta compatibility promises |
|
|
345
|
+
| [docs/development.md](docs/development.md) | Local development |
|
|
346
|
+
| [docs/github-launch-checklist.md](docs/github-launch-checklist.md) | GitHub About / topics / launch |
|
|
347
|
+
| [ROADMAP.md](ROADMAP.md) | Near- and medium-term plans |
|
|
348
|
+
| [CHANGELOG.md](CHANGELOG.md) | Release history |
|
|
326
349
|
|
|
327
350
|
---
|
|
328
351
|
|
|
@@ -331,19 +354,29 @@ See [ROADMAP.md](ROADMAP.md). Highlights:
|
|
|
331
354
|
Issues and pull requests are welcome.
|
|
332
355
|
|
|
333
356
|
1. Read [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
334
|
-
2.
|
|
335
|
-
3. Report security issues via [SECURITY.md](SECURITY.md)
|
|
357
|
+
2. Prefer [good first issues](docs/good-first-issues.md) ideas
|
|
358
|
+
3. Report security issues via [SECURITY.md](SECURITY.md) — never paste real secrets into issues
|
|
336
359
|
|
|
337
360
|
```bash
|
|
338
361
|
git clone https://github.com/pranee54/AgentDoctor.git
|
|
339
362
|
cd AgentDoctor
|
|
340
363
|
npm install
|
|
341
|
-
npm run
|
|
364
|
+
npm run verify
|
|
342
365
|
node dist/cli/index.js ./fixtures/clean-configured-project
|
|
343
366
|
```
|
|
344
367
|
|
|
345
368
|
---
|
|
346
369
|
|
|
370
|
+
## Next steps
|
|
371
|
+
|
|
372
|
+
- **Try it:** `npx @praneeth_54/agentdoctor`
|
|
373
|
+
- **Report a false positive / false negative:** use the issue templates (include version, rule ID, anonymized evidence — no secrets)
|
|
374
|
+
- **Propose a rule or adapter:** [feature request](.github/ISSUE_TEMPLATE/feature_request.md) / [rule proposal](.github/ISSUE_TEMPLATE/rule_proposal.md)
|
|
375
|
+
- **Contribute:** [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
376
|
+
- **Useful?** Star or watch the repository so you see updates
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
347
380
|
## License
|
|
348
381
|
|
|
349
382
|
[MIT](LICENSE) © AgentDoctor Contributors
|
|
@@ -15,7 +15,7 @@ export async function runDoctorCommand() {
|
|
|
15
15
|
lines.push(` ${symbolOk()} Core scan API available`);
|
|
16
16
|
lines.push("");
|
|
17
17
|
lines.push(colors.dim("Environment looks ready."));
|
|
18
|
-
lines.push(colors.dim("
|
|
18
|
+
lines.push(colors.dim("Automatic fixes are not available yet."));
|
|
19
19
|
lines.push("");
|
|
20
20
|
process.stdout.write(lines.join("\n"));
|
|
21
21
|
return EXIT_CODES.SUCCESS;
|
|
@@ -24,20 +24,12 @@ export async function runScanCommand(options) {
|
|
|
24
24
|
verbose: options.verbose === true,
|
|
25
25
|
}));
|
|
26
26
|
}
|
|
27
|
-
if (options.
|
|
28
|
-
if (
|
|
27
|
+
if (options.minScore !== undefined && result.scores !== null) {
|
|
28
|
+
if (result.scores.overall < options.minScore) {
|
|
29
29
|
if (!options.json) {
|
|
30
|
-
console.error(
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
const threshold = options.minScore ?? 0;
|
|
35
|
-
if (result.scores.overall < threshold) {
|
|
36
|
-
if (!options.json) {
|
|
37
|
-
console.error(`\nCI check failed: overall score ${result.scores.overall} is below --min-score ${threshold}`);
|
|
38
|
-
}
|
|
39
|
-
return EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
30
|
+
console.error(`\nCI check failed: overall score ${result.scores.overall} is below --min-score ${options.minScore}`);
|
|
40
31
|
}
|
|
32
|
+
return EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
41
33
|
}
|
|
42
34
|
}
|
|
43
35
|
return EXIT_CODES.SUCCESS;
|
package/dist/cli/program.js
CHANGED
|
@@ -29,9 +29,9 @@ export function createProgram() {
|
|
|
29
29
|
.version(PACKAGE_VERSION, "-V, --version", "Print AgentDoctor version")
|
|
30
30
|
.argument("[path]", "Repository path to scan (default: current directory)")
|
|
31
31
|
.option("--json", "Emit machine-readable JSON (no decorative output)", false)
|
|
32
|
-
.option("--ci", "CI mode (non-interactive; --min-score is
|
|
32
|
+
.option("--ci", "CI mode (non-interactive; report-only unless --min-score is set)", false)
|
|
33
33
|
.option("--verbose", "Show timing and extra diagnostics", false)
|
|
34
|
-
.option("--min-score <number>", "
|
|
34
|
+
.option("--min-score <number>", "Exit 1 when overall readiness score is below this (0-100)", parseMinScore)
|
|
35
35
|
.action(async (pathArg, options) => {
|
|
36
36
|
const minScore = readMinScore(options);
|
|
37
37
|
const code = await runScanCommand({
|
|
@@ -48,9 +48,9 @@ export function createProgram() {
|
|
|
48
48
|
.description("Scan a repository for AI coding agent configuration issues (default command)")
|
|
49
49
|
.argument("[path]", "Repository path to scan")
|
|
50
50
|
.option("--json", "Emit machine-readable JSON", false)
|
|
51
|
-
.option("--ci", "CI mode (--min-score
|
|
51
|
+
.option("--ci", "CI mode (non-interactive; report-only unless --min-score is set)", false)
|
|
52
52
|
.option("--verbose", "Show timing and extra diagnostics", false)
|
|
53
|
-
.option("--min-score <number>", "
|
|
53
|
+
.option("--min-score <number>", "Exit 1 when overall readiness score is below this (0-100)", parseMinScore)
|
|
54
54
|
.action(async (pathArg, options) => {
|
|
55
55
|
const minScore = readMinScore(options);
|
|
56
56
|
const code = await runScanCommand({
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.2.0-beta";
|
|
2
2
|
export declare const DEFAULT_MAX_FILE_SIZE_BYTES: number;
|
|
3
3
|
/** Directories skipped during normal discovery (unless a rule needs them later). */
|
|
4
4
|
export declare const DEFAULT_IGNORE_DIRECTORIES: Set<string>;
|
package/dist/constants.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = "0.
|
|
1
|
+
export const PACKAGE_VERSION = "0.2.0-beta";
|
|
2
2
|
export const DEFAULT_MAX_FILE_SIZE_BYTES = 2 * 1024 * 1024; // 2 MiB
|
|
3
3
|
/** Directories skipped during normal discovery (unless a rule needs them later). */
|
|
4
4
|
export const DEFAULT_IGNORE_DIRECTORIES = new Set([
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ScanOptions, ScanResult } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Public scan entry point.
|
|
4
|
-
* Pipeline: discovery → project detection → agent adapters → rule engine → findings.
|
|
5
|
-
* Readiness scoring is reserved for a later release (`scores` remains null for now).
|
|
4
|
+
* Pipeline: discovery → project detection → agent adapters → rule engine → findings → scores.
|
|
6
5
|
*/
|
|
7
6
|
export declare function scan(options?: ScanOptions): Promise<ScanResult>;
|
|
@@ -4,10 +4,10 @@ import { detectProject } from "../../detectors/project.js";
|
|
|
4
4
|
import { sanitizeTerminalText } from "../../security/redaction.js";
|
|
5
5
|
import { buildRuleContext } from "../rules/build-context.js";
|
|
6
6
|
import { runRules } from "../rules/run-rules.js";
|
|
7
|
+
import { computeReadinessScores } from "../scoring/compute-scores.js";
|
|
7
8
|
/**
|
|
8
9
|
* Public scan entry point.
|
|
9
|
-
* Pipeline: discovery → project detection → agent adapters → rule engine → findings.
|
|
10
|
-
* Readiness scoring is reserved for a later release (`scores` remains null for now).
|
|
10
|
+
* Pipeline: discovery → project detection → agent adapters → rule engine → findings → scores.
|
|
11
11
|
*/
|
|
12
12
|
export async function scan(options = {}) {
|
|
13
13
|
const totalStarted = performance.now();
|
|
@@ -51,21 +51,24 @@ export async function scan(options = {}) {
|
|
|
51
51
|
if (agentSecurityAnalysis === "limited") {
|
|
52
52
|
warnings.push("No supported coding-agent configuration detected; agent-specific security exposure checks are limited.");
|
|
53
53
|
}
|
|
54
|
+
const scoringStarted = performance.now();
|
|
55
|
+
const scores = computeReadinessScores(findings);
|
|
56
|
+
const scoringMs = Math.round(performance.now() - scoringStarted);
|
|
54
57
|
return {
|
|
55
58
|
version: PACKAGE_VERSION,
|
|
56
59
|
repository,
|
|
57
60
|
agents,
|
|
58
61
|
findings,
|
|
59
62
|
summary,
|
|
60
|
-
scores
|
|
61
|
-
scoringAvailable:
|
|
63
|
+
scores,
|
|
64
|
+
scoringAvailable: true,
|
|
62
65
|
agentSecurityAnalysis,
|
|
63
66
|
timing: {
|
|
64
67
|
discoveryMs: discovery.elapsedMs,
|
|
65
68
|
detectionMs,
|
|
66
69
|
agentsMs,
|
|
67
70
|
rulesMs,
|
|
68
|
-
scoringMs
|
|
71
|
+
scoringMs,
|
|
69
72
|
totalMs: Math.round(performance.now() - totalStarted),
|
|
70
73
|
},
|
|
71
74
|
diagnostics: {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const SEVERITY_BASE = {
|
|
2
|
+
critical: 35,
|
|
3
|
+
warning: 10,
|
|
4
|
+
info: 2,
|
|
5
|
+
};
|
|
6
|
+
const SEVERITY_SORT_RANK = {
|
|
7
|
+
critical: 0,
|
|
8
|
+
warning: 1,
|
|
9
|
+
info: 2,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* v1 readiness scores from post-dedupe findings.
|
|
13
|
+
* Spec: docs/scoring.md
|
|
14
|
+
*/
|
|
15
|
+
export function computeReadinessScores(findings) {
|
|
16
|
+
const overallRaw = 100 - sumDeductions(findings);
|
|
17
|
+
const overall = clampScore(applySecurityCaps(overallRaw, findings));
|
|
18
|
+
return {
|
|
19
|
+
overall,
|
|
20
|
+
categories: {
|
|
21
|
+
security: scoreSubset(findings.filter((f) => f.category === "security")),
|
|
22
|
+
context: scoreSubset(findings.filter((f) => f.category === "context")),
|
|
23
|
+
instructions: scoreSubset(findings.filter((f) => f.category === "instructions")),
|
|
24
|
+
mcp: scoreSubset(findings.filter((f) => f.category === "mcp")),
|
|
25
|
+
compatibility: scoreSubset(findings.filter((f) => f.category === "compatibility")),
|
|
26
|
+
performance: scoreSubset(findings.filter((f) => f.category === "performance")),
|
|
27
|
+
},
|
|
28
|
+
agents: {
|
|
29
|
+
cursor: scoreSubset(findings.filter((f) => f.affectedAgents.includes("cursor"))),
|
|
30
|
+
"claude-code": scoreSubset(findings.filter((f) => f.affectedAgents.includes("claude-code"))),
|
|
31
|
+
codex: scoreSubset(findings.filter((f) => f.affectedAgents.includes("codex"))),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function scoreSubset(findings) {
|
|
36
|
+
return clampScore(100 - sumDeductions(findings));
|
|
37
|
+
}
|
|
38
|
+
function sumDeductions(findings) {
|
|
39
|
+
const sorted = sortFindings(findings);
|
|
40
|
+
const severityIndex = {
|
|
41
|
+
critical: 0,
|
|
42
|
+
warning: 0,
|
|
43
|
+
info: 0,
|
|
44
|
+
};
|
|
45
|
+
let total = 0;
|
|
46
|
+
for (const finding of sorted) {
|
|
47
|
+
const occurrence = severityIndex[finding.severity];
|
|
48
|
+
severityIndex[finding.severity] = occurrence + 1;
|
|
49
|
+
total += SEVERITY_BASE[finding.severity] * diminishingMultiplier(occurrence);
|
|
50
|
+
}
|
|
51
|
+
return total;
|
|
52
|
+
}
|
|
53
|
+
function diminishingMultiplier(zeroBasedIndex) {
|
|
54
|
+
if (zeroBasedIndex === 0)
|
|
55
|
+
return 1;
|
|
56
|
+
if (zeroBasedIndex === 1)
|
|
57
|
+
return 0.7;
|
|
58
|
+
if (zeroBasedIndex === 2)
|
|
59
|
+
return 0.5;
|
|
60
|
+
return 0.35;
|
|
61
|
+
}
|
|
62
|
+
function sortFindings(findings) {
|
|
63
|
+
return [...findings].sort((a, b) => {
|
|
64
|
+
const sev = SEVERITY_SORT_RANK[a.severity] - SEVERITY_SORT_RANK[b.severity];
|
|
65
|
+
if (sev !== 0)
|
|
66
|
+
return sev;
|
|
67
|
+
const rule = a.ruleId.localeCompare(b.ruleId);
|
|
68
|
+
if (rule !== 0)
|
|
69
|
+
return rule;
|
|
70
|
+
const pathA = a.evidence?.path ?? "";
|
|
71
|
+
const pathB = b.evidence?.path ?? "";
|
|
72
|
+
const pathCmp = pathA.localeCompare(pathB);
|
|
73
|
+
if (pathCmp !== 0)
|
|
74
|
+
return pathCmp;
|
|
75
|
+
return a.id.localeCompare(b.id);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function applySecurityCaps(overall, findings) {
|
|
79
|
+
const securityCriticals = findings.filter((f) => f.category === "security" && f.severity === "critical").length;
|
|
80
|
+
if (securityCriticals >= 2) {
|
|
81
|
+
return Math.min(overall, 49);
|
|
82
|
+
}
|
|
83
|
+
if (securityCriticals >= 1) {
|
|
84
|
+
return Math.min(overall, 69);
|
|
85
|
+
}
|
|
86
|
+
return overall;
|
|
87
|
+
}
|
|
88
|
+
function clampScore(value) {
|
|
89
|
+
return Math.max(0, Math.min(100, Math.round(value)));
|
|
90
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Scores } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Production scans
|
|
5
|
-
*
|
|
3
|
+
* Historical filesScanned-based stub. Kept for unit tests that document the
|
|
4
|
+
* pre-v1 placeholder behavior. Production scans use computeReadinessScores
|
|
5
|
+
* (docs/scoring.md) — do not call this from scan().
|
|
6
6
|
*/
|
|
7
7
|
export declare function computePlaceholderScores(filesScanned: number): Scores;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Production scans
|
|
4
|
-
*
|
|
2
|
+
* Historical filesScanned-based stub. Kept for unit tests that document the
|
|
3
|
+
* pre-v1 placeholder behavior. Production scans use computeReadinessScores
|
|
4
|
+
* (docs/scoring.md) — do not call this from scan().
|
|
5
5
|
*/
|
|
6
6
|
export function computePlaceholderScores(filesScanned) {
|
|
7
7
|
const base = 72;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -106,11 +106,11 @@ export interface ScanResult {
|
|
|
106
106
|
findings: Finding[];
|
|
107
107
|
summary: FindingsSummary;
|
|
108
108
|
/**
|
|
109
|
-
* Readiness scores when
|
|
110
|
-
*
|
|
109
|
+
* Readiness scores (v1). Always populated when `scoringAvailable` is true.
|
|
110
|
+
* Remains typed as nullable for older consumers / transitional tooling.
|
|
111
111
|
*/
|
|
112
112
|
scores: Scores | null;
|
|
113
|
-
/**
|
|
113
|
+
/** True when the readiness scoring model is active and `scores` is populated. */
|
|
114
114
|
scoringAvailable: boolean;
|
|
115
115
|
/**
|
|
116
116
|
* `limited` when no supported coding agent is detected/configured.
|