@praneeth_54/agentdoctor 0.1.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 +58 -0
- package/LICENSE +21 -0
- package/README.md +348 -0
- package/dist/agents/claude/adapter.d.ts +1 -0
- package/dist/agents/claude/adapter.js +1 -0
- package/dist/agents/claude/detector.d.ts +16 -0
- package/dist/agents/claude/detector.js +225 -0
- package/dist/agents/codex/adapter.d.ts +1 -0
- package/dist/agents/codex/adapter.js +1 -0
- package/dist/agents/codex/detector.d.ts +17 -0
- package/dist/agents/codex/detector.js +151 -0
- package/dist/agents/cursor/adapter.d.ts +1 -0
- package/dist/agents/cursor/adapter.js +1 -0
- package/dist/agents/cursor/detector.d.ts +17 -0
- package/dist/agents/cursor/detector.js +198 -0
- package/dist/agents/detect-agents.d.ts +17 -0
- package/dist/agents/detect-agents.js +23 -0
- package/dist/agents/inspect.d.ts +36 -0
- package/dist/agents/inspect.js +165 -0
- package/dist/agents/registry.d.ts +7 -0
- package/dist/agents/registry.js +11 -0
- package/dist/agents/types.d.ts +52 -0
- package/dist/agents/types.js +15 -0
- package/dist/cli/commands/doctor.d.ts +5 -0
- package/dist/cli/commands/doctor.js +22 -0
- package/dist/cli/commands/explain.d.ts +5 -0
- package/dist/cli/commands/explain.js +51 -0
- package/dist/cli/commands/fix.d.ts +8 -0
- package/dist/cli/commands/fix.js +19 -0
- package/dist/cli/commands/scan.d.ts +10 -0
- package/dist/cli/commands/scan.js +59 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/program.d.ts +3 -0
- package/dist/cli/program.js +124 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +38 -0
- package/dist/core/mcp/parse.d.ts +7 -0
- package/dist/core/mcp/parse.js +303 -0
- package/dist/core/mcp/types.d.ts +33 -0
- package/dist/core/mcp/types.js +1 -0
- package/dist/core/rules/build-context.d.ts +10 -0
- package/dist/core/rules/build-context.js +31 -0
- package/dist/core/rules/context/generated-directory.d.ts +2 -0
- package/dist/core/rules/context/generated-directory.js +89 -0
- package/dist/core/rules/context/large-instruction-file.d.ts +2 -0
- package/dist/core/rules/context/large-instruction-file.js +56 -0
- package/dist/core/rules/context/large-log-file.d.ts +2 -0
- package/dist/core/rules/context/large-log-file.js +45 -0
- package/dist/core/rules/dedupe.d.ts +13 -0
- package/dist/core/rules/dedupe.js +53 -0
- package/dist/core/rules/ignore.d.ts +23 -0
- package/dist/core/rules/ignore.js +97 -0
- package/dist/core/rules/instructions/duplicate-content.d.ts +2 -0
- package/dist/core/rules/instructions/duplicate-content.js +99 -0
- package/dist/core/rules/instructions/empty-instructions.d.ts +2 -0
- package/dist/core/rules/instructions/empty-instructions.js +53 -0
- package/dist/core/rules/instructions/missing-path-reference.d.ts +2 -0
- package/dist/core/rules/instructions/missing-path-reference.js +131 -0
- package/dist/core/rules/mcp/mcp-rules.d.ts +3 -0
- package/dist/core/rules/mcp/mcp-rules.js +83 -0
- package/dist/core/rules/registry.d.ts +6 -0
- package/dist/core/rules/registry.js +31 -0
- package/dist/core/rules/run-rules.d.ts +16 -0
- package/dist/core/rules/run-rules.js +36 -0
- package/dist/core/rules/security/claude-bypass-permissions.d.ts +7 -0
- package/dist/core/rules/security/claude-bypass-permissions.js +52 -0
- package/dist/core/rules/security/env-file-exposure.d.ts +2 -0
- package/dist/core/rules/security/env-file-exposure.js +87 -0
- package/dist/core/rules/security/mcp-broad-filesystem.d.ts +2 -0
- package/dist/core/rules/security/mcp-broad-filesystem.js +42 -0
- package/dist/core/rules/security/private-key-file.d.ts +2 -0
- package/dist/core/rules/security/private-key-file.js +60 -0
- package/dist/core/rules/text-cache.d.ts +19 -0
- package/dist/core/rules/text-cache.js +112 -0
- package/dist/core/rules/thresholds.d.ts +13 -0
- package/dist/core/rules/thresholds.js +13 -0
- package/dist/core/rules/types.d.ts +57 -0
- package/dist/core/rules/types.js +23 -0
- package/dist/core/scanner/scan.d.ts +7 -0
- package/dist/core/scanner/scan.js +70 -0
- package/dist/core/scoring/placeholder.d.ts +7 -0
- package/dist/core/scoring/placeholder.js +29 -0
- package/dist/detectors/framework.d.ts +17 -0
- package/dist/detectors/framework.js +148 -0
- package/dist/detectors/language.d.ts +14 -0
- package/dist/detectors/language.js +122 -0
- package/dist/detectors/monorepo.d.ts +13 -0
- package/dist/detectors/monorepo.js +44 -0
- package/dist/detectors/package-manager.d.ts +14 -0
- package/dist/detectors/package-manager.js +78 -0
- package/dist/detectors/project.d.ts +10 -0
- package/dist/detectors/project.js +60 -0
- package/dist/discovery/files.d.ts +15 -0
- package/dist/discovery/files.js +118 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/reporters/json/report.d.ts +5 -0
- package/dist/reporters/json/report.js +84 -0
- package/dist/reporters/terminal/report.d.ts +8 -0
- package/dist/reporters/terminal/report.js +147 -0
- package/dist/security/redaction.d.ts +9 -0
- package/dist/security/redaction.js +26 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.js +6 -0
- package/dist/utils/colors.d.ts +14 -0
- package/dist/utils/colors.js +26 -0
- package/dist/utils/fs.d.ts +17 -0
- package/dist/utils/fs.js +63 -0
- package/dist/utils/path.d.ts +17 -0
- package/dist/utils/path.js +37 -0
- package/package.json +80 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Publish as scoped package `@praneeth_54/agentdoctor` (unscoped `agentdoctor` blocked by npm as too similar to `agent-doctor`)
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Track fake credential fixtures required by CI (were excluded by `.gitignore`)
|
|
17
|
+
- Align package and docs URLs with the public GitHub repository
|
|
18
|
+
- Release workflow selects notes by tag and attaches the npm tarball
|
|
19
|
+
- CLI help text matches shipped capabilities (`--min-score` no-op until scoring)
|
|
20
|
+
|
|
21
|
+
### Planned
|
|
22
|
+
|
|
23
|
+
- Deterministic readiness scoring
|
|
24
|
+
- Safe automatic fixes
|
|
25
|
+
- Packaged GitHub Action
|
|
26
|
+
|
|
27
|
+
## [0.1.0-beta] — 2026-07-29
|
|
28
|
+
|
|
29
|
+
First public beta.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- CLI: `scan` (default), `explain`, `doctor`, `fix` stub
|
|
34
|
+
- Flags: `--json`, `--ci`, `--verbose`, `--min-score`, `--version`, `--help`
|
|
35
|
+
- Repository detection (languages, frameworks, package managers, monorepos)
|
|
36
|
+
- Agent adapters for Cursor, Claude Code, and Codex
|
|
37
|
+
- Rule engine with security, context, instruction, and MCP findings
|
|
38
|
+
- Stable rule IDs and cross-agent finding deduplication
|
|
39
|
+
- Terminal and JSON reporters
|
|
40
|
+
- Programmatic `scan()` API
|
|
41
|
+
- Fixture-based unit and integration tests
|
|
42
|
+
|
|
43
|
+
### Security
|
|
44
|
+
|
|
45
|
+
- Conservative wording for exposure findings
|
|
46
|
+
- Secret values never printed
|
|
47
|
+
- Repository boundary enforcement for paths and symlinks
|
|
48
|
+
- Control-character sanitization in output
|
|
49
|
+
|
|
50
|
+
### Known limitations
|
|
51
|
+
|
|
52
|
+
- Readiness scores are not yet available (`scoringAvailable: false`)
|
|
53
|
+
- Automatic fixes are not applied
|
|
54
|
+
- Not a complete secret scanner
|
|
55
|
+
- Git “tracked secret” detection deferred
|
|
56
|
+
|
|
57
|
+
[Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v0.1.0-beta...HEAD
|
|
58
|
+
[0.1.0-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.0-beta
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AgentDoctor Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# AgentDoctor
|
|
2
|
+
|
|
3
|
+
**Lighthouse for AI coding agents.**
|
|
4
|
+
|
|
5
|
+
AgentDoctor audits a repository’s AI coding agent configuration — instructions, ignore rules, permissions, and MCP setup — using local static analysis. No API key. No upload by default.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @praneeth_54/agentdoctor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
| -------------- | ----------------------------------------------------------------------------------- |
|
|
13
|
+
| **What it is** | A CLI health check for agent config in your repo |
|
|
14
|
+
| **Why use it** | Catch misconfigurations, sensitive context exposure, and instruction problems early |
|
|
15
|
+
| **Install** | `npx @praneeth_54/agentdoctor` or `npm install -g @praneeth_54/agentdoctor` |
|
|
16
|
+
| **Requires** | Node.js 20+ |
|
|
17
|
+
|
|
18
|
+
[](https://github.com/pranee54/AgentDoctor/actions)
|
|
19
|
+
[](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
|
|
20
|
+
[](https://nodejs.org)
|
|
21
|
+
[](LICENSE)
|
|
22
|
+
[](CHANGELOG.md)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Demo
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
$ npx @praneeth_54/agentdoctor
|
|
30
|
+
|
|
31
|
+
AgentDoctor v0.1.0-beta
|
|
32
|
+
|
|
33
|
+
Repository
|
|
34
|
+
Framework: Next.js
|
|
35
|
+
Language: TypeScript
|
|
36
|
+
Package manager: npm
|
|
37
|
+
Files scanned: 46
|
|
38
|
+
|
|
39
|
+
AI Coding Agents
|
|
40
|
+
|
|
41
|
+
✓ Cursor configured
|
|
42
|
+
✓ Claude Code configured
|
|
43
|
+
✓ Codex configured
|
|
44
|
+
|
|
45
|
+
Findings
|
|
46
|
+
|
|
47
|
+
CRITICAL
|
|
48
|
+
|
|
49
|
+
✗ Sensitive environment file may enter agent context
|
|
50
|
+
.env.production
|
|
51
|
+
Affected: Claude Code, Codex
|
|
52
|
+
Fix: Exclude the file from agent context and keep it out of version control.
|
|
53
|
+
|
|
54
|
+
WARNING
|
|
55
|
+
|
|
56
|
+
! Large instruction file
|
|
57
|
+
CLAUDE.md — 38 KB
|
|
58
|
+
|
|
59
|
+
Summary
|
|
60
|
+
|
|
61
|
+
1 critical
|
|
62
|
+
1 warning
|
|
63
|
+
0 info
|
|
64
|
+
|
|
65
|
+
Scoring is not included in this beta
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Why AgentDoctor exists
|
|
71
|
+
|
|
72
|
+
Teams adopt AI coding agents quickly and accumulate project instructions, ignore rules, MCP servers, and permission settings. Those files are easy to misconfigure and hard to review consistently.
|
|
73
|
+
|
|
74
|
+
| Tooling analogy | Domain |
|
|
75
|
+
| --------------- | -------------------------------- |
|
|
76
|
+
| Lighthouse | Web pages |
|
|
77
|
+
| `npm audit` | Dependencies |
|
|
78
|
+
| ESLint | Source code |
|
|
79
|
+
| **AgentDoctor** | **AI coding agent environments** |
|
|
80
|
+
|
|
81
|
+
AgentDoctor analyzes configuration files. It does not run agents or edit your project.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Installation
|
|
86
|
+
|
|
87
|
+
### One-shot
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
npx @praneeth_54/agentdoctor
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Global (optional)
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install -g @praneeth_54/agentdoctor
|
|
97
|
+
agentdoctor
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The published package name is `@praneeth_54/agentdoctor` (npm blocks the unscoped name `agentdoctor` as too similar to an existing package). The CLI binary remains `agentdoctor`.
|
|
101
|
+
|
|
102
|
+
### Library
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install @praneeth_54/agentdoctor
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { scan } from "@praneeth_54/agentdoctor";
|
|
110
|
+
|
|
111
|
+
const result = await scan({ cwd: process.cwd() });
|
|
112
|
+
console.log(result.summary);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Quick start
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Scan the current directory
|
|
121
|
+
npx @praneeth_54/agentdoctor
|
|
122
|
+
|
|
123
|
+
# Scan a path
|
|
124
|
+
npx @praneeth_54/agentdoctor ./my-app
|
|
125
|
+
|
|
126
|
+
# Machine-readable output
|
|
127
|
+
npx @praneeth_54/agentdoctor --json
|
|
128
|
+
|
|
129
|
+
# Extra detail (paths, timing, finding rationale)
|
|
130
|
+
npx @praneeth_54/agentdoctor --verbose
|
|
131
|
+
|
|
132
|
+
# Explain a rule
|
|
133
|
+
npx @praneeth_54/agentdoctor explain security/env-file-exposure
|
|
134
|
+
|
|
135
|
+
# Environment health check
|
|
136
|
+
npx @praneeth_54/agentdoctor doctor
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Features
|
|
142
|
+
|
|
143
|
+
| Capability | Status |
|
|
144
|
+
| ------------------------------------------------------- | ------- |
|
|
145
|
+
| Zero-config first run | ✓ |
|
|
146
|
+
| Works offline / no API key | ✓ |
|
|
147
|
+
| Detects project-level agent configuration | ✓ |
|
|
148
|
+
| Deterministic security / context / instruction findings | ✓ |
|
|
149
|
+
| Inspects supported MCP project configuration | ✓ |
|
|
150
|
+
| Stable JSON output for CI | ✓ |
|
|
151
|
+
| `explain <rule>` documentation | ✓ |
|
|
152
|
+
| Readiness scoring | Planned |
|
|
153
|
+
| Safe automatic fixes | Planned |
|
|
154
|
+
| Official GitHub Action package | Planned |
|
|
155
|
+
|
|
156
|
+
### Feature comparison
|
|
157
|
+
|
|
158
|
+
| Concern | Manual review | Generic linters | AgentDoctor |
|
|
159
|
+
| -------------------------------------------- | ------------- | --------------- | ---------------- |
|
|
160
|
+
| Agent instruction files present and usable | Manual | — | ✓ |
|
|
161
|
+
| Empty or duplicated instructions | Manual | — | ✓ |
|
|
162
|
+
| Sensitive filenames vs agent access patterns | Manual | Partial | ✓ (conservative) |
|
|
163
|
+
| Broad MCP filesystem scopes | Manual | — | ✓ |
|
|
164
|
+
| Large always-on instruction files | Manual | — | ✓ |
|
|
165
|
+
| Uploads repository by default | — | Sometimes | **Never** |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## What it detects
|
|
170
|
+
|
|
171
|
+
### Supported agents
|
|
172
|
+
|
|
173
|
+
| Agent | Project-level detection |
|
|
174
|
+
| ----------- | ------------------------------------------ |
|
|
175
|
+
| Cursor | Rules, ignore files, MCP, `AGENTS.md` |
|
|
176
|
+
| Claude Code | Instructions, settings, rules, MCP |
|
|
177
|
+
| Codex | `AGENTS.md` / overrides, project `.codex/` |
|
|
178
|
+
|
|
179
|
+
### Finding categories
|
|
180
|
+
|
|
181
|
+
Security, context efficiency, instruction quality, and MCP configuration. Full catalog: [docs/rules.md](docs/rules.md).
|
|
182
|
+
|
|
183
|
+
Adapters are pluggable — additional agents can be registered without rewriting the scanner.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Architecture
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
┌─────────────┐
|
|
191
|
+
│ Discovery │ bounded filesystem walk
|
|
192
|
+
└──────┬──────┘
|
|
193
|
+
▼
|
|
194
|
+
┌─────────────────┐
|
|
195
|
+
│ Project detect │ language / framework / package manager
|
|
196
|
+
└──────┬──────────┘
|
|
197
|
+
▼
|
|
198
|
+
┌─────────────────┐
|
|
199
|
+
│ Agent adapters │ Cursor · Claude Code · Codex
|
|
200
|
+
└──────┬──────────┘
|
|
201
|
+
▼
|
|
202
|
+
┌─────────────────┐
|
|
203
|
+
│ Rule engine │ security · context · instructions · MCP
|
|
204
|
+
└──────┬──────────┘
|
|
205
|
+
▼
|
|
206
|
+
┌─────────────────┐
|
|
207
|
+
│ Findings │ deterministic IDs · deduped · fixability metadata
|
|
208
|
+
└──────┬──────────┘
|
|
209
|
+
▼
|
|
210
|
+
┌─────────────────┐
|
|
211
|
+
│ Reporters │ terminal · JSON
|
|
212
|
+
└─────────────────┘
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Details: [docs/architecture.md](docs/architecture.md)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## JSON output
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
npx @praneeth_54/agentdoctor --json
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"version": "0.1.0-beta",
|
|
228
|
+
"repository": {
|
|
229
|
+
"primaryFramework": "nextjs",
|
|
230
|
+
"primaryLanguage": "typescript",
|
|
231
|
+
"filesScanned": 46
|
|
232
|
+
},
|
|
233
|
+
"agents": [
|
|
234
|
+
{
|
|
235
|
+
"id": "cursor",
|
|
236
|
+
"detected": true,
|
|
237
|
+
"configured": true,
|
|
238
|
+
"status": "configured"
|
|
239
|
+
}
|
|
240
|
+
],
|
|
241
|
+
"findings": [
|
|
242
|
+
{
|
|
243
|
+
"id": "security/env-file-exposure:.env.production",
|
|
244
|
+
"ruleId": "security/env-file-exposure",
|
|
245
|
+
"category": "security",
|
|
246
|
+
"severity": "critical",
|
|
247
|
+
"title": "Sensitive environment file may enter agent context",
|
|
248
|
+
"affectedAgents": ["claude-code", "codex"],
|
|
249
|
+
"fixability": "review"
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
"summary": { "critical": 1, "warning": 0, "info": 0, "total": 1 },
|
|
253
|
+
"scoringAvailable": false,
|
|
254
|
+
"scores": null
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Exit codes: [docs/exit-codes.md](docs/exit-codes.md)
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Privacy
|
|
263
|
+
|
|
264
|
+
**Your code stays on your machine.**
|
|
265
|
+
|
|
266
|
+
Normal scans do not:
|
|
267
|
+
|
|
268
|
+
- send source code to external services
|
|
269
|
+
- require authentication
|
|
270
|
+
- call an LLM
|
|
271
|
+
- execute project code
|
|
272
|
+
- start MCP servers
|
|
273
|
+
- enable telemetry by default
|
|
274
|
+
|
|
275
|
+
If anonymous telemetry is ever introduced, it will be opt-in.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## FAQ
|
|
280
|
+
|
|
281
|
+
**Does AgentDoctor require an API key?**
|
|
282
|
+
No. Core scanning is local and deterministic.
|
|
283
|
+
|
|
284
|
+
**Is this a secret scanner?**
|
|
285
|
+
No. It uses conservative filename and configuration heuristics. It never prints secret values and does not claim complete coverage.
|
|
286
|
+
|
|
287
|
+
**Will it modify my repository?**
|
|
288
|
+
Not in this release. `agentdoctor fix` is reserved for a future safe-fix mode.
|
|
289
|
+
|
|
290
|
+
**Can I use it in CI?**
|
|
291
|
+
Yes — prefer `--json`. `--min-score` is ignored until readiness scoring ships.
|
|
292
|
+
|
|
293
|
+
**How do I understand a finding?**
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
npx @praneeth_54/agentdoctor explain <rule-id>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Documentation
|
|
302
|
+
|
|
303
|
+
Start at [docs/README.md](docs/README.md).
|
|
304
|
+
|
|
305
|
+
| Doc | Contents |
|
|
306
|
+
| ---------------------------------------------- | --------------------------- |
|
|
307
|
+
| [docs/architecture.md](docs/architecture.md) | Pipeline and package layout |
|
|
308
|
+
| [docs/rules.md](docs/rules.md) | Stable rule IDs |
|
|
309
|
+
| [docs/exit-codes.md](docs/exit-codes.md) | Process exit codes |
|
|
310
|
+
| [docs/compatibility.md](docs/compatibility.md) | Beta compatibility promises |
|
|
311
|
+
| [docs/development.md](docs/development.md) | Local development |
|
|
312
|
+
| [ROADMAP.md](ROADMAP.md) | Near- and medium-term plans |
|
|
313
|
+
| [CHANGELOG.md](CHANGELOG.md) | Release history |
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Roadmap
|
|
318
|
+
|
|
319
|
+
See [ROADMAP.md](ROADMAP.md). Highlights:
|
|
320
|
+
|
|
321
|
+
1. Deterministic readiness scoring
|
|
322
|
+
2. Conservative auto-fix for safe findings
|
|
323
|
+
3. Packaged GitHub Action
|
|
324
|
+
4. Additional agent adapters
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Contributing
|
|
329
|
+
|
|
330
|
+
Issues and pull requests are welcome.
|
|
331
|
+
|
|
332
|
+
1. Read [CONTRIBUTING.md](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
333
|
+
2. Set up locally with [docs/development.md](docs/development.md)
|
|
334
|
+
3. Report security issues via [SECURITY.md](SECURITY.md)
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
git clone https://github.com/pranee54/AgentDoctor.git
|
|
338
|
+
cd AgentDoctor
|
|
339
|
+
npm install
|
|
340
|
+
npm run typecheck && npm run lint && npm test && npm run build
|
|
341
|
+
node dist/cli/index.js ./fixtures/clean-configured-project
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## License
|
|
347
|
+
|
|
348
|
+
[MIT](LICENSE) © AgentDoctor Contributors
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { claudeAdapter, detectClaudeCode } from "./detector.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { claudeAdapter, detectClaudeCode } from "./detector.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentAdapter, AgentDetectionContext, AgentDetectionResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code project configuration detection.
|
|
4
|
+
*
|
|
5
|
+
* Official sources (code.claude.com docs):
|
|
6
|
+
* - Project instructions: `./CLAUDE.md` or `./.claude/CLAUDE.md`
|
|
7
|
+
* - Local (gitignored) instructions: `./CLAUDE.local.md`
|
|
8
|
+
* - Nested `CLAUDE.md` / `CLAUDE.local.md` in subdirectories (on-demand load)
|
|
9
|
+
* - Modular rules: .claude/rules/ markdown files (recursive)
|
|
10
|
+
* - Project settings: .claude/settings.json, .claude/settings.local.json
|
|
11
|
+
*
|
|
12
|
+
* We do NOT inspect ~/.claude or managed org policies — repository only.
|
|
13
|
+
* Claude Code does not read AGENTS.md directly (docs recommend importing via CLAUDE.md).
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectClaudeCode(context: AgentDetectionContext): Promise<AgentDetectionResult>;
|
|
16
|
+
export declare const claudeAdapter: AgentAdapter;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { AGENT_DISPLAY_NAMES } from "../../constants.js";
|
|
2
|
+
import { deriveStatus, inspectRepoFile, pathExistsInsideRoot, toAgentConfigFile, tryParseJson, } from "../inspect.js";
|
|
3
|
+
import { basenameOf, isRootLevel } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Claude Code project configuration detection.
|
|
6
|
+
*
|
|
7
|
+
* Official sources (code.claude.com docs):
|
|
8
|
+
* - Project instructions: `./CLAUDE.md` or `./.claude/CLAUDE.md`
|
|
9
|
+
* - Local (gitignored) instructions: `./CLAUDE.local.md`
|
|
10
|
+
* - Nested `CLAUDE.md` / `CLAUDE.local.md` in subdirectories (on-demand load)
|
|
11
|
+
* - Modular rules: .claude/rules/ markdown files (recursive)
|
|
12
|
+
* - Project settings: .claude/settings.json, .claude/settings.local.json
|
|
13
|
+
*
|
|
14
|
+
* We do NOT inspect ~/.claude or managed org policies — repository only.
|
|
15
|
+
* Claude Code does not read AGENTS.md directly (docs recommend importing via CLAUDE.md).
|
|
16
|
+
*/
|
|
17
|
+
export async function detectClaudeCode(context) {
|
|
18
|
+
const { root, discovery, maxFileSizeBytes } = context;
|
|
19
|
+
const configFiles = [];
|
|
20
|
+
const diagnostics = [];
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
const metadata = {
|
|
23
|
+
claudeMdCount: 0,
|
|
24
|
+
claudeLocalCount: 0,
|
|
25
|
+
rulesCount: 0,
|
|
26
|
+
hasClaudeDirectory: false,
|
|
27
|
+
hasSettings: false,
|
|
28
|
+
hasLocalSettings: false,
|
|
29
|
+
};
|
|
30
|
+
const hasClaudeDir = await pathExistsInsideRoot(root, ".claude");
|
|
31
|
+
metadata.hasClaudeDirectory = hasClaudeDir;
|
|
32
|
+
async function addMarkdownInstruction(relativePath, kind) {
|
|
33
|
+
if (seen.has(relativePath)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
seen.add(relativePath);
|
|
37
|
+
const inspected = await inspectRepoFile(root, relativePath, maxFileSizeBytes);
|
|
38
|
+
const scope = relativePath === "CLAUDE.md" ||
|
|
39
|
+
relativePath === ".claude/CLAUDE.md" ||
|
|
40
|
+
relativePath === "CLAUDE.local.md"
|
|
41
|
+
? "root"
|
|
42
|
+
: isRootLevel(relativePath)
|
|
43
|
+
? "root"
|
|
44
|
+
: "nested";
|
|
45
|
+
configFiles.push(toAgentConfigFile(inspected, kind, {
|
|
46
|
+
legacy: false,
|
|
47
|
+
scope,
|
|
48
|
+
}));
|
|
49
|
+
if (kind === "claude-md") {
|
|
50
|
+
metadata.claudeMdCount = Number(metadata.claudeMdCount) + 1;
|
|
51
|
+
}
|
|
52
|
+
else if (kind === "claude-local-md") {
|
|
53
|
+
metadata.claudeLocalCount = Number(metadata.claudeLocalCount) + 1;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
metadata.rulesCount = Number(metadata.rulesCount) + 1;
|
|
57
|
+
}
|
|
58
|
+
if (!inspected.exists) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!inspected.readable && inspected.error) {
|
|
62
|
+
diagnostics.push({
|
|
63
|
+
code: "claude/unreadable-file",
|
|
64
|
+
severity: "warning",
|
|
65
|
+
message: `Could not read Claude Code file: ${inspected.error}`,
|
|
66
|
+
file: relativePath,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else if (inspected.empty) {
|
|
70
|
+
diagnostics.push({
|
|
71
|
+
code: "claude/empty-instruction",
|
|
72
|
+
severity: "info",
|
|
73
|
+
message: "Claude Code instruction file is empty",
|
|
74
|
+
file: relativePath,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function addSettingsFile(relativePath, kind) {
|
|
79
|
+
if (seen.has(relativePath)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
seen.add(relativePath);
|
|
83
|
+
const inspected = await inspectRepoFile(root, relativePath, maxFileSizeBytes);
|
|
84
|
+
let parseError;
|
|
85
|
+
if (inspected.readable && inspected.text !== null && !inspected.empty) {
|
|
86
|
+
const parsed = tryParseJson(inspected.text);
|
|
87
|
+
if (!parsed.ok) {
|
|
88
|
+
parseError = parsed.error;
|
|
89
|
+
diagnostics.push({
|
|
90
|
+
code: "claude/malformed-settings",
|
|
91
|
+
severity: "warning",
|
|
92
|
+
message: `${relativePath} could not be parsed: ${parsed.error}`,
|
|
93
|
+
file: relativePath,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Count setting keys only — do not surface setting values.
|
|
97
|
+
if (parsed.ok && parsed.data && typeof parsed.data === "object") {
|
|
98
|
+
metadata[`${kind}Keys`] = Object.keys(parsed.data).length;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else if (inspected.exists && inspected.empty) {
|
|
102
|
+
diagnostics.push({
|
|
103
|
+
code: "claude/empty-settings",
|
|
104
|
+
severity: "info",
|
|
105
|
+
message: `${relativePath} is empty`,
|
|
106
|
+
file: relativePath,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else if (inspected.exists && !inspected.readable && inspected.error) {
|
|
110
|
+
diagnostics.push({
|
|
111
|
+
code: "claude/unreadable-settings",
|
|
112
|
+
severity: "warning",
|
|
113
|
+
message: `Could not read ${relativePath}: ${inspected.error}`,
|
|
114
|
+
file: relativePath,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
configFiles.push(toAgentConfigFile(inspected, kind, {
|
|
118
|
+
legacy: false,
|
|
119
|
+
scope: "root",
|
|
120
|
+
...(parseError !== undefined ? { parseError } : {}),
|
|
121
|
+
}));
|
|
122
|
+
if (kind === "claude-settings") {
|
|
123
|
+
metadata.hasSettings = true;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
metadata.hasLocalSettings = true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Targeted root/project paths (may be empty and missing from discovery)
|
|
130
|
+
const targeted = [
|
|
131
|
+
"CLAUDE.md",
|
|
132
|
+
".claude/CLAUDE.md",
|
|
133
|
+
"CLAUDE.local.md",
|
|
134
|
+
".claude/settings.json",
|
|
135
|
+
".claude/settings.local.json",
|
|
136
|
+
];
|
|
137
|
+
for (const relative of targeted) {
|
|
138
|
+
if (await pathExistsInsideRoot(root, relative)) {
|
|
139
|
+
if (relative.endsWith("settings.json") || relative.endsWith("settings.local.json")) {
|
|
140
|
+
await addSettingsFile(relative, relative.endsWith("settings.local.json") ? "claude-settings-local" : "claude-settings");
|
|
141
|
+
}
|
|
142
|
+
else if (relative.endsWith("CLAUDE.local.md")) {
|
|
143
|
+
await addMarkdownInstruction(relative, "claude-local-md");
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
await addMarkdownInstruction(relative, "claude-md");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Nested CLAUDE.md / CLAUDE.local.md and .claude/rules from discovery
|
|
151
|
+
for (const file of discovery.files) {
|
|
152
|
+
const relative = file.relativePath;
|
|
153
|
+
const base = basenameOf(relative);
|
|
154
|
+
if (base === "CLAUDE.md") {
|
|
155
|
+
await addMarkdownInstruction(relative, "claude-md");
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (base === "CLAUDE.local.md") {
|
|
159
|
+
await addMarkdownInstruction(relative, "claude-local-md");
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (relative.includes(".claude/rules/") && base.endsWith(".md")) {
|
|
163
|
+
await addMarkdownInstruction(relative, "claude-rule-md");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const usableInstruction = configFiles.some((f) => f.readable &&
|
|
167
|
+
!f.empty &&
|
|
168
|
+
(f.kind === "claude-md" ||
|
|
169
|
+
f.kind === "claude-local-md" ||
|
|
170
|
+
f.kind === "claude-rule-md" ||
|
|
171
|
+
((f.kind === "claude-settings" || f.kind === "claude-settings-local") &&
|
|
172
|
+
f.parseError === undefined)));
|
|
173
|
+
const detected = hasClaudeDir ||
|
|
174
|
+
Number(metadata.claudeMdCount) > 0 ||
|
|
175
|
+
Number(metadata.claudeLocalCount) > 0 ||
|
|
176
|
+
Number(metadata.rulesCount) > 0 ||
|
|
177
|
+
Boolean(metadata.hasSettings) ||
|
|
178
|
+
Boolean(metadata.hasLocalSettings);
|
|
179
|
+
const configured = usableInstruction;
|
|
180
|
+
const hasErrors = diagnostics.some((d) => d.severity === "error");
|
|
181
|
+
// Malformed settings alone without instructions → misconfigured if detected
|
|
182
|
+
const hasParseProblems = configFiles.some((f) => f.parseError !== undefined);
|
|
183
|
+
const status = deriveStatus({
|
|
184
|
+
detected,
|
|
185
|
+
configured,
|
|
186
|
+
hasErrors: hasErrors || (hasParseProblems && !configured),
|
|
187
|
+
});
|
|
188
|
+
const parts = [];
|
|
189
|
+
if (Number(metadata.claudeMdCount) > 0) {
|
|
190
|
+
parts.push("CLAUDE.md");
|
|
191
|
+
}
|
|
192
|
+
if (Number(metadata.rulesCount) > 0) {
|
|
193
|
+
parts.push(`${metadata.rulesCount} rule${Number(metadata.rulesCount) === 1 ? "" : "s"}`);
|
|
194
|
+
}
|
|
195
|
+
if (metadata.hasSettings || metadata.hasLocalSettings) {
|
|
196
|
+
parts.push("settings");
|
|
197
|
+
}
|
|
198
|
+
let summary;
|
|
199
|
+
if (!detected) {
|
|
200
|
+
summary = "not configured";
|
|
201
|
+
}
|
|
202
|
+
else if (configured) {
|
|
203
|
+
summary = parts.length > 0 ? parts.join(", ") : "configured";
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
summary = "detected but not configured";
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
id: "claude-code",
|
|
210
|
+
displayName: AGENT_DISPLAY_NAMES["claude-code"],
|
|
211
|
+
detected,
|
|
212
|
+
configured,
|
|
213
|
+
status,
|
|
214
|
+
summary,
|
|
215
|
+
configFiles,
|
|
216
|
+
configPaths: configFiles.map((f) => f.relativePath),
|
|
217
|
+
diagnostics,
|
|
218
|
+
metadata,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
export const claudeAdapter = {
|
|
222
|
+
id: "claude-code",
|
|
223
|
+
displayName: AGENT_DISPLAY_NAMES["claude-code"],
|
|
224
|
+
detect: detectClaudeCode,
|
|
225
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { codexAdapter, detectCodex } from "./detector.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { codexAdapter, detectCodex } from "./detector.js";
|