@praneeth_54/agentdoctor 0.1.4-beta → 0.2.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -2
- package/README.md +38 -22
- package/dist/cli/commands/doctor.js +1 -1
- package/dist/cli/commands/scan.js +4 -12
- package/dist/cli/program.js +4 -4
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/scanner/scan.d.ts +1 -2
- package/dist/core/scanner/scan.js +8 -5
- package/dist/core/scoring/compute-scores.d.ts +6 -0
- package/dist/core/scoring/compute-scores.js +90 -0
- package/dist/core/scoring/placeholder.d.ts +3 -3
- package/dist/core/scoring/placeholder.js +3 -3
- package/dist/types/index.d.ts +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,8 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Planned
|
|
11
11
|
|
|
12
|
-
- Deterministic readiness scoring
|
|
13
12
|
- Safe automatic fixes
|
|
13
|
+
- Terminal readiness line and GitHub Action score-gate inputs (deferred; see scoring.md v2+)
|
|
14
|
+
|
|
15
|
+
## [0.2.0-beta] — 2026-08-02
|
|
16
|
+
|
|
17
|
+
Minor beta: deterministic readiness scoring and CLI `--min-score` enforcement.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Deterministic readiness scoring (v1): `scan()` populates `scoringAvailable: true` and
|
|
22
|
+
`scores` (`overall`, `categories`, `agents`) from post-dedupe findings
|
|
23
|
+
([docs/scoring.md](docs/scoring.md))
|
|
24
|
+
- CLI `--min-score N` enforcement: exit code `1` when `scores.overall < N`
|
|
25
|
+
- `--ci` without `--min-score` remains report-only (exit `0` on successful scan)
|
|
26
|
+
- Scoring specification and compatibility / exit-code docs updated for shipped behavior
|
|
27
|
+
|
|
28
|
+
### Compatibility
|
|
29
|
+
|
|
30
|
+
- No new JSON top-level fields (`scoringModel` / `scoreExplanation` deferred)
|
|
31
|
+
- Findings, rule IDs, and agent detection unchanged
|
|
32
|
+
- GitHub Action remains `--ci --json` report-only (no score-gate inputs)
|
|
33
|
+
- Default Action `version` input is `0.2.0-beta`
|
|
14
34
|
|
|
15
35
|
## [0.1.4-beta] — 2026-08-02
|
|
16
36
|
|
|
@@ -123,7 +143,8 @@ First public beta.
|
|
|
123
143
|
- Not a complete secret scanner
|
|
124
144
|
- Git “tracked secret” detection deferred
|
|
125
145
|
|
|
126
|
-
[Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v0.
|
|
146
|
+
[Unreleased]: https://github.com/pranee54/AgentDoctor/compare/v0.2.0-beta...HEAD
|
|
147
|
+
[0.2.0-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.2.0-beta
|
|
127
148
|
[0.1.4-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.4-beta
|
|
128
149
|
[0.1.3-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.3-beta
|
|
129
150
|
[0.1.2-beta]: https://github.com/pranee54/AgentDoctor/releases/tag/v0.1.2-beta
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ 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.1.x-beta`).
|
|
19
|
+
Public beta (`0.1.x-beta`). Deterministic readiness scores ship in JSON; automatic fixes are not available yet.
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
@@ -24,12 +24,12 @@ Public beta (`0.1.x-beta`). Readiness scoring and automatic fixes are not availa
|
|
|
24
24
|
|
|
25
25
|

|
|
26
26
|
|
|
27
|
-
_Real scan of the included `insecure-agent-project` fixture using AgentDoctor v0.
|
|
27
|
+
_Real scan of the included `insecure-agent-project` fixture using AgentDoctor v0.2.0-beta._
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
30
|
$ npx @praneeth_54/agentdoctor
|
|
31
31
|
|
|
32
|
-
🩺 AgentDoctor v0.
|
|
32
|
+
🩺 AgentDoctor v0.2.0-beta
|
|
33
33
|
|
|
34
34
|
Scanning repository...
|
|
35
35
|
|
|
@@ -155,7 +155,7 @@ npx @praneeth_54/agentdoctor
|
|
|
155
155
|
Pin a beta version when you need a fixed install:
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
|
-
npx @praneeth_54/agentdoctor@0.
|
|
158
|
+
npx @praneeth_54/agentdoctor@0.2.0-beta
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
### Global (optional)
|
|
@@ -259,7 +259,7 @@ steps:
|
|
|
259
259
|
|
|
260
260
|
- name: Audit coding-agent configuration
|
|
261
261
|
id: agentdoctor
|
|
262
|
-
uses: pranee54/AgentDoctor@v0.
|
|
262
|
+
uses: pranee54/AgentDoctor@v0.2.0-beta
|
|
263
263
|
with:
|
|
264
264
|
path: .
|
|
265
265
|
output-file: agentdoctor-report.json
|
|
@@ -271,7 +271,7 @@ steps:
|
|
|
271
271
|
path: ${{ steps.agentdoctor.outputs.report-path }}
|
|
272
272
|
```
|
|
273
273
|
|
|
274
|
-
The action installs the published `@praneeth_54/agentdoctor@0.
|
|
274
|
+
The action installs the published `@praneeth_54/agentdoctor@0.2.0-beta` package, runs it with
|
|
275
275
|
`--ci --json`, and writes the report inside the checked-out workspace. It sets up Node.js 20
|
|
276
276
|
for the CLI. The optional `version` input accepts an exact npm version or the `latest` / `beta`
|
|
277
277
|
dist-tag.
|
|
@@ -281,13 +281,28 @@ dist-tag.
|
|
|
281
281
|
Use JSON directly in other CI systems:
|
|
282
282
|
|
|
283
283
|
```bash
|
|
284
|
+
# Report-only (exit 0 even when findings exist; scores still in JSON)
|
|
284
285
|
npx @praneeth_54/agentdoctor --ci --json
|
|
286
|
+
|
|
287
|
+
# Fail CI when overall readiness is below 70
|
|
288
|
+
npx @praneeth_54/agentdoctor --ci --json --min-score 70
|
|
285
289
|
```
|
|
286
290
|
|
|
287
|
-
`--ci` runs non-interactively
|
|
291
|
+
`--ci` runs non-interactively and does **not** apply an implicit score threshold.
|
|
292
|
+
Use `--min-score N` (with or without `--ci`) to fail with exit code `1` when
|
|
293
|
+
`scores.overall < N`.
|
|
288
294
|
|
|
289
295
|
Exit codes: [docs/exit-codes.md](docs/exit-codes.md). Compatibility promises: [docs/compatibility.md](docs/compatibility.md).
|
|
290
296
|
|
|
297
|
+
### Readiness scoring
|
|
298
|
+
|
|
299
|
+
Scans populate `scoringAvailable: true` and a deterministic `scores` object
|
|
300
|
+
(overall, categories, agents). The terminal report does not render a readiness line yet;
|
|
301
|
+
scores are available in JSON (`--json`).
|
|
302
|
+
|
|
303
|
+
`--min-score N` is enforced by the CLI. Details (weights, security caps, threshold rules,
|
|
304
|
+
and deferred v2 items): [docs/scoring.md](docs/scoring.md).
|
|
305
|
+
|
|
291
306
|
---
|
|
292
307
|
|
|
293
308
|
## Beta limitations
|
|
@@ -296,21 +311,21 @@ Honest limits of the current public beta:
|
|
|
296
311
|
|
|
297
312
|
| Limitation | Status |
|
|
298
313
|
| ----------------------------------- | --------------------------------------------------------------- |
|
|
299
|
-
|
|
|
300
|
-
| `--min-score`
|
|
314
|
+
| Terminal readiness line | Scores ship in JSON only; terminal does not print N/100 yet |
|
|
315
|
+
| GitHub Action score gates | Action remains `--ci --json` report-only (no `min-score` input) |
|
|
301
316
|
| Automatic fixes (`agentdoctor fix`) | Stub only — does not modify files |
|
|
302
317
|
| Secret-content scanning | Filename / config heuristics only |
|
|
303
318
|
| Detection style | Intentionally conservative; false security findings are avoided |
|
|
304
319
|
| Agent coverage | Cursor, Claude Code, Codex project configs |
|
|
305
320
|
|
|
306
|
-
See [CHANGELOG.md](CHANGELOG.md) and [docs/release-notes-v0.
|
|
321
|
+
See [CHANGELOG.md](CHANGELOG.md) and [docs/release-notes-v0.2.0-beta.md](docs/release-notes-v0.2.0-beta.md).
|
|
307
322
|
|
|
308
323
|
---
|
|
309
324
|
|
|
310
325
|
## Architecture
|
|
311
326
|
|
|
312
327
|
```text
|
|
313
|
-
Discovery → Project detect → Agent adapters → Rule engine → Findings → Terminal / JSON
|
|
328
|
+
Discovery → Project detect → Agent adapters → Rule engine → Findings → Scores → Terminal / JSON
|
|
314
329
|
```
|
|
315
330
|
|
|
316
331
|
Details: [docs/architecture.md](docs/architecture.md)
|
|
@@ -319,17 +334,18 @@ Details: [docs/architecture.md](docs/architecture.md)
|
|
|
319
334
|
|
|
320
335
|
## Documentation
|
|
321
336
|
|
|
322
|
-
| Doc | Contents
|
|
323
|
-
| ------------------------------------------------------------------ |
|
|
324
|
-
| [docs/README.md](docs/README.md) | Documentation index
|
|
325
|
-
| [docs/architecture.md](docs/architecture.md) | Scan pipeline
|
|
326
|
-
| [docs/rules.md](docs/rules.md) | Stable rule IDs
|
|
327
|
-
| [docs/exit-codes.md](docs/exit-codes.md) | Process exit codes
|
|
328
|
-
| [docs/
|
|
329
|
-
| [docs/
|
|
330
|
-
| [docs/
|
|
331
|
-
| [
|
|
332
|
-
| [
|
|
337
|
+
| Doc | Contents |
|
|
338
|
+
| ------------------------------------------------------------------ | ------------------------------- |
|
|
339
|
+
| [docs/README.md](docs/README.md) | Documentation index |
|
|
340
|
+
| [docs/architecture.md](docs/architecture.md) | Scan pipeline |
|
|
341
|
+
| [docs/rules.md](docs/rules.md) | Stable rule IDs |
|
|
342
|
+
| [docs/exit-codes.md](docs/exit-codes.md) | Process exit codes |
|
|
343
|
+
| [docs/scoring.md](docs/scoring.md) | Readiness scoring specification |
|
|
344
|
+
| [docs/compatibility.md](docs/compatibility.md) | Beta compatibility promises |
|
|
345
|
+
| [docs/development.md](docs/development.md) | Local development |
|
|
346
|
+
| [docs/github-launch-checklist.md](docs/github-launch-checklist.md) | GitHub About / topics / launch |
|
|
347
|
+
| [ROADMAP.md](ROADMAP.md) | Near- and medium-term plans |
|
|
348
|
+
| [CHANGELOG.md](CHANGELOG.md) | Release history |
|
|
333
349
|
|
|
334
350
|
---
|
|
335
351
|
|
|
@@ -15,7 +15,7 @@ export async function runDoctorCommand() {
|
|
|
15
15
|
lines.push(` ${symbolOk()} Core scan API available`);
|
|
16
16
|
lines.push("");
|
|
17
17
|
lines.push(colors.dim("Environment looks ready."));
|
|
18
|
-
lines.push(colors.dim("
|
|
18
|
+
lines.push(colors.dim("Automatic fixes are not available yet."));
|
|
19
19
|
lines.push("");
|
|
20
20
|
process.stdout.write(lines.join("\n"));
|
|
21
21
|
return EXIT_CODES.SUCCESS;
|
|
@@ -24,20 +24,12 @@ export async function runScanCommand(options) {
|
|
|
24
24
|
verbose: options.verbose === true,
|
|
25
25
|
}));
|
|
26
26
|
}
|
|
27
|
-
if (options.
|
|
28
|
-
if (
|
|
27
|
+
if (options.minScore !== undefined && result.scores !== null) {
|
|
28
|
+
if (result.scores.overall < options.minScore) {
|
|
29
29
|
if (!options.json) {
|
|
30
|
-
console.error(
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
const threshold = options.minScore ?? 0;
|
|
35
|
-
if (result.scores.overall < threshold) {
|
|
36
|
-
if (!options.json) {
|
|
37
|
-
console.error(`\nCI check failed: overall score ${result.scores.overall} is below --min-score ${threshold}`);
|
|
38
|
-
}
|
|
39
|
-
return EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
30
|
+
console.error(`\nCI check failed: overall score ${result.scores.overall} is below --min-score ${options.minScore}`);
|
|
40
31
|
}
|
|
32
|
+
return EXIT_CODES.ISSUES_OR_THRESHOLD;
|
|
41
33
|
}
|
|
42
34
|
}
|
|
43
35
|
return EXIT_CODES.SUCCESS;
|
package/dist/cli/program.js
CHANGED
|
@@ -29,9 +29,9 @@ export function createProgram() {
|
|
|
29
29
|
.version(PACKAGE_VERSION, "-V, --version", "Print AgentDoctor version")
|
|
30
30
|
.argument("[path]", "Repository path to scan (default: current directory)")
|
|
31
31
|
.option("--json", "Emit machine-readable JSON (no decorative output)", false)
|
|
32
|
-
.option("--ci", "CI mode (non-interactive; --min-score is
|
|
32
|
+
.option("--ci", "CI mode (non-interactive; report-only unless --min-score is set)", false)
|
|
33
33
|
.option("--verbose", "Show timing and extra diagnostics", false)
|
|
34
|
-
.option("--min-score <number>", "
|
|
34
|
+
.option("--min-score <number>", "Exit 1 when overall readiness score is below this (0-100)", parseMinScore)
|
|
35
35
|
.action(async (pathArg, options) => {
|
|
36
36
|
const minScore = readMinScore(options);
|
|
37
37
|
const code = await runScanCommand({
|
|
@@ -48,9 +48,9 @@ export function createProgram() {
|
|
|
48
48
|
.description("Scan a repository for AI coding agent configuration issues (default command)")
|
|
49
49
|
.argument("[path]", "Repository path to scan")
|
|
50
50
|
.option("--json", "Emit machine-readable JSON", false)
|
|
51
|
-
.option("--ci", "CI mode (--min-score
|
|
51
|
+
.option("--ci", "CI mode (non-interactive; report-only unless --min-score is set)", false)
|
|
52
52
|
.option("--verbose", "Show timing and extra diagnostics", false)
|
|
53
|
-
.option("--min-score <number>", "
|
|
53
|
+
.option("--min-score <number>", "Exit 1 when overall readiness score is below this (0-100)", parseMinScore)
|
|
54
54
|
.action(async (pathArg, options) => {
|
|
55
55
|
const minScore = readMinScore(options);
|
|
56
56
|
const code = await runScanCommand({
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const PACKAGE_VERSION = "0.
|
|
1
|
+
export declare const PACKAGE_VERSION = "0.2.0-beta";
|
|
2
2
|
export declare const DEFAULT_MAX_FILE_SIZE_BYTES: number;
|
|
3
3
|
/** Directories skipped during normal discovery (unless a rule needs them later). */
|
|
4
4
|
export declare const DEFAULT_IGNORE_DIRECTORIES: Set<string>;
|
package/dist/constants.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = "0.
|
|
1
|
+
export const PACKAGE_VERSION = "0.2.0-beta";
|
|
2
2
|
export const DEFAULT_MAX_FILE_SIZE_BYTES = 2 * 1024 * 1024; // 2 MiB
|
|
3
3
|
/** Directories skipped during normal discovery (unless a rule needs them later). */
|
|
4
4
|
export const DEFAULT_IGNORE_DIRECTORIES = new Set([
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ScanOptions, ScanResult } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Public scan entry point.
|
|
4
|
-
* Pipeline: discovery → project detection → agent adapters → rule engine → findings.
|
|
5
|
-
* Readiness scoring is reserved for a later release (`scores` remains null for now).
|
|
4
|
+
* Pipeline: discovery → project detection → agent adapters → rule engine → findings → scores.
|
|
6
5
|
*/
|
|
7
6
|
export declare function scan(options?: ScanOptions): Promise<ScanResult>;
|
|
@@ -4,10 +4,10 @@ import { detectProject } from "../../detectors/project.js";
|
|
|
4
4
|
import { sanitizeTerminalText } from "../../security/redaction.js";
|
|
5
5
|
import { buildRuleContext } from "../rules/build-context.js";
|
|
6
6
|
import { runRules } from "../rules/run-rules.js";
|
|
7
|
+
import { computeReadinessScores } from "../scoring/compute-scores.js";
|
|
7
8
|
/**
|
|
8
9
|
* Public scan entry point.
|
|
9
|
-
* Pipeline: discovery → project detection → agent adapters → rule engine → findings.
|
|
10
|
-
* Readiness scoring is reserved for a later release (`scores` remains null for now).
|
|
10
|
+
* Pipeline: discovery → project detection → agent adapters → rule engine → findings → scores.
|
|
11
11
|
*/
|
|
12
12
|
export async function scan(options = {}) {
|
|
13
13
|
const totalStarted = performance.now();
|
|
@@ -51,21 +51,24 @@ export async function scan(options = {}) {
|
|
|
51
51
|
if (agentSecurityAnalysis === "limited") {
|
|
52
52
|
warnings.push("No supported coding-agent configuration detected; agent-specific security exposure checks are limited.");
|
|
53
53
|
}
|
|
54
|
+
const scoringStarted = performance.now();
|
|
55
|
+
const scores = computeReadinessScores(findings);
|
|
56
|
+
const scoringMs = Math.round(performance.now() - scoringStarted);
|
|
54
57
|
return {
|
|
55
58
|
version: PACKAGE_VERSION,
|
|
56
59
|
repository,
|
|
57
60
|
agents,
|
|
58
61
|
findings,
|
|
59
62
|
summary,
|
|
60
|
-
scores
|
|
61
|
-
scoringAvailable:
|
|
63
|
+
scores,
|
|
64
|
+
scoringAvailable: true,
|
|
62
65
|
agentSecurityAnalysis,
|
|
63
66
|
timing: {
|
|
64
67
|
discoveryMs: discovery.elapsedMs,
|
|
65
68
|
detectionMs,
|
|
66
69
|
agentsMs,
|
|
67
70
|
rulesMs,
|
|
68
|
-
scoringMs
|
|
71
|
+
scoringMs,
|
|
69
72
|
totalMs: Math.round(performance.now() - totalStarted),
|
|
70
73
|
},
|
|
71
74
|
diagnostics: {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const SEVERITY_BASE = {
|
|
2
|
+
critical: 35,
|
|
3
|
+
warning: 10,
|
|
4
|
+
info: 2,
|
|
5
|
+
};
|
|
6
|
+
const SEVERITY_SORT_RANK = {
|
|
7
|
+
critical: 0,
|
|
8
|
+
warning: 1,
|
|
9
|
+
info: 2,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* v1 readiness scores from post-dedupe findings.
|
|
13
|
+
* Spec: docs/scoring.md
|
|
14
|
+
*/
|
|
15
|
+
export function computeReadinessScores(findings) {
|
|
16
|
+
const overallRaw = 100 - sumDeductions(findings);
|
|
17
|
+
const overall = clampScore(applySecurityCaps(overallRaw, findings));
|
|
18
|
+
return {
|
|
19
|
+
overall,
|
|
20
|
+
categories: {
|
|
21
|
+
security: scoreSubset(findings.filter((f) => f.category === "security")),
|
|
22
|
+
context: scoreSubset(findings.filter((f) => f.category === "context")),
|
|
23
|
+
instructions: scoreSubset(findings.filter((f) => f.category === "instructions")),
|
|
24
|
+
mcp: scoreSubset(findings.filter((f) => f.category === "mcp")),
|
|
25
|
+
compatibility: scoreSubset(findings.filter((f) => f.category === "compatibility")),
|
|
26
|
+
performance: scoreSubset(findings.filter((f) => f.category === "performance")),
|
|
27
|
+
},
|
|
28
|
+
agents: {
|
|
29
|
+
cursor: scoreSubset(findings.filter((f) => f.affectedAgents.includes("cursor"))),
|
|
30
|
+
"claude-code": scoreSubset(findings.filter((f) => f.affectedAgents.includes("claude-code"))),
|
|
31
|
+
codex: scoreSubset(findings.filter((f) => f.affectedAgents.includes("codex"))),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function scoreSubset(findings) {
|
|
36
|
+
return clampScore(100 - sumDeductions(findings));
|
|
37
|
+
}
|
|
38
|
+
function sumDeductions(findings) {
|
|
39
|
+
const sorted = sortFindings(findings);
|
|
40
|
+
const severityIndex = {
|
|
41
|
+
critical: 0,
|
|
42
|
+
warning: 0,
|
|
43
|
+
info: 0,
|
|
44
|
+
};
|
|
45
|
+
let total = 0;
|
|
46
|
+
for (const finding of sorted) {
|
|
47
|
+
const occurrence = severityIndex[finding.severity];
|
|
48
|
+
severityIndex[finding.severity] = occurrence + 1;
|
|
49
|
+
total += SEVERITY_BASE[finding.severity] * diminishingMultiplier(occurrence);
|
|
50
|
+
}
|
|
51
|
+
return total;
|
|
52
|
+
}
|
|
53
|
+
function diminishingMultiplier(zeroBasedIndex) {
|
|
54
|
+
if (zeroBasedIndex === 0)
|
|
55
|
+
return 1;
|
|
56
|
+
if (zeroBasedIndex === 1)
|
|
57
|
+
return 0.7;
|
|
58
|
+
if (zeroBasedIndex === 2)
|
|
59
|
+
return 0.5;
|
|
60
|
+
return 0.35;
|
|
61
|
+
}
|
|
62
|
+
function sortFindings(findings) {
|
|
63
|
+
return [...findings].sort((a, b) => {
|
|
64
|
+
const sev = SEVERITY_SORT_RANK[a.severity] - SEVERITY_SORT_RANK[b.severity];
|
|
65
|
+
if (sev !== 0)
|
|
66
|
+
return sev;
|
|
67
|
+
const rule = a.ruleId.localeCompare(b.ruleId);
|
|
68
|
+
if (rule !== 0)
|
|
69
|
+
return rule;
|
|
70
|
+
const pathA = a.evidence?.path ?? "";
|
|
71
|
+
const pathB = b.evidence?.path ?? "";
|
|
72
|
+
const pathCmp = pathA.localeCompare(pathB);
|
|
73
|
+
if (pathCmp !== 0)
|
|
74
|
+
return pathCmp;
|
|
75
|
+
return a.id.localeCompare(b.id);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function applySecurityCaps(overall, findings) {
|
|
79
|
+
const securityCriticals = findings.filter((f) => f.category === "security" && f.severity === "critical").length;
|
|
80
|
+
if (securityCriticals >= 2) {
|
|
81
|
+
return Math.min(overall, 49);
|
|
82
|
+
}
|
|
83
|
+
if (securityCriticals >= 1) {
|
|
84
|
+
return Math.min(overall, 69);
|
|
85
|
+
}
|
|
86
|
+
return overall;
|
|
87
|
+
}
|
|
88
|
+
function clampScore(value) {
|
|
89
|
+
return Math.max(0, Math.min(100, Math.round(value)));
|
|
90
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Scores } from "../../types/index.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* Production scans
|
|
5
|
-
*
|
|
3
|
+
* Historical filesScanned-based stub. Kept for unit tests that document the
|
|
4
|
+
* pre-v1 placeholder behavior. Production scans use computeReadinessScores
|
|
5
|
+
* (docs/scoring.md) — do not call this from scan().
|
|
6
6
|
*/
|
|
7
7
|
export declare function computePlaceholderScores(filesScanned: number): Scores;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Production scans
|
|
4
|
-
*
|
|
2
|
+
* Historical filesScanned-based stub. Kept for unit tests that document the
|
|
3
|
+
* pre-v1 placeholder behavior. Production scans use computeReadinessScores
|
|
4
|
+
* (docs/scoring.md) — do not call this from scan().
|
|
5
5
|
*/
|
|
6
6
|
export function computePlaceholderScores(filesScanned) {
|
|
7
7
|
const base = 72;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -106,11 +106,11 @@ export interface ScanResult {
|
|
|
106
106
|
findings: Finding[];
|
|
107
107
|
summary: FindingsSummary;
|
|
108
108
|
/**
|
|
109
|
-
* Readiness scores when
|
|
110
|
-
*
|
|
109
|
+
* Readiness scores (v1). Always populated when `scoringAvailable` is true.
|
|
110
|
+
* Remains typed as nullable for older consumers / transitional tooling.
|
|
111
111
|
*/
|
|
112
112
|
scores: Scores | null;
|
|
113
|
-
/**
|
|
113
|
+
/** True when the readiness scoring model is active and `scores` is populated. */
|
|
114
114
|
scoringAvailable: boolean;
|
|
115
115
|
/**
|
|
116
116
|
* `limited` when no supported coding agent is detected/configured.
|