projscan 4.9.2 → 4.10.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 (185) hide show
  1. package/README.md +226 -1350
  2. package/dist/analyzers/securityCheck.js +33 -15
  3. package/dist/analyzers/securityCheck.js.map +1 -1
  4. package/dist/analyzers/supplyChainCheck.js +9 -2
  5. package/dist/analyzers/supplyChainCheck.js.map +1 -1
  6. package/dist/cli/commands/bugHunt.js +3 -1
  7. package/dist/cli/commands/bugHunt.js.map +1 -1
  8. package/dist/cli/commands/ci.js +29 -13
  9. package/dist/cli/commands/ci.js.map +1 -1
  10. package/dist/cli/commands/dogfood.js +2 -0
  11. package/dist/cli/commands/dogfood.js.map +1 -1
  12. package/dist/cli/commands/feedback.js +21 -2
  13. package/dist/cli/commands/feedback.js.map +1 -1
  14. package/dist/cli/commands/init.js +3 -0
  15. package/dist/cli/commands/init.js.map +1 -1
  16. package/dist/cli/commands/route.js +3 -2
  17. package/dist/cli/commands/route.js.map +1 -1
  18. package/dist/core/adoption.js +50 -21
  19. package/dist/core/adoption.js.map +1 -1
  20. package/dist/core/agentBrief.js +2 -1
  21. package/dist/core/agentBrief.js.map +1 -1
  22. package/dist/core/bugHunt.js +51 -22
  23. package/dist/core/bugHunt.js.map +1 -1
  24. package/dist/core/bugHuntHotspotFindings.js +2 -1
  25. package/dist/core/bugHuntHotspotFindings.js.map +1 -1
  26. package/dist/core/ciGate.d.ts +10 -0
  27. package/dist/core/ciGate.js +21 -0
  28. package/dist/core/ciGate.js.map +1 -0
  29. package/dist/core/dogfood.d.ts +1 -0
  30. package/dist/core/dogfood.js +42 -20
  31. package/dist/core/dogfood.js.map +1 -1
  32. package/dist/core/dogfoodDiscovery.d.ts +8 -0
  33. package/dist/core/dogfoodDiscovery.js +119 -0
  34. package/dist/core/dogfoodDiscovery.js.map +1 -0
  35. package/dist/core/feedback.js +73 -5
  36. package/dist/core/feedback.js.map +1 -1
  37. package/dist/core/fileInspectionReport.js +37 -0
  38. package/dist/core/fileInspectionReport.js.map +1 -1
  39. package/dist/core/intentRouterArchitectureKeywordWeights.d.ts +1 -0
  40. package/dist/core/intentRouterArchitectureKeywordWeights.js +69 -0
  41. package/dist/core/intentRouterArchitectureKeywordWeights.js.map +1 -0
  42. package/dist/core/intentRouterCatalog.js +85 -31
  43. package/dist/core/intentRouterCatalog.js.map +1 -1
  44. package/dist/core/intentRouterDependencyKeywordWeights.d.ts +1 -0
  45. package/dist/core/intentRouterDependencyKeywordWeights.js +100 -0
  46. package/dist/core/intentRouterDependencyKeywordWeights.js.map +1 -0
  47. package/dist/core/intentRouterFileImpactKeywordWeights.d.ts +1 -0
  48. package/dist/core/intentRouterFileImpactKeywordWeights.js +92 -0
  49. package/dist/core/intentRouterFileImpactKeywordWeights.js.map +1 -0
  50. package/dist/core/intentRouterKeywordEarlyGuards.js +8 -3
  51. package/dist/core/intentRouterKeywordEarlyGuards.js.map +1 -1
  52. package/dist/core/intentRouterKeywordSearchGuards.js +28 -24
  53. package/dist/core/intentRouterKeywordSearchGuards.js.map +1 -1
  54. package/dist/core/intentRouterKeywordToolGuards.js +43 -0
  55. package/dist/core/intentRouterKeywordToolGuards.js.map +1 -1
  56. package/dist/core/intentRouterKeywordWeights.js +40 -1222
  57. package/dist/core/intentRouterKeywordWeights.js.map +1 -1
  58. package/dist/core/intentRouterOperationalKeywordWeights.d.ts +1 -0
  59. package/dist/core/intentRouterOperationalKeywordWeights.js +203 -0
  60. package/dist/core/intentRouterOperationalKeywordWeights.js.map +1 -0
  61. package/dist/core/intentRouterPlanningSignals.js +4 -1
  62. package/dist/core/intentRouterPlanningSignals.js.map +1 -1
  63. package/dist/core/intentRouterPrDiffKeywords.d.ts +4 -0
  64. package/dist/core/intentRouterPrDiffKeywords.js +64 -0
  65. package/dist/core/intentRouterPrDiffKeywords.js.map +1 -0
  66. package/dist/core/intentRouterPrDiffSignals.js +6 -0
  67. package/dist/core/intentRouterPrDiffSignals.js.map +1 -1
  68. package/dist/core/intentRouterProductImprovementSignals.d.ts +1 -0
  69. package/dist/core/intentRouterProductImprovementSignals.js +48 -0
  70. package/dist/core/intentRouterProductImprovementSignals.js.map +1 -0
  71. package/dist/core/intentRouterRegressionKeywordMatches.js +3 -0
  72. package/dist/core/intentRouterRegressionKeywordMatches.js.map +1 -1
  73. package/dist/core/intentRouterRegressionKeywordWeights.d.ts +1 -0
  74. package/dist/core/intentRouterRegressionKeywordWeights.js +118 -0
  75. package/dist/core/intentRouterRegressionKeywordWeights.js.map +1 -0
  76. package/dist/core/intentRouterReleaseSignals.d.ts +1 -0
  77. package/dist/core/intentRouterReleaseSignals.js +47 -0
  78. package/dist/core/intentRouterReleaseSignals.js.map +1 -1
  79. package/dist/core/intentRouterReviewSignals.d.ts +1 -0
  80. package/dist/core/intentRouterReviewSignals.js +23 -1
  81. package/dist/core/intentRouterReviewSignals.js.map +1 -1
  82. package/dist/core/intentRouterSearchKeywordWeights.d.ts +1 -0
  83. package/dist/core/intentRouterSearchKeywordWeights.js +407 -0
  84. package/dist/core/intentRouterSearchKeywordWeights.js.map +1 -0
  85. package/dist/core/intentRouterSecurityKeywordWeights.d.ts +1 -0
  86. package/dist/core/intentRouterSecurityKeywordWeights.js +50 -0
  87. package/dist/core/intentRouterSecurityKeywordWeights.js.map +1 -0
  88. package/dist/core/intentRouterTrustFeedbackKeywordWeights.d.ts +1 -0
  89. package/dist/core/intentRouterTrustFeedbackKeywordWeights.js +222 -0
  90. package/dist/core/intentRouterTrustFeedbackKeywordWeights.js.map +1 -0
  91. package/dist/core/intentRouterUnderstandSignals.js +1 -0
  92. package/dist/core/intentRouterUnderstandSignals.js.map +1 -1
  93. package/dist/core/intentRouterWorkSignals.js +3 -0
  94. package/dist/core/intentRouterWorkSignals.js.map +1 -1
  95. package/dist/core/intentRouterWorkflowKeywordWeights.d.ts +1 -0
  96. package/dist/core/intentRouterWorkflowKeywordWeights.js +124 -0
  97. package/dist/core/intentRouterWorkflowKeywordWeights.js.map +1 -0
  98. package/dist/core/issueEngine.js +46 -2
  99. package/dist/core/issueEngine.js.map +1 -1
  100. package/dist/core/memory.d.ts +2 -0
  101. package/dist/core/memory.js +33 -1
  102. package/dist/core/memory.js.map +1 -1
  103. package/dist/core/preflightChangedFiles.d.ts +3 -0
  104. package/dist/core/preflightChangedFiles.js +13 -0
  105. package/dist/core/preflightChangedFiles.js.map +1 -1
  106. package/dist/core/preflightEvidence.d.ts +3 -0
  107. package/dist/core/preflightEvidence.js +3 -0
  108. package/dist/core/preflightEvidence.js.map +1 -1
  109. package/dist/core/privacy.d.ts +2 -0
  110. package/dist/core/privacy.js +10 -0
  111. package/dist/core/privacy.js.map +1 -1
  112. package/dist/core/qualityScorecard.js +25 -13
  113. package/dist/core/qualityScorecard.js.map +1 -1
  114. package/dist/core/startEvidence.js +26 -1
  115. package/dist/core/startEvidence.js.map +1 -1
  116. package/dist/core/startFixedRouteCriteria.js +5 -0
  117. package/dist/core/startFixedRouteCriteria.js.map +1 -1
  118. package/dist/core/startInputs.d.ts +3 -0
  119. package/dist/core/startMissionPolicy.d.ts +1 -1
  120. package/dist/core/startMissionPolicy.js +18 -7
  121. package/dist/core/startMissionPolicy.js.map +1 -1
  122. package/dist/core/startMode.js +17 -4
  123. package/dist/core/startMode.js.map +1 -1
  124. package/dist/core/startReportBuilder.js +1 -1
  125. package/dist/core/startReportBuilder.js.map +1 -1
  126. package/dist/core/startReviewGate.js +26 -4
  127. package/dist/core/startReviewGate.js.map +1 -1
  128. package/dist/core/startRouteActions.js +6 -0
  129. package/dist/core/startRouteActions.js.map +1 -1
  130. package/dist/core/understand.js +60 -13
  131. package/dist/core/understand.js.map +1 -1
  132. package/dist/core/workplan.js +99 -17
  133. package/dist/core/workplan.js.map +1 -1
  134. package/dist/projscan-sbom.cdx.json +6 -6
  135. package/dist/reporters/ciIssueDetails.d.ts +10 -0
  136. package/dist/reporters/ciIssueDetails.js +37 -0
  137. package/dist/reporters/ciIssueDetails.js.map +1 -0
  138. package/dist/reporters/consoleCiReporter.d.ts +2 -1
  139. package/dist/reporters/consoleCiReporter.js +26 -9
  140. package/dist/reporters/consoleCiReporter.js.map +1 -1
  141. package/dist/reporters/consoleFileReporter.js +10 -0
  142. package/dist/reporters/consoleFileReporter.js.map +1 -1
  143. package/dist/reporters/consoleHealthReporter.js +3 -1
  144. package/dist/reporters/consoleHealthReporter.js.map +1 -1
  145. package/dist/reporters/jsonReporter.d.ts +2 -1
  146. package/dist/reporters/jsonReporter.js +17 -10
  147. package/dist/reporters/jsonReporter.js.map +1 -1
  148. package/dist/reporters/markdownFileReporter.js +11 -0
  149. package/dist/reporters/markdownFileReporter.js.map +1 -1
  150. package/dist/reporters/markdownHealthReporter.d.ts +2 -1
  151. package/dist/reporters/markdownHealthReporter.js +5 -5
  152. package/dist/reporters/markdownHealthReporter.js.map +1 -1
  153. package/dist/reporters/scoreBreakdownReporter.d.ts +2 -0
  154. package/dist/reporters/scoreBreakdownReporter.js +24 -0
  155. package/dist/reporters/scoreBreakdownReporter.js.map +1 -0
  156. package/dist/tool-manifest.json +2 -2
  157. package/dist/types/analysis.d.ts +21 -1
  158. package/dist/types/bugHunt.d.ts +3 -0
  159. package/dist/types/config.d.ts +9 -0
  160. package/dist/types/dogfood.d.ts +15 -1
  161. package/dist/types/inspection.d.ts +3 -0
  162. package/dist/types/preflight.d.ts +3 -0
  163. package/dist/types/startMissionControl.d.ts +3 -0
  164. package/dist/types/startMissionReview.d.ts +2 -0
  165. package/dist/utils/ciFailOn.d.ts +5 -0
  166. package/dist/utils/ciFailOn.js +12 -0
  167. package/dist/utils/ciFailOn.js.map +1 -0
  168. package/dist/utils/config.js +3 -1
  169. package/dist/utils/config.js.map +1 -1
  170. package/dist/utils/configBasics.d.ts +2 -0
  171. package/dist/utils/configBasics.js +21 -0
  172. package/dist/utils/configBasics.js.map +1 -1
  173. package/dist/utils/configIssueRules.js +64 -0
  174. package/dist/utils/configIssueRules.js.map +1 -1
  175. package/dist/utils/scoreCalculator.js +77 -16
  176. package/dist/utils/scoreCalculator.js.map +1 -1
  177. package/docs/GUIDE.md +36 -6
  178. package/docs/demos/projscan-4-1-demo.html +8 -8
  179. package/docs/demos/projscan-mission-control.tape +2 -2
  180. package/docs/demos/projscan-mission-proof.tape +9 -5
  181. package/docs/projscan-mission-control.gif +0 -0
  182. package/docs/projscan-mission-control.png +0 -0
  183. package/docs/projscan-mission-proof.gif +0 -0
  184. package/docs/projscan-proof-router.png +0 -0
  185. package/package.json +1 -1
@@ -1,3 +1,9 @@
1
+ const BASE_SCORE = 100;
2
+ const SEVERITY_WEIGHTS = {
3
+ error: 20,
4
+ warning: 10,
5
+ info: 3,
6
+ };
1
7
  /**
2
8
  * Calculate a project health score (0–100) and letter grade from detected issues.
3
9
  *
@@ -14,23 +20,78 @@
14
20
  * F < 60
15
21
  */
16
22
  export function calculateScore(issues) {
17
- const errors = issues.filter((i) => i.severity === 'error').length;
18
- const warnings = issues.filter((i) => i.severity === 'warning').length;
19
- const infos = issues.filter((i) => i.severity === 'info').length;
20
- const deductions = errors * 20 + warnings * 10 + infos * 3;
21
- const score = Math.max(0, 100 - deductions);
22
- let grade;
23
+ const errors = countSeverity(issues, 'error');
24
+ const warnings = countSeverity(issues, 'warning');
25
+ const infos = countSeverity(issues, 'info');
26
+ const uncappedPenalty = penaltyFor('error', errors) + penaltyFor('warning', warnings) + penaltyFor('info', infos);
27
+ const totalPenalty = Math.min(BASE_SCORE, uncappedPenalty);
28
+ const score = Math.max(0, BASE_SCORE - uncappedPenalty);
29
+ const grade = gradeForScore(score);
30
+ return {
31
+ score,
32
+ grade,
33
+ errors,
34
+ warnings,
35
+ infos,
36
+ scoreBreakdown: buildScoreBreakdown(issues, {
37
+ score,
38
+ grade,
39
+ errors,
40
+ warnings,
41
+ infos,
42
+ totalPenalty,
43
+ uncappedPenalty,
44
+ }),
45
+ };
46
+ }
47
+ function countSeverity(issues, severity) {
48
+ return issues.filter((issue) => issue.severity === severity).length;
49
+ }
50
+ function penaltyFor(severity, count) {
51
+ return count * SEVERITY_WEIGHTS[severity];
52
+ }
53
+ function gradeForScore(score) {
23
54
  if (score >= 90)
24
- grade = 'A';
25
- else if (score >= 80)
26
- grade = 'B';
27
- else if (score >= 70)
28
- grade = 'C';
29
- else if (score >= 60)
30
- grade = 'D';
31
- else
32
- grade = 'F';
33
- return { score, grade, errors, warnings, infos };
55
+ return 'A';
56
+ if (score >= 80)
57
+ return 'B';
58
+ if (score >= 70)
59
+ return 'C';
60
+ if (score >= 60)
61
+ return 'D';
62
+ return 'F';
63
+ }
64
+ function buildScoreBreakdown(issues, score) {
65
+ return {
66
+ baseScore: BASE_SCORE,
67
+ finalScore: score.score,
68
+ grade: score.grade,
69
+ totalPenalty: score.totalPenalty,
70
+ uncappedPenalty: score.uncappedPenalty,
71
+ bySeverity: {
72
+ error: severityBreakdown(score.errors, 'error'),
73
+ warning: severityBreakdown(score.warnings, 'warning'),
74
+ info: severityBreakdown(score.infos, 'info'),
75
+ },
76
+ byCategory: categoryBreakdown(issues),
77
+ };
78
+ }
79
+ function severityBreakdown(count, severity) {
80
+ const weight = SEVERITY_WEIGHTS[severity];
81
+ return { count, weight, penalty: count * weight };
82
+ }
83
+ function categoryBreakdown(issues) {
84
+ const categories = new Map();
85
+ for (const issue of issues) {
86
+ const category = issue.category || 'uncategorized';
87
+ const current = categories.get(category) ?? { count: 0, penalty: 0 };
88
+ current.count += 1;
89
+ current.penalty += SEVERITY_WEIGHTS[issue.severity];
90
+ categories.set(category, current);
91
+ }
92
+ return [...categories.entries()]
93
+ .sort(([a], [b]) => a.localeCompare(b))
94
+ .map(([category, value]) => ({ category, ...value }));
34
95
  }
35
96
  const GRADE_COLORS = {
36
97
  A: 'brightgreen',
@@ -1 +1 @@
1
- {"version":3,"file":"scoreCalculator.js","sourceRoot":"","sources":["../../src/utils/scoreCalculator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAAC,MAAe;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACvE,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAEjE,MAAM,UAAU,GAAG,MAAM,GAAG,EAAE,GAAG,QAAQ,GAAG,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,UAAU,CAAC,CAAC;IAE5C,IAAI,KAA2B,CAAC;IAChC,IAAI,KAAK,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;SACxB,IAAI,KAAK,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;SAC7B,IAAI,KAAK,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;SAC7B,IAAI,KAAK,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;;QAC7B,KAAK,GAAG,GAAG,CAAC;IAEjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,YAAY,GAAyC;IACzD,CAAC,EAAE,aAAa;IAChB,CAAC,EAAE,OAAO;IACV,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,KAAK;CACT,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,KAA2B;IAClD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,yCAAyC,KAAK,IAAI,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAA2B;IACvD,OAAO,uBAAuB,QAAQ,CAAC,KAAK,CAAC,iDAAiD,CAAC;AACjG,CAAC"}
1
+ {"version":3,"file":"scoreCalculator.js","sourceRoot":"","sources":["../../src/utils/scoreCalculator.ts"],"names":[],"mappings":"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"}
package/docs/GUIDE.md CHANGED
@@ -551,13 +551,14 @@ Natural follow-up to `projscan hotspots` - once hotspots tells you _which_ file
551
551
  projscan ci
552
552
  ```
553
553
 
554
- A CI-pipeline-friendly health gate. Runs the full health check and exits with code 1 if the score falls below a threshold. No spinners or banners - clean output for CI logs.
554
+ A CI-pipeline-friendly health gate. Runs the full health check and exits with code 1 if the score falls below a threshold and at least one finding meets the `failOn` severity floor. No spinners or banners - clean output for CI logs.
555
555
 
556
556
  **Options:**
557
557
 
558
558
  | Flag | Description | Default |
559
559
  | ------------------ | ------------------------------------------------ | ----------------------------------------------------------- |
560
560
  | `--min-score <n>` | Minimum passing score (0–100) | `minScore` from `.projscanrc`, else 70 |
561
+ | `--fail-on <severity>` | Lowest severity that can fail a below-threshold gate: `info`, `warning`, or `error` | `failOn` from `.projscanrc`, else `warning` |
561
562
  | `--changed-only` | Gate only on issues in files changed vs base ref | off |
562
563
  | `--base-ref <ref>` | Git base ref for `--changed-only` | auto (origin/main → origin/master → main → master → HEAD~1) |
563
564
 
@@ -566,7 +567,7 @@ A CI-pipeline-friendly health gate. Runs the full health check and exits with co
566
567
  ```bash
567
568
  $ projscan ci --min-score 80
568
569
 
569
- projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80)
570
+ projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80, failOn: warning)
570
571
  ```
571
572
 
572
573
  <img src="npx%20projscan%20ci%20--min-score%2070.gif" alt="npx projscan ci" width="700">
@@ -574,7 +575,8 @@ projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80)
574
575
  **Exit codes:**
575
576
 
576
577
  - `0` - Score meets or exceeds the threshold
577
- - `1` - Score is below the threshold
578
+ - `0` - Score is below the threshold but no finding meets the `failOn` floor
579
+ - `1` - Score is below the threshold and at least one finding meets the `failOn` floor
578
580
 
579
581
  **JSON output** (useful for scripts):
580
582
 
@@ -582,6 +584,10 @@ projscan: B (82/100) - 0 errors, 2 warnings, 1 info - PASS (threshold: 80)
582
584
  projscan ci --min-score 70 --format json
583
585
  ```
584
586
 
587
+ Every `ci.issues[]` item keeps the original issue fields and adds
588
+ annotation-friendly fields: `ruleId`, `message`, primary `location`, all
589
+ `locations`, and `remediation` when a fix hint is available.
590
+
585
591
  **SARIF output** (for GitHub Code Scanning or any SARIF consumer):
586
592
 
587
593
  ```bash
@@ -887,6 +893,9 @@ Use it before broader rollout. The report includes feedback questions for the fi
887
893
  ## Health Score
888
894
 
889
895
  Every `projscan doctor` and `projscan badge` run calculates a health score from 0 to 100 based on detected issues.
896
+ `doctor --format json` and `ci --format json` include `scoreBreakdown` so scripts
897
+ and reviewers can see the base score, per-severity weights, category penalties,
898
+ total penalty, final score, and grade.
890
899
 
891
900
  **Scoring:**
892
901
 
@@ -909,7 +918,8 @@ Every `projscan doctor` and `projscan badge` run calculates a health score from
909
918
  The score appears in all output formats:
910
919
 
911
920
  - **Console**: Shown at the top of the doctor report
912
- - **JSON**: Included as `health.score` and `health.grade` fields
921
+ - **JSON**: Included as `health.score`, `health.grade`, and `health.scoreBreakdown`
922
+ fields. CI uses the same structure under `ci.scoreBreakdown`.
913
923
  - **Markdown**: Shown as a heading with an auto-generated shields.io badge
914
924
  - **HTML**: Shown in the health summary card
915
925
  - **SARIF**: Not surfaced directly - SARIF is per-issue, not per-project. The score still drives `ci`'s exit code.
@@ -1005,6 +1015,7 @@ ProjScan loads a project-wide config from one of:
1005
1015
  ```json
1006
1016
  {
1007
1017
  "minScore": 80,
1018
+ "failOn": "warning",
1008
1019
  "baseRef": "origin/main",
1009
1020
  "ignore": ["**/fixtures/**", "**/generated/**"],
1010
1021
  "scan": {
@@ -1013,6 +1024,9 @@ ProjScan loads a project-wide config from one of:
1013
1024
  "offline": false
1014
1025
  },
1015
1026
  "disableRules": ["missing-editorconfig", "large-*"],
1027
+ "suppress": {
1028
+ "hardcoded-secret": ["src/firebase.ts"]
1029
+ },
1016
1030
  "severityOverrides": {
1017
1031
  "missing-prettier": "info"
1018
1032
  },
@@ -1034,12 +1048,14 @@ ProjScan loads a project-wide config from one of:
1034
1048
  | Field | Type | Effect |
1035
1049
  | --------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1036
1050
  | `minScore` | number (0–100) | Default threshold for `projscan ci`. Clamped to 0–100. |
1051
+ | `failOn` | `'info' \| 'warning' \| 'error'` | Lowest severity that can fail a below-threshold `projscan ci` gate. Default `warning`; set `info` for legacy strictness or `error` for error-only blocking. |
1037
1052
  | `baseRef` | string | Default base ref for `--changed-only`. |
1038
1053
  | `ignore` | string[] | Extra glob patterns added to the built-in ignore list (`node_modules`, `.git`, `dist`, `build`, `coverage`, `.next`, `.nuxt`, `.cache`, `.turbo`, `.output`). |
1039
1054
  | `scan.includeIgnored` | boolean | Explicitly include files hidden by Git ignore rules. Default `false`. |
1040
1055
  | `scan.scanEnvValues` | boolean | Explicitly read `.env*` contents during secret-pattern checks. Default `false`; `.env` files are path-only. |
1041
1056
  | `scan.offline` | boolean | Block projscan network-capable features: telemetry sending, `audit`, registry checks, and optional semantic model loading. Default `false`. |
1042
1057
  | `disableRules` | string[] | Silence rules by id. Exact match (`missing-prettier`) or wildcard prefix (`large-*`). |
1058
+ | `suppress` | `Record<string, string[]>` | Silence a rule only for matching paths/globs, for example `{ "hardcoded-secret": ["src/firebase.ts"] }`. Other rules still run on that file. |
1043
1059
  | `severityOverrides` | `Record<string, 'info' \| 'warning' \| 'error'>` | Remap a rule's severity. Useful for downgrading project-specific false positives without disabling them. |
1044
1060
  | `reportPolicies` | `Record<string, { reportScope?: string[]; redactPaths?: boolean }>` | Named evidence export presets selected with `--report-policy <name>` on `analyze`, `doctor`, and `ci`. |
1045
1061
  | `hotspots.limit` | number (1–100) | Default limit for `projscan hotspots`. |
@@ -1047,6 +1063,12 @@ ProjScan loads a project-wide config from one of:
1047
1063
 
1048
1064
  Invalid JSON in a discovered config file is a hard error - projscan exits rather than silently ignoring it.
1049
1065
 
1066
+ Use inline suppressions for a single confirmed false positive:
1067
+
1068
+ ```ts
1069
+ const firebaseKey = "AIza..." // projscan-ignore-line hardcoded-secret -- Firebase web keys are public identifiers
1070
+ ```
1071
+
1050
1072
  ### Embedded config in `package.json`
1051
1073
 
1052
1074
  If you prefer to keep everything in `package.json`:
@@ -1564,8 +1586,10 @@ If you'd rather skip Code Scanning, `projscan init github-action` writes a pull-
1564
1586
  The `ci` command is purpose-built for pipelines:
1565
1587
 
1566
1588
  ```bash
1567
- projscan ci # Fail if score < 70 (default)
1589
+ projscan ci # Fail if score < 70 and warning/error findings exist
1568
1590
  projscan ci --min-score 80 # Custom threshold
1591
+ projscan ci --fail-on info # Legacy strictness: info can fail the gate
1592
+ projscan ci --fail-on error # Only errors can fail a below-threshold gate
1569
1593
  projscan ci --changed-only # Gate only on PR diff
1570
1594
  projscan ci --format json # JSON output for scripts
1571
1595
  projscan ci --format sarif > projscan.sarif # SARIF for any consumer
@@ -1577,9 +1601,15 @@ projscan ci --format sarif > projscan.sarif # SARIF for any consumer
1577
1601
  result=$(projscan ci --min-score 0 --format json)
1578
1602
  pass=$(echo "$result" | jq '.ci.pass')
1579
1603
  score=$(echo "$result" | jq '.ci.score')
1580
- echo "Score: $score, Pass: $pass"
1604
+ fail_on=$(echo "$result" | jq -r '.ci.failOn')
1605
+ echo "Score: $score, Pass: $pass, FailOn: $fail_on"
1581
1606
  ```
1582
1607
 
1608
+ For PR annotation tooling, read `.ci.issues[]`. Each issue includes `ruleId`,
1609
+ `severity`, `message`, primary `location`, all `locations`, and `remediation`
1610
+ when available. Gate metadata lives at `.ci.failOn`, `.ci.scorePass`, and
1611
+ `.ci.severityFloorMet`.
1612
+
1583
1613
  ### Tracking health over time in CI
1584
1614
 
1585
1615
  Combine `ci` with `diff` to track regressions:
@@ -426,11 +426,11 @@
426
426
  <section class="hero" aria-label="projscan Mission Control">
427
427
  <div class="intro">
428
428
  <div>
429
- <p class="eyebrow">Mission Outcome Loop</p>
429
+ <p class="eyebrow">Mission proof loop</p>
430
430
  <h1>Resume from saved proof.</h1>
431
431
  <p class="lead">
432
- projscan routes a developer goal, saves the mission, reads the proof state, and tells
433
- the next agent what changed, what remains, and whether the work is ready for version
432
+ projscan routes a developer goal, saves the mission, reads proof state, and tells the
433
+ next agent which proof passed, which work remains, and whether to request version
434
434
  review.
435
435
  </p>
436
436
  <div class="pills" aria-label="Product capabilities">
@@ -445,7 +445,7 @@
445
445
  <div class="metric-row" aria-label="Release candidate signals">
446
446
  <div class="metric">
447
447
  <strong>1 bundle</strong>
448
- <span>mission plus proof</span>
448
+ <span>mission and proof</span>
449
449
  </div>
450
450
  <div class="metric">
451
451
  <strong>45</strong>
@@ -479,14 +479,14 @@
479
479
  <span class="line dim">read proof-logs/summary.json and status.jsonl</span>
480
480
 
481
481
  <div class="term-section">
482
- <span class="line term-heading">What Changed</span>
482
+ <span class="line term-heading">Completed Proof</span>
483
483
  <span class="line">- Mission proof passed after 3 command(s).</span>
484
484
  <span class="line">- 1 reviewer decision recorded.</span>
485
485
  <span class="line">- 0 failed gates remain.</span>
486
486
  </div>
487
487
 
488
488
  <div class="term-section">
489
- <span class="line term-heading">What Remains</span>
489
+ <span class="line term-heading">Remaining Work</span>
490
490
  <span class="line success">Run ./review.sh and choose a reviewer reply.</span>
491
491
  <span class="line success">Version candidate: review_candidate</span>
492
492
  </div>
@@ -531,7 +531,7 @@
531
531
  <h2>Start from saved proof.</h2>
532
532
  <p>
533
533
  <code>projscan start --mission</code> reads the bundle proof state and gives the next
534
- agent a focused "what changed / what remains" handoff.
534
+ agent a focused proof status and remaining-work handoff.
535
535
  </p>
536
536
  </article>
537
537
  <article class="card">
@@ -611,7 +611,7 @@
611
611
  <span class="tag red">Gate</span>
612
612
  <span>
613
613
  <strong>Version review</strong>
614
- Outcome data says whether to request review or keep fixing failed proof.
614
+ Use outcome data to request review or keep fixing failed proof.
615
615
  </span>
616
616
  </div>
617
617
  </div>
@@ -8,6 +8,6 @@ Set Theme "Catppuccin Mocha"
8
8
  Set TypingSpeed 35ms
9
9
  Set Padding 16
10
10
 
11
- Type "projscan start --shortcuts --intent 'is it safe to commit this change?'"
11
+ Type "projscan start --shortcuts --intent 'is it safe to commit this change?' --quiet"
12
12
  Enter
13
- Sleep 12s
13
+ Sleep 24s
@@ -12,14 +12,18 @@ Type "rm -rf .projscan/vhs-mission"
12
12
  Enter
13
13
  Sleep 500ms
14
14
 
15
- Type "projscan start --save-mission .projscan/vhs-mission --intent 'is it safe to commit this change?'"
15
+ Type "projscan start --save-mission .projscan/vhs-mission --intent 'what can projscan read?' --quiet"
16
16
  Enter
17
- Sleep 10s
17
+ Sleep 30s
18
18
 
19
- Type "projscan mission-proof --mission .projscan/vhs-mission --format markdown | sed -n '1,38p'"
19
+ Type "sh .projscan/vhs-mission/review.sh | sed -n '1,34p'"
20
20
  Enter
21
21
  Sleep 8s
22
22
 
23
- Type "projscan start --mission .projscan/vhs-mission --handoff-prompt | sed -n '1,8p'"
23
+ Type "projscan mission-proof --mission .projscan/vhs-mission --format markdown --quiet | sed -n '1,32p'"
24
+ Enter
25
+ Sleep 10s
26
+
27
+ Type "projscan start --mission .projscan/vhs-mission --review-gate --quiet | sed -n '1,24p'"
24
28
  Enter
25
- Sleep 16s
29
+ Sleep 24s
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "projscan",
3
3
  "mcpName": "io.github.abhiyoheswaran1/projscan",
4
- "version": "4.9.2",
4
+ "version": "4.10.0",
5
5
  "description": "Local code intelligence for agent-assisted engineering. Focused daily workflows for repo orientation before edits, proof before handoff or commit, and release-candidate review, with AST-backed evidence through an MCP server and CLI. Runs locally by default.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",