@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.
Files changed (112) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/LICENSE +21 -0
  3. package/README.md +348 -0
  4. package/dist/agents/claude/adapter.d.ts +1 -0
  5. package/dist/agents/claude/adapter.js +1 -0
  6. package/dist/agents/claude/detector.d.ts +16 -0
  7. package/dist/agents/claude/detector.js +225 -0
  8. package/dist/agents/codex/adapter.d.ts +1 -0
  9. package/dist/agents/codex/adapter.js +1 -0
  10. package/dist/agents/codex/detector.d.ts +17 -0
  11. package/dist/agents/codex/detector.js +151 -0
  12. package/dist/agents/cursor/adapter.d.ts +1 -0
  13. package/dist/agents/cursor/adapter.js +1 -0
  14. package/dist/agents/cursor/detector.d.ts +17 -0
  15. package/dist/agents/cursor/detector.js +198 -0
  16. package/dist/agents/detect-agents.d.ts +17 -0
  17. package/dist/agents/detect-agents.js +23 -0
  18. package/dist/agents/inspect.d.ts +36 -0
  19. package/dist/agents/inspect.js +165 -0
  20. package/dist/agents/registry.d.ts +7 -0
  21. package/dist/agents/registry.js +11 -0
  22. package/dist/agents/types.d.ts +52 -0
  23. package/dist/agents/types.js +15 -0
  24. package/dist/cli/commands/doctor.d.ts +5 -0
  25. package/dist/cli/commands/doctor.js +22 -0
  26. package/dist/cli/commands/explain.d.ts +5 -0
  27. package/dist/cli/commands/explain.js +51 -0
  28. package/dist/cli/commands/fix.d.ts +8 -0
  29. package/dist/cli/commands/fix.js +19 -0
  30. package/dist/cli/commands/scan.d.ts +10 -0
  31. package/dist/cli/commands/scan.js +59 -0
  32. package/dist/cli/index.d.ts +2 -0
  33. package/dist/cli/index.js +3 -0
  34. package/dist/cli/program.d.ts +3 -0
  35. package/dist/cli/program.js +124 -0
  36. package/dist/constants.d.ts +5 -0
  37. package/dist/constants.js +38 -0
  38. package/dist/core/mcp/parse.d.ts +7 -0
  39. package/dist/core/mcp/parse.js +303 -0
  40. package/dist/core/mcp/types.d.ts +33 -0
  41. package/dist/core/mcp/types.js +1 -0
  42. package/dist/core/rules/build-context.d.ts +10 -0
  43. package/dist/core/rules/build-context.js +31 -0
  44. package/dist/core/rules/context/generated-directory.d.ts +2 -0
  45. package/dist/core/rules/context/generated-directory.js +89 -0
  46. package/dist/core/rules/context/large-instruction-file.d.ts +2 -0
  47. package/dist/core/rules/context/large-instruction-file.js +56 -0
  48. package/dist/core/rules/context/large-log-file.d.ts +2 -0
  49. package/dist/core/rules/context/large-log-file.js +45 -0
  50. package/dist/core/rules/dedupe.d.ts +13 -0
  51. package/dist/core/rules/dedupe.js +53 -0
  52. package/dist/core/rules/ignore.d.ts +23 -0
  53. package/dist/core/rules/ignore.js +97 -0
  54. package/dist/core/rules/instructions/duplicate-content.d.ts +2 -0
  55. package/dist/core/rules/instructions/duplicate-content.js +99 -0
  56. package/dist/core/rules/instructions/empty-instructions.d.ts +2 -0
  57. package/dist/core/rules/instructions/empty-instructions.js +53 -0
  58. package/dist/core/rules/instructions/missing-path-reference.d.ts +2 -0
  59. package/dist/core/rules/instructions/missing-path-reference.js +131 -0
  60. package/dist/core/rules/mcp/mcp-rules.d.ts +3 -0
  61. package/dist/core/rules/mcp/mcp-rules.js +83 -0
  62. package/dist/core/rules/registry.d.ts +6 -0
  63. package/dist/core/rules/registry.js +31 -0
  64. package/dist/core/rules/run-rules.d.ts +16 -0
  65. package/dist/core/rules/run-rules.js +36 -0
  66. package/dist/core/rules/security/claude-bypass-permissions.d.ts +7 -0
  67. package/dist/core/rules/security/claude-bypass-permissions.js +52 -0
  68. package/dist/core/rules/security/env-file-exposure.d.ts +2 -0
  69. package/dist/core/rules/security/env-file-exposure.js +87 -0
  70. package/dist/core/rules/security/mcp-broad-filesystem.d.ts +2 -0
  71. package/dist/core/rules/security/mcp-broad-filesystem.js +42 -0
  72. package/dist/core/rules/security/private-key-file.d.ts +2 -0
  73. package/dist/core/rules/security/private-key-file.js +60 -0
  74. package/dist/core/rules/text-cache.d.ts +19 -0
  75. package/dist/core/rules/text-cache.js +112 -0
  76. package/dist/core/rules/thresholds.d.ts +13 -0
  77. package/dist/core/rules/thresholds.js +13 -0
  78. package/dist/core/rules/types.d.ts +57 -0
  79. package/dist/core/rules/types.js +23 -0
  80. package/dist/core/scanner/scan.d.ts +7 -0
  81. package/dist/core/scanner/scan.js +70 -0
  82. package/dist/core/scoring/placeholder.d.ts +7 -0
  83. package/dist/core/scoring/placeholder.js +29 -0
  84. package/dist/detectors/framework.d.ts +17 -0
  85. package/dist/detectors/framework.js +148 -0
  86. package/dist/detectors/language.d.ts +14 -0
  87. package/dist/detectors/language.js +122 -0
  88. package/dist/detectors/monorepo.d.ts +13 -0
  89. package/dist/detectors/monorepo.js +44 -0
  90. package/dist/detectors/package-manager.d.ts +14 -0
  91. package/dist/detectors/package-manager.js +78 -0
  92. package/dist/detectors/project.d.ts +10 -0
  93. package/dist/detectors/project.js +60 -0
  94. package/dist/discovery/files.d.ts +15 -0
  95. package/dist/discovery/files.js +118 -0
  96. package/dist/index.d.ts +8 -0
  97. package/dist/index.js +7 -0
  98. package/dist/reporters/json/report.d.ts +5 -0
  99. package/dist/reporters/json/report.js +84 -0
  100. package/dist/reporters/terminal/report.d.ts +8 -0
  101. package/dist/reporters/terminal/report.js +147 -0
  102. package/dist/security/redaction.d.ts +9 -0
  103. package/dist/security/redaction.js +26 -0
  104. package/dist/types/index.d.ts +137 -0
  105. package/dist/types/index.js +6 -0
  106. package/dist/utils/colors.d.ts +14 -0
  107. package/dist/utils/colors.js +26 -0
  108. package/dist/utils/fs.d.ts +17 -0
  109. package/dist/utils/fs.js +63 -0
  110. package/dist/utils/path.d.ts +17 -0
  111. package/dist/utils/path.js +37 -0
  112. 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
+ [![CI](https://img.shields.io/github/actions/workflow/status/pranee54/AgentDoctor/ci.yml?branch=main&label=CI)](https://github.com/pranee54/AgentDoctor/actions)
19
+ [![npm](https://img.shields.io/npm/v/@praneeth_54/agentdoctor?label=npm)](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
20
+ [![Node](https://img.shields.io/node/v/@praneeth_54/agentdoctor)](https://nodejs.org)
21
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
22
+ [![Release](https://img.shields.io/badge/release-v0.1.0--beta-orange)](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";