@praneeth_54/agentdoctor 0.3.0-beta → 1.1.0

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 (267) hide show
  1. package/CHANGELOG.md +105 -1
  2. package/README.md +64 -31
  3. package/dist/agents/inspect.js +58 -51
  4. package/dist/cli/commands/brain-mcp.d.ts +9 -0
  5. package/dist/cli/commands/brain-mcp.js +38 -0
  6. package/dist/cli/commands/explain.js +1 -1
  7. package/dist/cli/commands/fix.js +22 -6
  8. package/dist/cli/commands/scan.d.ts +5 -0
  9. package/dist/cli/commands/scan.js +25 -6
  10. package/dist/cli/commands/verify.d.ts +6 -0
  11. package/dist/cli/commands/verify.js +25 -11
  12. package/dist/cli/program.js +61 -7
  13. package/dist/constants.d.ts +1 -1
  14. package/dist/constants.js +1 -1
  15. package/dist/core/fix/apply.d.ts +5 -1
  16. package/dist/core/fix/apply.js +34 -14
  17. package/dist/core/fix/plan.d.ts +1 -1
  18. package/dist/core/fix/plan.js +110 -3
  19. package/dist/core/fix/render.d.ts +2 -0
  20. package/dist/core/fix/render.js +57 -9
  21. package/dist/core/fix/run.js +5 -1
  22. package/dist/core/fix/types.d.ts +1 -1
  23. package/dist/core/fix/types.js +5 -1
  24. package/dist/core/fix/writers/claude-settings.d.ts +16 -0
  25. package/dist/core/fix/writers/claude-settings.js +100 -0
  26. package/dist/core/fix/writers/codex-config.d.ts +22 -0
  27. package/dist/core/fix/writers/codex-config.js +183 -0
  28. package/dist/core/fix/writers/cursorignore.js +2 -8
  29. package/dist/core/path-resolution/index.d.ts +5 -0
  30. package/dist/core/path-resolution/index.js +5 -0
  31. package/dist/core/path-resolution/prepare.d.ts +33 -0
  32. package/dist/core/path-resolution/prepare.js +98 -0
  33. package/dist/core/policy/evaluate.d.ts +44 -0
  34. package/dist/core/policy/evaluate.js +120 -0
  35. package/dist/core/rules/claude-deny.d.ts +8 -0
  36. package/dist/core/rules/claude-deny.js +39 -0
  37. package/dist/core/rules/codex-deny.d.ts +5 -0
  38. package/dist/core/rules/codex-deny.js +42 -0
  39. package/dist/core/rules/context/generated-directory.js +43 -9
  40. package/dist/core/rules/context/large-log-file.js +27 -10
  41. package/dist/core/rules/ignore.js +2 -5
  42. package/dist/core/rules/instructions/missing-path-reference.d.ts +5 -1
  43. package/dist/core/rules/instructions/missing-path-reference.js +24 -6
  44. package/dist/core/rules/path-kind.d.ts +15 -2
  45. package/dist/core/rules/path-kind.js +113 -10
  46. package/dist/core/rules/security/env-file-exposure.js +9 -24
  47. package/dist/core/rules/text-cache.js +46 -40
  48. package/dist/core/understanding/architecture/index.d.ts +4 -0
  49. package/dist/core/understanding/architecture/index.js +3 -0
  50. package/dist/core/understanding/architecture/infer.d.ts +6 -0
  51. package/dist/core/understanding/architecture/infer.js +39 -0
  52. package/dist/core/understanding/architecture/models.d.ts +23 -0
  53. package/dist/core/understanding/architecture/models.js +127 -0
  54. package/dist/core/understanding/architecture/patterns/distribution.d.ts +2 -0
  55. package/dist/core/understanding/architecture/patterns/distribution.js +115 -0
  56. package/dist/core/understanding/architecture/patterns/index.d.ts +2 -0
  57. package/dist/core/understanding/architecture/patterns/index.js +8 -0
  58. package/dist/core/understanding/architecture/patterns/layered.d.ts +2 -0
  59. package/dist/core/understanding/architecture/patterns/layered.js +279 -0
  60. package/dist/core/understanding/architecture/patterns/structural.d.ts +2 -0
  61. package/dist/core/understanding/architecture/patterns/structural.js +197 -0
  62. package/dist/core/understanding/architecture/rules.d.ts +4 -0
  63. package/dist/core/understanding/architecture/rules.js +6 -0
  64. package/dist/core/understanding/architecture/types.d.ts +52 -0
  65. package/dist/core/understanding/architecture/types.js +1 -0
  66. package/dist/core/understanding/brain/build.d.ts +13 -0
  67. package/dist/core/understanding/brain/build.js +158 -0
  68. package/dist/core/understanding/brain/claims/index.d.ts +3 -0
  69. package/dist/core/understanding/brain/claims/index.js +2 -0
  70. package/dist/core/understanding/brain/claims/lifecycle.d.ts +16 -0
  71. package/dist/core/understanding/brain/claims/lifecycle.js +78 -0
  72. package/dist/core/understanding/brain/claims/types.d.ts +32 -0
  73. package/dist/core/understanding/brain/claims/types.js +25 -0
  74. package/dist/core/understanding/brain/components/index.d.ts +17 -0
  75. package/dist/core/understanding/brain/components/index.js +97 -0
  76. package/dist/core/understanding/brain/components/types.d.ts +16 -0
  77. package/dist/core/understanding/brain/components/types.js +8 -0
  78. package/dist/core/understanding/brain/confidence.d.ts +19 -0
  79. package/dist/core/understanding/brain/confidence.js +39 -0
  80. package/dist/core/understanding/brain/contract.d.ts +17 -0
  81. package/dist/core/understanding/brain/contract.js +100 -0
  82. package/dist/core/understanding/brain/contradictions/index.d.ts +12 -0
  83. package/dist/core/understanding/brain/contradictions/index.js +57 -0
  84. package/dist/core/understanding/brain/contradictions/types.d.ts +12 -0
  85. package/dist/core/understanding/brain/contradictions/types.js +8 -0
  86. package/dist/core/understanding/brain/delta.d.ts +25 -0
  87. package/dist/core/understanding/brain/delta.js +116 -0
  88. package/dist/core/understanding/brain/evidence/index.d.ts +3 -0
  89. package/dist/core/understanding/brain/evidence/index.js +2 -0
  90. package/dist/core/understanding/brain/evidence/redact.d.ts +4 -0
  91. package/dist/core/understanding/brain/evidence/redact.js +36 -0
  92. package/dist/core/understanding/brain/evidence/types.d.ts +34 -0
  93. package/dist/core/understanding/brain/evidence/types.js +35 -0
  94. package/dist/core/understanding/brain/explain.d.ts +17 -0
  95. package/dist/core/understanding/brain/explain.js +33 -0
  96. package/dist/core/understanding/brain/index.d.ts +28 -0
  97. package/dist/core/understanding/brain/index.js +16 -0
  98. package/dist/core/understanding/brain/migrate.d.ts +21 -0
  99. package/dist/core/understanding/brain/migrate.js +47 -0
  100. package/dist/core/understanding/brain/query.d.ts +60 -0
  101. package/dist/core/understanding/brain/query.js +92 -0
  102. package/dist/core/understanding/brain/security.d.ts +3 -0
  103. package/dist/core/understanding/brain/security.js +43 -0
  104. package/dist/core/understanding/brain/storage/index.d.ts +2 -0
  105. package/dist/core/understanding/brain/storage/index.js +1 -0
  106. package/dist/core/understanding/brain/storage/store.d.ts +53 -0
  107. package/dist/core/understanding/brain/storage/store.js +305 -0
  108. package/dist/core/understanding/brain/trace.d.ts +24 -0
  109. package/dist/core/understanding/brain/trace.js +207 -0
  110. package/dist/core/understanding/brain/types.d.ts +32 -0
  111. package/dist/core/understanding/brain/types.js +8 -0
  112. package/dist/core/understanding/brain/version.d.ts +13 -0
  113. package/dist/core/understanding/brain/version.js +7 -0
  114. package/dist/core/understanding/delta/compare.d.ts +26 -0
  115. package/dist/core/understanding/delta/compare.js +74 -0
  116. package/dist/core/understanding/delta/index.d.ts +2 -0
  117. package/dist/core/understanding/delta/index.js +1 -0
  118. package/dist/core/understanding/dependencies/discover.d.ts +7 -0
  119. package/dist/core/understanding/dependencies/discover.js +550 -0
  120. package/dist/core/understanding/dependencies/extract.d.ts +10 -0
  121. package/dist/core/understanding/dependencies/extract.js +189 -0
  122. package/dist/core/understanding/dependencies/index.d.ts +4 -0
  123. package/dist/core/understanding/dependencies/index.js +3 -0
  124. package/dist/core/understanding/dependencies/models.d.ts +12 -0
  125. package/dist/core/understanding/dependencies/models.js +125 -0
  126. package/dist/core/understanding/dependencies/types.d.ts +27 -0
  127. package/dist/core/understanding/dependencies/types.js +1 -0
  128. package/dist/core/understanding/domain/discover.d.ts +14 -0
  129. package/dist/core/understanding/domain/discover.js +90 -0
  130. package/dist/core/understanding/domain/index.d.ts +2 -0
  131. package/dist/core/understanding/domain/index.js +1 -0
  132. package/dist/core/understanding/entrypoints/discover.d.ts +6 -0
  133. package/dist/core/understanding/entrypoints/discover.js +62 -0
  134. package/dist/core/understanding/entrypoints/extract.d.ts +19 -0
  135. package/dist/core/understanding/entrypoints/extract.js +43 -0
  136. package/dist/core/understanding/entrypoints/index.d.ts +4 -0
  137. package/dist/core/understanding/entrypoints/index.js +3 -0
  138. package/dist/core/understanding/entrypoints/models.d.ts +26 -0
  139. package/dist/core/understanding/entrypoints/models.js +216 -0
  140. package/dist/core/understanding/entrypoints/types.d.ts +20 -0
  141. package/dist/core/understanding/entrypoints/types.js +1 -0
  142. package/dist/core/understanding/index.d.ts +32 -0
  143. package/dist/core/understanding/index.js +18 -0
  144. package/dist/core/understanding/mind/build.d.ts +16 -0
  145. package/dist/core/understanding/mind/build.js +134 -0
  146. package/dist/core/understanding/mind/index.d.ts +6 -0
  147. package/dist/core/understanding/mind/index.js +3 -0
  148. package/dist/core/understanding/mind/query.d.ts +33 -0
  149. package/dist/core/understanding/mind/query.js +39 -0
  150. package/dist/core/understanding/mind/types.d.ts +24 -0
  151. package/dist/core/understanding/mind/types.js +7 -0
  152. package/dist/core/understanding/model/builder.d.ts +9 -0
  153. package/dist/core/understanding/model/builder.js +209 -0
  154. package/dist/core/understanding/model/ids.d.ts +7 -0
  155. package/dist/core/understanding/model/ids.js +48 -0
  156. package/dist/core/understanding/model/index.d.ts +7 -0
  157. package/dist/core/understanding/model/index.js +6 -0
  158. package/dist/core/understanding/model/schema.d.ts +12 -0
  159. package/dist/core/understanding/model/schema.js +33 -0
  160. package/dist/core/understanding/model/serializer.d.ts +9 -0
  161. package/dist/core/understanding/model/serializer.js +46 -0
  162. package/dist/core/understanding/model/types.d.ts +110 -0
  163. package/dist/core/understanding/model/types.js +1 -0
  164. package/dist/core/understanding/model/validator.d.ts +5 -0
  165. package/dist/core/understanding/model/validator.js +126 -0
  166. package/dist/core/understanding/model/version.d.ts +9 -0
  167. package/dist/core/understanding/model/version.js +7 -0
  168. package/dist/core/understanding/ownership/discover.d.ts +12 -0
  169. package/dist/core/understanding/ownership/discover.js +242 -0
  170. package/dist/core/understanding/ownership/index.d.ts +2 -0
  171. package/dist/core/understanding/ownership/index.js +1 -0
  172. package/dist/core/understanding/ownership/types.d.ts +23 -0
  173. package/dist/core/understanding/ownership/types.js +1 -0
  174. package/dist/core/understanding/query/engine.d.ts +24 -0
  175. package/dist/core/understanding/query/engine.js +35 -0
  176. package/dist/core/understanding/query/errors.d.ts +13 -0
  177. package/dist/core/understanding/query/errors.js +26 -0
  178. package/dist/core/understanding/query/executor.d.ts +8 -0
  179. package/dist/core/understanding/query/executor.js +34 -0
  180. package/dist/core/understanding/query/index.d.ts +7 -0
  181. package/dist/core/understanding/query/index.js +5 -0
  182. package/dist/core/understanding/query/models.d.ts +102 -0
  183. package/dist/core/understanding/query/models.js +1 -0
  184. package/dist/core/understanding/query/query.d.ts +68 -0
  185. package/dist/core/understanding/query/query.js +145 -0
  186. package/dist/core/understanding/query/registry.d.ts +8 -0
  187. package/dist/core/understanding/query/registry.js +340 -0
  188. package/dist/core/understanding/query/types.d.ts +63 -0
  189. package/dist/core/understanding/query/types.js +1 -0
  190. package/dist/core/understanding/relationships/discover.d.ts +11 -0
  191. package/dist/core/understanding/relationships/discover.js +517 -0
  192. package/dist/core/understanding/relationships/extract.d.ts +14 -0
  193. package/dist/core/understanding/relationships/extract.js +165 -0
  194. package/dist/core/understanding/relationships/index.d.ts +4 -0
  195. package/dist/core/understanding/relationships/index.js +3 -0
  196. package/dist/core/understanding/relationships/models.d.ts +21 -0
  197. package/dist/core/understanding/relationships/models.js +185 -0
  198. package/dist/core/understanding/relationships/types.d.ts +42 -0
  199. package/dist/core/understanding/relationships/types.js +1 -0
  200. package/dist/core/understanding/risks/discover.d.ts +8 -0
  201. package/dist/core/understanding/risks/discover.js +155 -0
  202. package/dist/core/understanding/risks/index.d.ts +2 -0
  203. package/dist/core/understanding/risks/index.js +1 -0
  204. package/dist/core/understanding/risks/types.d.ts +26 -0
  205. package/dist/core/understanding/risks/types.js +1 -0
  206. package/dist/core/understanding/shared/domain-lexicon.d.ts +9 -0
  207. package/dist/core/understanding/shared/domain-lexicon.js +107 -0
  208. package/dist/core/understanding/shared/index.d.ts +2 -0
  209. package/dist/core/understanding/shared/index.js +2 -0
  210. package/dist/core/understanding/shared/tokens.d.ts +7 -0
  211. package/dist/core/understanding/shared/tokens.js +141 -0
  212. package/dist/core/understanding/snapshot/identity.d.ts +24 -0
  213. package/dist/core/understanding/snapshot/identity.js +79 -0
  214. package/dist/core/understanding/snapshot/index.d.ts +2 -0
  215. package/dist/core/understanding/snapshot/index.js +1 -0
  216. package/dist/core/understanding/types/index.d.ts +22 -0
  217. package/dist/core/understanding/types/index.js +1 -0
  218. package/dist/core/understanding/understand/formatter.d.ts +10 -0
  219. package/dist/core/understanding/understand/formatter.js +115 -0
  220. package/dist/core/understanding/understand/index.d.ts +4 -0
  221. package/dist/core/understanding/understand/index.js +3 -0
  222. package/dist/core/understanding/understand/service.d.ts +17 -0
  223. package/dist/core/understanding/understand/service.js +76 -0
  224. package/dist/core/understanding/understand/summary.d.ts +14 -0
  225. package/dist/core/understanding/understand/summary.js +39 -0
  226. package/dist/core/understanding/understand/types.d.ts +31 -0
  227. package/dist/core/understanding/understand/types.js +1 -0
  228. package/dist/discovery/files.js +7 -2
  229. package/dist/discovery/log-like.d.ts +2 -0
  230. package/dist/discovery/log-like.js +7 -0
  231. package/dist/index.d.ts +2 -0
  232. package/dist/index.js +1 -0
  233. package/dist/mcp/brain/compile.d.ts +9 -0
  234. package/dist/mcp/brain/compile.js +42 -0
  235. package/dist/mcp/brain/errors.d.ts +12 -0
  236. package/dist/mcp/brain/errors.js +23 -0
  237. package/dist/mcp/brain/index.d.ts +11 -0
  238. package/dist/mcp/brain/index.js +8 -0
  239. package/dist/mcp/brain/provenance.d.ts +29 -0
  240. package/dist/mcp/brain/provenance.js +59 -0
  241. package/dist/mcp/brain/schemas.d.ts +13 -0
  242. package/dist/mcp/brain/schemas.js +105 -0
  243. package/dist/mcp/brain/security/root.d.ts +6 -0
  244. package/dist/mcp/brain/security/root.js +66 -0
  245. package/dist/mcp/brain/server.d.ts +12 -0
  246. package/dist/mcp/brain/server.js +46 -0
  247. package/dist/mcp/brain/session.d.ts +33 -0
  248. package/dist/mcp/brain/session.js +117 -0
  249. package/dist/mcp/brain/tools/handlers.d.ts +13 -0
  250. package/dist/mcp/brain/tools/handlers.js +483 -0
  251. package/dist/mcp/brain/tools/registry.d.ts +9 -0
  252. package/dist/mcp/brain/tools/registry.js +191 -0
  253. package/dist/reporters/github/annotations.d.ts +8 -0
  254. package/dist/reporters/github/annotations.js +42 -0
  255. package/dist/reporters/github/emit.d.ts +23 -0
  256. package/dist/reporters/github/emit.js +31 -0
  257. package/dist/reporters/github/summary.d.ts +20 -0
  258. package/dist/reporters/github/summary.js +111 -0
  259. package/dist/reporters/terminal/report.d.ts +5 -0
  260. package/dist/reporters/terminal/report.js +68 -5
  261. package/dist/reporters/verify/terminal.d.ts +4 -0
  262. package/dist/reporters/verify/terminal.js +26 -0
  263. package/dist/utils/fs.d.ts +5 -0
  264. package/dist/utils/fs.js +34 -0
  265. package/dist/utils/path.d.ts +5 -0
  266. package/dist/utils/path.js +16 -0
  267. package/package.json +15 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,108 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Notes
11
+
12
+ - Owner-only after this tree is green: `npm publish`, git tag `v1.1.0`, GitHub Release.
13
+ Do **not** auto-publish from CI agents.
14
+
15
+ ## [1.1.0] — 2026-08-13
16
+
17
+ Minor release: Brain → MCP → Agent consumption for Project Brain (Safety V1 unchanged).
18
+
19
+ ### Added
20
+
21
+ - Project Brain MCP bridge (`agentdoctor brain-mcp --root <path>`): STDIO MCP server
22
+ exposing evidence-backed Brain tools (`brain_overview`, `brain_query`, `brain_explain`,
23
+ `brain_trace`, `brain_claims`, `brain_evidence`, `brain_ownership`, `brain_risk`,
24
+ `brain_delta`, `brain_snapshot`) with provenance envelopes. Local-only; no API key.
25
+ Docs: [docs/mcp/brain-mcp.md](docs/mcp/brain-mcp.md). Examples: [examples/mcp/](examples/mcp/).
26
+ Demo: [docs/demo/brain-mcp-demo.md](docs/demo/brain-mcp-demo.md).
27
+ Validation: [validation/mcp-agent/](validation/mcp-agent/).
28
+
29
+ ### Changed
30
+
31
+ - Build packaging now includes `src/core/understanding/**` and `src/mcp/**` so the
32
+ `brain-mcp` CLI command can run from `dist/` (Safety public API export remains
33
+ Scan/Fix/Verify-focused).
34
+ - MCP tool descriptions explicitly mark READ vs CONTROLLED WRITE (`brain_snapshot` rebuild
35
+ only under `.agentdoctor/project-brain/`).
36
+
37
+ ### Notes
38
+
39
+ - Product promise: help AI coding agents understand what is in a repository, what can be
40
+ trusted, and why. Not a generic coding assistant, not RAG, not chatbot memory.
41
+ - Authenticated third-party agent LLM smoke (Cursor / Claude Code / Codex Q1–Q7) remains an
42
+ environment/auth gate; engineering MCP + Brain contracts pass without it.
43
+
44
+ ## [1.0.0] — 2026-08-12
45
+
46
+ First production release: Scan → Fix → Verify → CI contract frozen for v1.
47
+
48
+ ### Added
49
+
50
+ - Claude Code safe-context Fix writer: `agentdoctor fix` appends allowlisted
51
+ `permissions.deny` Read rules to `.claude/settings.json` for
52
+ `context/generated-directory` and `context/large-log-file` when Claude Code is
53
+ configured (alongside existing Cursor `.cursorignore` fixes).
54
+ - Codex safe-context Fix writer: `agentdoctor fix` merges allowlisted filesystem
55
+ `deny` keys into `.codex/config.toml` permission profiles for the same safe
56
+ context findings when Codex is detected. Skips when `sandbox_mode` is set or
57
+ `default_permissions` selects a built-in `:…` profile.
58
+ - GitHub Action / CLI CI policy enforcement: `minimum-score` / `--min-score`,
59
+ `fail-on-severity` / `--fail-on-severity`, `fail-on-rule` / `--fail-on-rule`,
60
+ `fail-on-new` / `--fail-on-new`, `verify-baseline`, `json-output`, `summary` /
61
+ `--summary`, and `annotations` / `--annotations`. Action `version: workspace`
62
+ runs the checked-out `dist/cli` for local CI.
63
+ - Guided Next steps on failed `scan` / `fix` / `verify` terminal output, and on
64
+ GitHub Step Summary when a policy gate fails — shortest path back to green
65
+ (reproduce → fix or explain → verify).
66
+ - Windows CI quality job (Node 20) and Windows-safe Fix/Action overwrite writes.
67
+ - Action smoke coverage for `fail-on-rule`, `verify-baseline`, and baseline
68
+ symlink escape rejection.
69
+
70
+ ### Fixed
71
+
72
+ - `instructions/missing-path-reference` also resolves non-`./` paths relative to the
73
+ instruction file directory (monorepo package docs), while root-level instruction
74
+ files still require repository-root paths. Corpus-100: 121 → 88 findings for this
75
+ rule (−33); other rules unchanged.
76
+ - `context/generated-directory` and `context/large-log-file` honor Claude Code Read
77
+ deny exclusions when computing `affectedAgents`, so Fix → Verify clears Claude
78
+ context findings after a deny rule is applied.
79
+ - The same rules honor Codex filesystem deny keys in `.codex/config.toml` when
80
+ computing `affectedAgents`.
81
+ - Action writes the JSON report even when a policy gate fails (exit `1`), so
82
+ artifacts remain available for triage.
83
+ - `--min-score` / Action `minimum-score` fail when no supported agents are
84
+ configured (`agentSecurityAnalysis: limited`) instead of passing on a vacuous 100.
85
+ - Terminal readiness prints `n/a` when analysis is limited (no agents).
86
+ - Agentless first scan no longer shows a green “No agent-configuration findings”
87
+ success line; it tells the user to add Cursor / Claude Code / Codex config and
88
+ re-run.
89
+ - Invalid `--min-score` values exit `2` (usage) instead of `3` (internal).
90
+ - Codex Fix refuses invalid `.codex/config.toml` during planning (same as Claude
91
+ invalid JSON) instead of silently skipping Codex and writing Cursor-only fixes.
92
+ - Codex Fix refuses unrecognizable / invalid `.codex/config.toml` content instead of
93
+ appending permission profiles into garbage TOML.
94
+ - `agentdoctor fix` exits `2` when confirmation is cancelled (non-TTY without `--yes`)
95
+ or when Fix refuses invalid settings / cannot write due to permissions.
96
+ - `scan --ci` now fails (exit `1`) when any **critical** finding exists. Omit `--ci` for
97
+ report-only scans. The GitHub Action stays report-only unless policy inputs are set
98
+ (it no longer passes a bare `--ci`).
99
+ - Discovery keeps oversized log/dump-like paths as size metadata so
100
+ `context/large-log-file` flags files above the content-read limit (previously silent
101
+ false negatives for the largest logs).
102
+ - Action `verify-baseline` re-checks workspace containment after `realpath` so a
103
+ workspace-relative symlink cannot escape to an outside file.
104
+ - Fix writers and Action report overwrite use Windows-safe replace (rename cannot
105
+ overwrite an existing destination on Windows).
106
+
107
+ ### Compatibility
108
+
109
+ - CLI + JSON + rule ID contracts frozen for v1 (see [docs/compatibility.md](docs/compatibility.md))
110
+ - Action `version` input default is `1.0.0` (bumped after npm published `@praneeth_54/agentdoctor@1.0.0`)
111
+
10
112
  ## [0.3.0-beta] — 2026-08-07
11
113
 
12
114
  Minor beta: completes the Scan → Fix → Verify CLI loop and corrects release-facing honesty.
@@ -171,7 +273,9 @@ First public beta.
171
273
  - Not a complete secret scanner
172
274
  - Git “tracked secret” detection deferred
173
275
 
174
- [Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v0.3.0-beta...HEAD
276
+ [Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v1.1.0...HEAD
277
+ [1.1.0]: https://github.com/pranee54/AgentDoctor/releases/tag/v1.1.0
278
+ [1.0.0]: https://github.com/pranee54/AgentDoctor/releases/tag/v1.0.0
175
279
  [0.3.0-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.3.0-beta
176
280
  [0.2.0-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.2.0-beta
177
281
  [0.1.4-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.4-beta
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AgentDoctor
2
2
 
3
- [![npm](https://img.shields.io/npm/v/@praneeth_54/agentdoctor)](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
3
+ [![npm](https://img.shields.io/npm/v/@praneeth_54/agentdoctor?label=npm)](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@praneeth_54/agentdoctor)](https://www.npmjs.com/package/@praneeth_54/agentdoctor)
5
5
  [![CI](https://img.shields.io/github/actions/workflow/status/pranee54/AgentDoctor/ci.yml?branch=main&label=CI)](https://github.com/pranee54/AgentDoctor/actions)
6
6
  [![Node](https://img.shields.io/node/v/@praneeth_54/agentdoctor)](https://nodejs.org)
@@ -16,7 +16,9 @@ AgentDoctor is a local CLI that inspects project-level AI coding agent setup —
16
16
  npx @praneeth_54/agentdoctor
17
17
  ```
18
18
 
19
- Public beta (`0.3.0-beta`). Scan → Fix → Verify. Deterministic scores in the terminal and JSON.
19
+ Public release track: Safety V1 (`1.0.0`) plus Project Brain MCP for agents (`1.1.0`).
20
+ Scan → Fix → Verify → CI remains the Safety contract. Brain MCP helps agents understand
21
+ what is in a repository, what can be trusted, and why — not a generic coding assistant.
20
22
 
21
23
  ---
22
24
 
@@ -24,12 +26,12 @@ Public beta (`0.3.0-beta`). Scan → Fix → Verify. Deterministic scores in the
24
26
 
25
27
  ![AgentDoctor scanning a repository and reporting coding-agent security findings](docs/images/cli-scan.png)
26
28
 
27
- _Real scan of the included `insecure-agent-project` fixture using AgentDoctor v0.3.0-beta._
29
+ _Real scan of the included `insecure-agent-project` fixture using AgentDoctor v1.0.0._
28
30
 
29
31
  ```text
30
32
  $ npx @praneeth_54/agentdoctor
31
33
 
32
- 🩺 AgentDoctor v0.3.0-beta
34
+ 🩺 AgentDoctor v1.0.0
33
35
 
34
36
  Scanning repository...
35
37
 
@@ -100,7 +102,7 @@ Manually reviewing all of that across Cursor, Claude Code, and Codex is slow and
100
102
  | ESLint | Source code |
101
103
  | **AgentDoctor** | **AI coding agent environments** |
102
104
 
103
- AgentDoctor analyzes configuration. It does not run agents or call an LLM. `agentdoctor fix` may append safe Cursor ignore patterns; it does not rewrite security settings or credentials.
105
+ AgentDoctor analyzes configuration. It does not run agents or call an LLM. `agentdoctor fix` may append safe context exclusions (Cursor `.cursorignore`, Claude Code Read deny rules, and Codex filesystem deny keys); it does not rewrite secrets, credentials, or security modes such as `bypassPermissions`.
104
106
 
105
107
  ---
106
108
 
@@ -142,7 +144,7 @@ You get deterministic findings with:
142
144
  - conservative recommendations
143
145
  - readiness score (`scores.overall` in JSON; overall line in the terminal)
144
146
 
145
- Safe Cursor context exclusions can be applied with `agentdoctor fix`. Security and review findings stay manual — Fix explains why and does not invent unsafe edits.
147
+ Safe context exclusions (Cursor / Claude Code / Codex) can be applied with `agentdoctor fix`. Security and review findings stay manual — Fix explains why and does not invent unsafe edits.
146
148
 
147
149
  ---
148
150
 
@@ -154,10 +156,10 @@ Safe Cursor context exclusions can be applied with `agentdoctor fix`. Security a
154
156
  npx @praneeth_54/agentdoctor
155
157
  ```
156
158
 
157
- Pin a beta version when you need a fixed install:
159
+ Pin a version when you need a fixed install:
158
160
 
159
161
  ```bash
160
- npx @praneeth_54/agentdoctor@0.3.0-beta
162
+ npx @praneeth_54/agentdoctor@1.0.0
161
163
  ```
162
164
 
163
165
  ### Global (optional)
@@ -173,7 +175,7 @@ agentdoctor
173
175
  # 1. Scan (save a baseline for Verify)
174
176
  npx @praneeth_54/agentdoctor scan . --json > agentdoctor-report.json
175
177
 
176
- # 2. Fix safe Cursor context exclusions (preview first with --dry-run)
178
+ # 2. Fix safe context exclusions (preview first with --dry-run)
177
179
  npx @praneeth_54/agentdoctor fix . --dry-run
178
180
  npx @praneeth_54/agentdoctor fix . -y
179
181
 
@@ -181,7 +183,11 @@ npx @praneeth_54/agentdoctor fix . -y
181
183
  npx @praneeth_54/agentdoctor verify . --baseline agentdoctor-report.json
182
184
  ```
183
185
 
184
- `fix` currently writes `.cursorignore` patterns for safe context findings (for example unignored `build/` or large logs). Review/manual security findings are listed as skipped — address those yourself, then re-run `verify`.
186
+ `fix` writes safe context exclusions for Cursor (`.cursorignore`), Claude Code
187
+ (`permissions.deny` Read rules in `.claude/settings.json`), and Codex (filesystem `deny`
188
+ keys under a permissions profile in `.codex/config.toml`) for findings such as unignored
189
+ `build/` or large logs. Review/manual security findings are listed as skipped — address those
190
+ yourself, then re-run `verify`.
185
191
 
186
192
  ### Common commands
187
193
 
@@ -279,10 +285,14 @@ steps:
279
285
 
280
286
  - name: Audit coding-agent configuration
281
287
  id: agentdoctor
282
- uses: pranee54/AgentDoctor@v0.3.0-beta
288
+ uses: pranee54/AgentDoctor@v1.0.0
283
289
  with:
284
290
  path: .
291
+ version: "1.0.0"
285
292
  output-file: agentdoctor-report.json
293
+ minimum-score: "70"
294
+ fail-on-severity: critical
295
+ summary: "true"
286
296
 
287
297
  - name: Upload AgentDoctor report
288
298
  uses: actions/upload-artifact@v4
@@ -291,10 +301,12 @@ steps:
291
301
  path: ${{ steps.agentdoctor.outputs.report-path }}
292
302
  ```
293
303
 
294
- The action installs the published `@praneeth_54/agentdoctor@0.3.0-beta` package, runs it with
295
- `--ci --json`, and writes the report inside the checked-out workspace. It sets up Node.js 20
296
- for the CLI. The optional `version` input accepts an exact npm version or the `latest` / `beta`
297
- dist-tag.
304
+ Policy inputs: `minimum-score`, `fail-on-severity`, `fail-on-rule`, `fail-on-new`,
305
+ `verify-baseline`, `summary`, `annotations`. The Action stays report-only until you set a
306
+ policy input. The Action default `version` is `1.0.0`. For local CI against this repo, use
307
+ `version: workspace` after `npm run build`. The action installs `@praneeth_54/agentdoctor`,
308
+ runs scan (or `verify` when `verify-baseline` is set) with `--json`, and writes the report
309
+ inside the workspace.
298
310
 
299
311
  ### CLI
300
312
 
@@ -302,15 +314,21 @@ Use JSON directly in other CI systems:
302
314
 
303
315
  ```bash
304
316
  # Report-only (exit 0 even when findings exist; scores still in JSON)
317
+ npx @praneeth_54/agentdoctor --json
318
+
319
+ # Fail when any critical finding exists
305
320
  npx @praneeth_54/agentdoctor --ci --json
306
321
 
307
- # Fail CI when overall readiness is below 70
322
+ # Fail when overall readiness is below 70 (with --ci also fails on criticals)
308
323
  npx @praneeth_54/agentdoctor --ci --json --min-score 70
324
+
325
+ # Fail on warning-or-higher (overrides the default critical gate from --ci)
326
+ npx @praneeth_54/agentdoctor --ci --json --fail-on-severity warning
309
327
  ```
310
328
 
311
- `--ci` runs non-interactively and does **not** apply an implicit score threshold.
312
- Use `--min-score N` (with or without `--ci`) to fail with exit code `1` when
313
- `scores.overall < N`.
329
+ `--ci` fails when any **critical** finding exists. Override the severity floor with
330
+ `--fail-on-severity`, and use `--min-score` / `--fail-on-rule` for additional gates.
331
+ Omit `--ci` for report-only JSON (exit `0` even when findings exist).
314
332
 
315
333
  Exit codes: [docs/exit-codes.md](docs/exit-codes.md). Compatibility promises: [docs/compatibility.md](docs/compatibility.md).
316
334
 
@@ -325,19 +343,18 @@ and deferred v2 items): [docs/scoring.md](docs/scoring.md).
325
343
 
326
344
  ---
327
345
 
328
- ## Beta limitations
346
+ ## Known limitations
329
347
 
330
- Honest limits of the current public beta:
348
+ Honest limits of v1:
331
349
 
332
- | Limitation | Status |
333
- | --------------------------- | ------------------------------------------------------------------- |
334
- | Automatic fixes | Safe Cursor `.cursorignore` context exclusions only |
335
- | Claude Code / Codex writers | Not implemented — Fix skips with an explicit reason |
336
- | Security findings | Review/manual — Fix does not rewrite secrets or permission settings |
337
- | GitHub Action score gates | Action remains `--ci --json` report-only (no `min-score` input) |
338
- | Secret-content scanning | Filename / config heuristics only |
339
- | Detection style | Intentionally conservative; false security findings are avoided |
340
- | Agent coverage | Cursor, Claude Code, Codex project configs |
350
+ | Limitation | Status |
351
+ | --------------------------- | ------------------------------------------------------------------------------- |
352
+ | Automatic fixes | Safe Cursor / Claude Code / Codex context exclusions only |
353
+ | Security findings | Review/manual — Fix does not rewrite secrets or security modes |
354
+ | Secret-content scanning | Filename / config heuristics only |
355
+ | Detection style | Intentionally conservative; false security findings are avoided |
356
+ | Agent coverage | Cursor, Claude Code, Codex project configs |
357
+ | Missing-path residual noise | Broad path-lattice expansion deferred; instruction-directory resolution shipped |
341
358
 
342
359
  See [CHANGELOG.md](CHANGELOG.md) and [docs/compatibility.md](docs/compatibility.md).
343
360
 
@@ -362,7 +379,9 @@ Details: [docs/architecture.md](docs/architecture.md)
362
379
  | [docs/rules.md](docs/rules.md) | Stable rule IDs |
363
380
  | [docs/exit-codes.md](docs/exit-codes.md) | Process exit codes |
364
381
  | [docs/scoring.md](docs/scoring.md) | Readiness scoring specification |
365
- | [docs/compatibility.md](docs/compatibility.md) | Beta compatibility promises |
382
+ | [docs/compatibility.md](docs/compatibility.md) | v1 compatibility promises |
383
+ | [docs/project-brain.md](docs/project-brain.md) | Project Brain understanding |
384
+ | [docs/mcp/brain-mcp.md](docs/mcp/brain-mcp.md) | Brain → MCP → Agent bridge |
366
385
  | [docs/development.md](docs/development.md) | Local development |
367
386
  | [docs/github-launch-checklist.md](docs/github-launch-checklist.md) | GitHub About / topics / launch |
368
387
  | [ROADMAP.md](ROADMAP.md) | Near- and medium-term plans |
@@ -388,6 +407,20 @@ node dist/cli/index.js ./fixtures/clean-configured-project
388
407
 
389
408
  ---
390
409
 
410
+ ## Project Brain MCP (agent context)
411
+
412
+ Evidence-backed repository understanding for agents (not a search MCP):
413
+
414
+ ```bash
415
+ agentdoctor brain-mcp --root /absolute/path/to/project
416
+ ```
417
+
418
+ Tools: overview, query, explain, trace, claims, evidence, ownership, risk, delta, snapshot.
419
+ Local STDIO only — no API key, no upload. Docs: [docs/mcp/brain-mcp.md](docs/mcp/brain-mcp.md).
420
+ Examples: [examples/mcp/](examples/mcp/).
421
+
422
+ ---
423
+
391
424
  ## Next steps
392
425
 
393
426
  - **Try it:** `npx @praneeth_54/agentdoctor`
@@ -23,11 +23,29 @@ export async function inspectRepoFile(root, relativePath, maxFileSizeBytes = DEF
23
23
  };
24
24
  }
25
25
  try {
26
- const lstat = await fs.lstat(absolutePath);
27
- const isSymlink = lstat.isSymbolicLink();
28
- if (isSymlink) {
29
- const real = await fs.realpath(absolutePath);
30
- if (!isPathInsideRoot(root, real)) {
26
+ // Open first, then inspect via the same handle (avoids TOCTOU with prior lstat/stat).
27
+ const handle = await fs.open(absolutePath, "r");
28
+ try {
29
+ const lstat = await fs.lstat(absolutePath);
30
+ const isSymlink = lstat.isSymbolicLink();
31
+ if (isSymlink) {
32
+ const real = await fs.realpath(absolutePath);
33
+ if (!isPathInsideRoot(root, real)) {
34
+ return {
35
+ relativePath: normalizedRelative,
36
+ absolutePath,
37
+ exists: true,
38
+ readable: false,
39
+ sizeBytes: 0,
40
+ empty: true,
41
+ isSymlink: true,
42
+ text: null,
43
+ error: "Symlink target is outside repository root",
44
+ };
45
+ }
46
+ }
47
+ const stat = await handle.stat();
48
+ if (!stat.isFile()) {
31
49
  return {
32
50
  relativePath: normalizedRelative,
33
51
  absolutePath,
@@ -35,64 +53,53 @@ export async function inspectRepoFile(root, relativePath, maxFileSizeBytes = DEF
35
53
  readable: false,
36
54
  sizeBytes: 0,
37
55
  empty: true,
38
- isSymlink: true,
56
+ isSymlink,
39
57
  text: null,
40
- error: "Symlink target is outside repository root",
58
+ error: "Not a regular file",
41
59
  };
42
60
  }
43
- }
44
- const stat = await fs.stat(absolutePath);
45
- if (!stat.isFile()) {
46
- return {
47
- relativePath: normalizedRelative,
48
- absolutePath,
49
- exists: true,
50
- readable: false,
51
- sizeBytes: 0,
52
- empty: true,
53
- isSymlink,
54
- text: null,
55
- error: "Not a regular file",
56
- };
57
- }
58
- const sizeBytes = Number(stat.size);
59
- if (sizeBytes === 0) {
61
+ const sizeBytes = Number(stat.size);
62
+ if (sizeBytes === 0) {
63
+ return {
64
+ relativePath: normalizedRelative,
65
+ absolutePath,
66
+ exists: true,
67
+ readable: true,
68
+ sizeBytes: 0,
69
+ empty: true,
70
+ isSymlink,
71
+ text: "",
72
+ };
73
+ }
74
+ if (sizeBytes > maxFileSizeBytes) {
75
+ return {
76
+ relativePath: normalizedRelative,
77
+ absolutePath,
78
+ exists: true,
79
+ readable: false,
80
+ sizeBytes,
81
+ empty: false,
82
+ isSymlink,
83
+ text: null,
84
+ error: "File exceeds max size limit",
85
+ };
86
+ }
87
+ const text = await handle.readFile("utf8");
88
+ const trimmedEmpty = text.trim().length === 0;
60
89
  return {
61
90
  relativePath: normalizedRelative,
62
91
  absolutePath,
63
92
  exists: true,
64
93
  readable: true,
65
- sizeBytes: 0,
66
- empty: true,
67
- isSymlink,
68
- text: "",
69
- };
70
- }
71
- if (sizeBytes > maxFileSizeBytes) {
72
- return {
73
- relativePath: normalizedRelative,
74
- absolutePath,
75
- exists: true,
76
- readable: false,
77
94
  sizeBytes,
78
- empty: false,
95
+ empty: trimmedEmpty,
79
96
  isSymlink,
80
- text: null,
81
- error: "File exceeds max size limit",
97
+ text,
82
98
  };
83
99
  }
84
- const text = await fs.readFile(absolutePath, "utf8");
85
- const trimmedEmpty = text.trim().length === 0;
86
- return {
87
- relativePath: normalizedRelative,
88
- absolutePath,
89
- exists: true,
90
- readable: true,
91
- sizeBytes,
92
- empty: trimmedEmpty,
93
- isSymlink,
94
- text,
95
- };
100
+ finally {
101
+ await handle.close();
102
+ }
96
103
  }
97
104
  catch (error) {
98
105
  const message = error instanceof Error ? error.message : "Unable to read file";
@@ -0,0 +1,9 @@
1
+ export interface BrainMcpCommandOptions {
2
+ root: string;
3
+ buildIfMissing?: boolean;
4
+ generatedAt?: string;
5
+ }
6
+ /**
7
+ * Start Brain MCP over STDIO. Must not write protocol noise to stdout.
8
+ */
9
+ export declare function runBrainMcpCommand(options: BrainMcpCommandOptions): Promise<number>;
@@ -0,0 +1,38 @@
1
+ import { EXIT_CODES } from "../../types/index.js";
2
+ import { BrainMcpError, runBrainMcpStdio } from "../../mcp/brain/index.js";
3
+ /**
4
+ * Start Brain MCP over STDIO. Must not write protocol noise to stdout.
5
+ */
6
+ export async function runBrainMcpCommand(options) {
7
+ try {
8
+ if (!options.root || options.root.trim().length === 0) {
9
+ process.stderr.write("Error: --root <path> is required (never scans process.cwd() implicitly)\n");
10
+ return EXIT_CODES.USAGE_ERROR;
11
+ }
12
+ await runBrainMcpStdio({
13
+ root: options.root,
14
+ buildIfMissing: options.buildIfMissing !== false,
15
+ ...(options.generatedAt !== undefined ? { generatedAt: options.generatedAt } : {}),
16
+ log: (message) => process.stderr.write(`${message}\n`),
17
+ });
18
+ // STDIO server runs until stdin closes; resolve when transport ends.
19
+ await new Promise((resolve) => {
20
+ const onClose = () => resolve();
21
+ process.stdin.on("end", onClose);
22
+ process.stdin.on("close", onClose);
23
+ });
24
+ return EXIT_CODES.SUCCESS;
25
+ }
26
+ catch (error) {
27
+ if (error instanceof BrainMcpError) {
28
+ process.stderr.write(`Error: ${error.message}\n`);
29
+ if (error.code === "invalid_root" || error.code === "invalid_argument") {
30
+ return EXIT_CODES.USAGE_ERROR;
31
+ }
32
+ return EXIT_CODES.INTERNAL_ERROR;
33
+ }
34
+ const message = error instanceof Error ? error.message : "brain-mcp failed";
35
+ process.stderr.write(`Error: ${message}\n`);
36
+ return EXIT_CODES.INTERNAL_ERROR;
37
+ }
38
+ }
@@ -39,7 +39,7 @@ export async function runExplainCommand(ruleId) {
39
39
  lines.push("");
40
40
  lines.push(colors.bold("Can AgentDoctor safely fix it?"));
41
41
  lines.push(rule.fixability === "safe"
42
- ? " Yes for Cursor context exclusions (`agentdoctor fix`). Other agents may still need a manual step."
42
+ ? " Yes for Cursor (`.cursorignore`), Claude Code (Read deny in `.claude/settings.json`), and Codex (filesystem deny in `.codex/config.toml`)."
43
43
  : rule.fixability === "review"
44
44
  ? " No — requires human review. Fix reports why and leaves the file unchanged."
45
45
  : rule.fixability === "manual"
@@ -1,7 +1,7 @@
1
1
  import { EXIT_CODES } from "../../types/index.js";
2
2
  import { isDirectory } from "../../utils/fs.js";
3
3
  import { resolveRepoRoot } from "../../utils/path.js";
4
- import { applyFixPlan, readCursorignore } from "../../core/fix/apply.js";
4
+ import { applyFixPlan, readClaudeSettings, readCodexConfig, readCursorignore, } from "../../core/fix/apply.js";
5
5
  import { buildFixPlan } from "../../core/fix/plan.js";
6
6
  import { renderFixPlanTerminal } from "../../core/fix/render.js";
7
7
  import { runFix } from "../../core/fix/run.js";
@@ -23,10 +23,14 @@ export async function runFixCommand(options) {
23
23
  const result = await scan({ cwd: target });
24
24
  const plan = await buildFixPlan(result);
25
25
  const cursorContent = await readCursorignore(plan.root);
26
+ const claudeSettingsContent = await readClaudeSettings(plan.root);
27
+ const codexConfigContent = await readCodexConfig(plan.root);
26
28
  const applyResult = await applyFixPlan(plan, { dryRun: true });
27
29
  process.stdout.write(renderFixPlanTerminal(plan, {
28
30
  dryRun: true,
29
31
  cursorContent,
32
+ claudeSettingsContent,
33
+ codexConfigContent,
30
34
  applyResult,
31
35
  }));
32
36
  return EXIT_CODES.SUCCESS;
@@ -38,27 +42,39 @@ export async function runFixCommand(options) {
38
42
  });
39
43
  if (cancelled) {
40
44
  process.stdout.write("\n Cancelled. No files were modified.\n\n");
41
- return EXIT_CODES.SUCCESS;
45
+ return EXIT_CODES.USAGE_ERROR;
42
46
  }
43
47
  const cursorContentAfter = await readCursorignore(plan.root);
48
+ const claudeSettingsAfter = await readClaudeSettings(plan.root);
49
+ const codexConfigAfter = await readCodexConfig(plan.root);
44
50
  process.stdout.write(renderFixPlanTerminal(plan, {
45
51
  dryRun: false,
46
52
  cursorContent: cursorContentAfter,
53
+ claudeSettingsContent: claudeSettingsAfter,
54
+ codexConfigContent: codexConfigAfter,
47
55
  applyResult,
48
56
  }));
49
- // After apply, show a short re-scan hint / delta for Cursor-fixable rules
50
57
  if (applyResult.writtenFiles.length > 0) {
51
58
  const after = await scan({ cwd: target });
52
59
  const remainingSafeContext = after.findings.filter((f) => f.fixability === "safe" &&
53
- (f.ruleId === "context/generated-directory" || f.ruleId === "context/large-log-file") &&
54
- f.affectedAgents.includes("cursor"));
55
- process.stdout.write(colors.dim(` Re-scan: ${remainingSafeContext.length} Cursor-related safe context finding(s) remain.\n\n`));
60
+ (f.ruleId === "context/generated-directory" || f.ruleId === "context/large-log-file"));
61
+ process.stdout.write(colors.dim(` Re-scan: ${remainingSafeContext.length} safe context finding(s) remain.\n\n`));
56
62
  }
57
63
  return EXIT_CODES.SUCCESS;
58
64
  }
59
65
  catch (error) {
60
66
  const message = error instanceof Error ? error.message : String(error);
61
67
  console.error(`Error: ${message}`);
68
+ if (isFixConfigOrPermissionError(message)) {
69
+ return EXIT_CODES.USAGE_ERROR;
70
+ }
62
71
  return EXIT_CODES.INTERNAL_ERROR;
63
72
  }
64
73
  }
74
+ function isFixConfigOrPermissionError(message) {
75
+ return (message.includes("refusing") ||
76
+ message.includes("not valid JSON") ||
77
+ message.includes("EACCES") ||
78
+ message.includes("EPERM") ||
79
+ message.includes("permission denied"));
80
+ }
@@ -1,3 +1,4 @@
1
+ import { type PolicyOptions } from "../../core/policy/evaluate.js";
1
2
  import { type ExitCode } from "../../types/index.js";
2
3
  export interface ScanCommandOptions {
3
4
  targetPath?: string;
@@ -5,6 +6,10 @@ export interface ScanCommandOptions {
5
6
  ci?: boolean;
6
7
  verbose?: boolean;
7
8
  minScore?: number;
9
+ failOnSeverity?: PolicyOptions["failOnSeverity"];
10
+ failOnRules?: string[];
11
+ summary?: boolean;
12
+ annotations?: boolean;
8
13
  }
9
14
  export declare function runScanCommand(options: ScanCommandOptions): Promise<ExitCode>;
10
15
  export declare function resolveTargetArgument(pathArg: string | undefined, cwd?: string): string;
@@ -1,10 +1,12 @@
1
1
  import path from "node:path";
2
+ import { evaluateScanPolicy } from "../../core/policy/evaluate.js";
2
3
  import { scan } from "../../core/scanner/scan.js";
4
+ import { emitGithubReports } from "../../reporters/github/emit.js";
3
5
  import { renderJsonReport } from "../../reporters/json/report.js";
4
6
  import { renderTerminalReport } from "../../reporters/terminal/report.js";
5
7
  import { EXIT_CODES } from "../../types/index.js";
6
- import { resolveRepoRoot } from "../../utils/path.js";
7
8
  import { isDirectory } from "../../utils/fs.js";
9
+ import { resolveRepoRoot } from "../../utils/path.js";
8
10
  export async function runScanCommand(options) {
9
11
  const target = resolveRepoRoot(options.targetPath ?? process.cwd());
10
12
  if (!(await isDirectory(target))) {
@@ -24,13 +26,30 @@ export async function runScanCommand(options) {
24
26
  verbose: options.verbose === true,
25
27
  }));
26
28
  }
27
- if (options.minScore !== undefined && result.scores !== null) {
28
- if (result.scores.overall < options.minScore) {
29
- if (!options.json) {
30
- console.error(`\nCI check failed: overall score ${result.scores.overall} is below --min-score ${options.minScore}`);
29
+ const failOnSeverity = options.failOnSeverity ?? (options.ci === true ? "critical" : undefined);
30
+ const policy = {
31
+ ...(options.minScore !== undefined ? { minimumScore: options.minScore } : {}),
32
+ ...(failOnSeverity !== undefined ? { failOnSeverity } : {}),
33
+ ...(options.failOnRules && options.failOnRules.length > 0
34
+ ? { failOnRules: options.failOnRules }
35
+ : {}),
36
+ };
37
+ const violations = evaluateScanPolicy(result, policy);
38
+ await emitGithubReports({
39
+ mode: "scan",
40
+ findings: result.findings,
41
+ overallScore: result.scores?.overall ?? null,
42
+ violations,
43
+ summary: options.summary === true,
44
+ annotations: options.annotations === true,
45
+ });
46
+ if (violations.length > 0) {
47
+ if (!options.json) {
48
+ for (const violation of violations) {
49
+ console.error(`\n${violation.message}`);
31
50
  }
32
- return EXIT_CODES.ISSUES_OR_THRESHOLD;
33
51
  }
52
+ return EXIT_CODES.ISSUES_OR_THRESHOLD;
34
53
  }
35
54
  return EXIT_CODES.SUCCESS;
36
55
  }