pr-checkmate 3.2.3 → 4.0.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 (174) hide show
  1. package/.eslintrc.js +3 -9
  2. package/LICENSE +8 -3
  3. package/README.md +54 -5
  4. package/dist/cjs/agent/hook.d.ts +37 -0
  5. package/dist/cjs/agent/hook.js +175 -0
  6. package/dist/cjs/agent/registration.d.ts +10 -0
  7. package/dist/cjs/agent/registration.js +28 -0
  8. package/dist/cjs/agent/setup.d.ts +20 -0
  9. package/dist/cjs/agent/setup.js +229 -0
  10. package/dist/cjs/cli.js +101 -0
  11. package/dist/cjs/config/constants.d.ts +2 -0
  12. package/dist/cjs/config/constants.js +5 -1
  13. package/dist/cjs/config/pr-checkmate.template.json +11 -1
  14. package/dist/cjs/core/checks/dependencies/grype-scan.js +18 -0
  15. package/dist/cjs/core/checks/findings.js +33 -7
  16. package/dist/cjs/core/checks/git/large-files.d.ts +1 -0
  17. package/dist/cjs/core/checks/git/large-files.js +3 -3
  18. package/dist/cjs/core/checks/languages/lint.js +12 -0
  19. package/dist/cjs/core/checks/languages/ruff-shared.js +6 -1
  20. package/dist/cjs/core/checks/pr/commitlint.js +4 -2
  21. package/dist/cjs/core/checks/pr/pr-size-check.d.ts +2 -0
  22. package/dist/cjs/core/checks/pr/pr-size-check.js +5 -5
  23. package/dist/cjs/core/checks/quality/package-size.d.ts +23 -1
  24. package/dist/cjs/core/checks/quality/package-size.js +20 -4
  25. package/dist/cjs/core/checks/quality/spellcheck.js +8 -5
  26. package/dist/cjs/core/checks/security/agent-instructions.d.ts +4 -0
  27. package/dist/cjs/core/checks/security/agent-instructions.js +149 -0
  28. package/dist/cjs/core/checks/security/diff-security.d.ts +7 -0
  29. package/dist/cjs/core/checks/security/diff-security.js +21 -1
  30. package/dist/cjs/core/checks/security/security.d.ts +0 -13
  31. package/dist/cjs/core/checks/security/security.js +27 -0
  32. package/dist/cjs/core/checks/security/workflow-security.js +33 -0
  33. package/dist/cjs/core/commands.d.ts +6 -0
  34. package/dist/cjs/core/commands.js +11 -1
  35. package/dist/cjs/core/finding-store.d.ts +16 -0
  36. package/dist/cjs/core/finding-store.js +73 -0
  37. package/dist/cjs/core/install/doctor.js +12 -0
  38. package/dist/cjs/core/install/grype-db.d.ts +25 -0
  39. package/dist/cjs/core/install/grype-db.js +45 -0
  40. package/dist/cjs/core/install/profiles.d.ts +1 -1
  41. package/dist/cjs/core/install/profiles.js +1 -1
  42. package/dist/cjs/core/install/reuse.js +6 -3
  43. package/dist/cjs/core/registry.js +2 -0
  44. package/dist/cjs/core/reporters.js +9 -0
  45. package/dist/cjs/core/run-checks.js +15 -5
  46. package/dist/cjs/core/sarif.d.ts +13 -0
  47. package/dist/cjs/core/sarif.js +60 -0
  48. package/dist/cjs/core/types.d.ts +7 -2
  49. package/dist/cjs/index.d.ts +2 -1
  50. package/dist/cjs/index.js +4 -1
  51. package/dist/cjs/init.d.ts +0 -8
  52. package/dist/cjs/init.js +12 -2
  53. package/dist/cjs/interfaces/index.d.ts +12 -0
  54. package/dist/cjs/mcp/config-tools.d.ts +30 -0
  55. package/dist/cjs/mcp/config-tools.js +320 -0
  56. package/dist/cjs/mcp/dependency.d.ts +33 -0
  57. package/dist/cjs/mcp/dependency.js +407 -0
  58. package/dist/cjs/mcp/protocol.d.ts +97 -0
  59. package/dist/cjs/mcp/protocol.js +181 -0
  60. package/dist/cjs/mcp/review.d.ts +63 -0
  61. package/dist/cjs/mcp/review.js +150 -0
  62. package/dist/cjs/mcp/serve.d.ts +8 -0
  63. package/dist/cjs/mcp/serve.js +49 -0
  64. package/dist/cjs/mcp/settings.d.ts +13 -0
  65. package/dist/cjs/mcp/settings.js +50 -0
  66. package/dist/cjs/mcp/tools.d.ts +23 -0
  67. package/dist/cjs/mcp/tools.js +633 -0
  68. package/dist/cjs/utils/execa.d.ts +7 -0
  69. package/dist/cjs/utils/execa.js +41 -1
  70. package/dist/cjs/utils/own-deps.js +8 -1
  71. package/dist/cjs/utils/resolve-bin.d.ts +2 -0
  72. package/dist/cjs/utils/resolve-bin.js +5 -0
  73. package/dist/cjs/utils/result-collector.d.ts +17 -1
  74. package/dist/cjs/utils/result-collector.js +7 -2
  75. package/dist/esm/agent/hook.d.ts +37 -0
  76. package/dist/esm/agent/hook.js +167 -0
  77. package/dist/esm/agent/registration.d.ts +10 -0
  78. package/dist/esm/agent/registration.js +21 -0
  79. package/dist/esm/agent/setup.d.ts +20 -0
  80. package/dist/esm/agent/setup.js +220 -0
  81. package/dist/esm/cli.js +100 -2
  82. package/dist/esm/config/constants.d.ts +2 -0
  83. package/dist/esm/config/constants.js +4 -0
  84. package/dist/esm/config/pr-checkmate.template.json +11 -1
  85. package/dist/esm/core/checks/dependencies/dependency-check.js +2 -2
  86. package/dist/esm/core/checks/dependencies/grype-scan.js +18 -0
  87. package/dist/esm/core/checks/dependencies/license-check.js +2 -2
  88. package/dist/esm/core/checks/dependencies/npm-audit.js +2 -2
  89. package/dist/esm/core/checks/findings.js +33 -7
  90. package/dist/esm/core/checks/git/diff-smell.js +1 -1
  91. package/dist/esm/core/checks/git/large-files.d.ts +1 -0
  92. package/dist/esm/core/checks/git/large-files.js +1 -1
  93. package/dist/esm/core/checks/languages/cpp-format.js +1 -1
  94. package/dist/esm/core/checks/languages/lint.js +12 -3
  95. package/dist/esm/core/checks/languages/prettier.js +3 -3
  96. package/dist/esm/core/checks/languages/python-format.js +2 -2
  97. package/dist/esm/core/checks/languages/python-lint.js +2 -2
  98. package/dist/esm/core/checks/languages/ruff-shared.js +6 -1
  99. package/dist/esm/core/checks/languages/typecheck.js +1 -1
  100. package/dist/esm/core/checks/pr/commitlint.js +4 -2
  101. package/dist/esm/core/checks/pr/pr-body.js +1 -1
  102. package/dist/esm/core/checks/pr/pr-size-check.d.ts +2 -0
  103. package/dist/esm/core/checks/pr/pr-size-check.js +3 -3
  104. package/dist/esm/core/checks/pr/pr-title-lint.js +1 -1
  105. package/dist/esm/core/checks/quality/dead-code.js +1 -1
  106. package/dist/esm/core/checks/quality/duplicate-check.js +1 -1
  107. package/dist/esm/core/checks/quality/markdown-lint.js +1 -1
  108. package/dist/esm/core/checks/quality/package-size.d.ts +23 -1
  109. package/dist/esm/core/checks/quality/package-size.js +19 -4
  110. package/dist/esm/core/checks/quality/spellcheck.js +11 -8
  111. package/dist/esm/core/checks/security/agent-instructions.d.ts +4 -0
  112. package/dist/esm/core/checks/security/agent-instructions.js +146 -0
  113. package/dist/esm/core/checks/security/diff-security.d.ts +7 -0
  114. package/dist/esm/core/checks/security/diff-security.js +21 -1
  115. package/dist/esm/core/checks/security/security.d.ts +0 -13
  116. package/dist/esm/core/checks/security/security.js +28 -1
  117. package/dist/esm/core/checks/security/workflow-security.js +33 -0
  118. package/dist/esm/core/commands.d.ts +6 -0
  119. package/dist/esm/core/commands.js +10 -0
  120. package/dist/esm/core/finding-store.d.ts +16 -0
  121. package/dist/esm/core/finding-store.js +67 -0
  122. package/dist/esm/core/install/doctor.js +12 -0
  123. package/dist/esm/core/install/grype-db.d.ts +25 -0
  124. package/dist/esm/core/install/grype-db.js +41 -0
  125. package/dist/esm/core/install/prepare.js +1 -1
  126. package/dist/esm/core/install/profiles.d.ts +1 -1
  127. package/dist/esm/core/install/profiles.js +1 -1
  128. package/dist/esm/core/install/reuse.js +6 -3
  129. package/dist/esm/core/registry.js +2 -0
  130. package/dist/esm/core/reporters.js +9 -0
  131. package/dist/esm/core/run-checks.js +17 -7
  132. package/dist/esm/core/sarif.d.ts +13 -0
  133. package/dist/esm/core/sarif.js +57 -0
  134. package/dist/esm/core/types.d.ts +7 -2
  135. package/dist/esm/index.d.ts +2 -1
  136. package/dist/esm/index.js +2 -0
  137. package/dist/esm/init.d.ts +0 -8
  138. package/dist/esm/init.js +15 -4
  139. package/dist/esm/interfaces/index.d.ts +12 -0
  140. package/dist/esm/mcp/config-tools.d.ts +30 -0
  141. package/dist/esm/mcp/config-tools.js +310 -0
  142. package/dist/esm/mcp/dependency.d.ts +33 -0
  143. package/dist/esm/mcp/dependency.js +402 -0
  144. package/dist/esm/mcp/protocol.d.ts +97 -0
  145. package/dist/esm/mcp/protocol.js +175 -0
  146. package/dist/esm/mcp/review.d.ts +63 -0
  147. package/dist/esm/mcp/review.js +139 -0
  148. package/dist/esm/mcp/serve.d.ts +8 -0
  149. package/dist/esm/mcp/serve.js +43 -0
  150. package/dist/esm/mcp/settings.d.ts +13 -0
  151. package/dist/esm/mcp/settings.js +43 -0
  152. package/dist/esm/mcp/tools.d.ts +23 -0
  153. package/dist/esm/mcp/tools.js +626 -0
  154. package/dist/esm/utils/execa.d.ts +7 -0
  155. package/dist/esm/utils/execa.js +40 -1
  156. package/dist/esm/utils/own-deps.js +8 -1
  157. package/dist/esm/utils/resolve-bin.d.ts +2 -0
  158. package/dist/esm/utils/resolve-bin.js +4 -0
  159. package/dist/esm/utils/result-collector.d.ts +17 -1
  160. package/dist/esm/utils/result-collector.js +7 -2
  161. package/eslint-default-rules.json +2 -8
  162. package/eslint.config.mjs +37 -8
  163. package/install-manifests/commitlint/package-lock.json +5 -4
  164. package/install-manifests/core/package-lock.json +5 -3
  165. package/install-manifests/js/package-lock.json +250 -571
  166. package/install-manifests/js/package.json +10 -8
  167. package/install-manifests/markdown/package-lock.json +16 -13
  168. package/install-manifests/markdown/package.json +3 -0
  169. package/install-manifests/spellcheck/package-lock.json +3 -3
  170. package/package.json +24 -16
  171. package/pr-checkmate.schema.json +35 -0
  172. package/src/config/.eslintrc.js +3 -9
  173. package/src/config/eslint-default-rules.json +2 -8
  174. package/src/config/pr-checkmate.schema.json +35 -0
@@ -1,7 +1,7 @@
1
1
  import { logger } from '../../utils/logger.js';
2
2
  import { clearToolPaths, packagePresent, registerToolPaths } from '../../utils/resolve-bin.js';
3
3
  import { ensureTooling } from './ensure.js';
4
- import { PROFILES, planProfiles } from './profiles.js';
4
+ import { planProfiles, PROFILES } from './profiles.js';
5
5
  /**
6
6
  * Whether a profile needs fetching at all, or already ships inside the package.
7
7
  *
@@ -3,7 +3,7 @@ import type { Language, LanguageUsage } from '../../utils/detect-language.js';
3
3
  /**
4
4
  * A named bundle of tooling, and the checks that stop working without it.
5
5
  *
6
- * The package ships ~233 MB of tooling, and no repository needs all of it: a
6
+ * The tooling totals ~233 MB, and no repository needs all of it: a
7
7
  * Python service pays for the whole JavaScript toolchain, a repository with
8
8
  * Spellcheck switched off still pays for cspell. Profiles are how that stops —
9
9
  * they name which slice of the tooling a given repository actually needs.
@@ -20,9 +20,9 @@ export const PROFILES = [
20
20
  'typescript',
21
21
  'eslint',
22
22
  'eslint-config-prettier',
23
- 'eslint-plugin-import-x',
24
23
  'eslint-plugin-jsdoc',
25
24
  'eslint-plugin-prettier',
25
+ 'eslint-plugin-simple-import-sort',
26
26
  'eslint-plugin-sonarjs',
27
27
  '@typescript-eslint/eslint-plugin',
28
28
  '@typescript-eslint/parser',
@@ -5,15 +5,18 @@ import { ownPackageRoot } from '../../utils/resolve-bin.js';
5
5
  /**
6
6
  * The major version we declare for a tool, from our own manifest.
7
7
  *
8
- * Read from `dependencies` rather than from the installed tree: what matters is
8
+ * Read from the manifest rather than from the installed tree: what matters is
9
9
  * the version our configuration was written against, and a hoisted install can
10
10
  * resolve to something else entirely.
11
11
  */
12
12
  function ownMajor(pkgName) {
13
13
  try {
14
14
  const manifest = path.join(ownPackageRoot(), 'package.json');
15
- const deps = JSON.parse(fs.readFileSync(manifest, 'utf-8')).dependencies;
16
- const range = deps?.[pkgName];
15
+ const parsed = JSON.parse(fs.readFileSync(manifest, 'utf-8'));
16
+ // Profile tooling is declared in `devDependencies` — it is fetched on demand
17
+ // rather than installed with us — but it is still the version our config was
18
+ // written against, and the manifest keeps both.
19
+ const range = parsed.dependencies?.[pkgName] ?? parsed.devDependencies?.[pkgName];
17
20
  if (!range)
18
21
  return null;
19
22
  // `^10.6.0`, `>=3.0.0`, `~5.1` — the leading number is the major in every
@@ -38,6 +38,7 @@ import { packageSizeCheck } from './checks/quality/package-size.js';
38
38
  import { spellcheckCheck } from './checks/quality/spellcheck.js';
39
39
  import { symlinksCheck } from './checks/quality/symlinks.js';
40
40
  import { yamlLintCheck } from './checks/quality/yaml-lint.js';
41
+ import { agentInstructionsCheck } from './checks/security/agent-instructions.js';
41
42
  import { diffSecurityCheck } from './checks/security/diff-security.js';
42
43
  import { dockerfileSecurityCheck } from './checks/security/dockerfile-security.js';
43
44
  import { migrationSafetyCheck } from './checks/security/migration-safety.js';
@@ -63,6 +64,7 @@ export const REGISTRY = [
63
64
  diffSecurityCheck,
64
65
  workflowSecurityCheck,
65
66
  dockerfileSecurityCheck,
67
+ agentInstructionsCheck,
66
68
  caseCollisionCheck,
67
69
  vulnScanCheck,
68
70
  grypeScanCheck,
@@ -1,4 +1,7 @@
1
1
  import fs from 'node:fs';
2
+ import { isMcpRegistered } from '../agent/registration.js';
3
+ import { AGENT_SETUP_COMMAND } from '../config/constants.js';
4
+ import { readMcpSettings } from '../mcp/settings.js';
2
5
  import { paginate, request } from '../utils/http.js';
3
6
  import { logger } from '../utils/index.js';
4
7
  import { packageVersion } from '../utils/package-version.js';
@@ -100,6 +103,12 @@ function printStdout(report, cfg) {
100
103
  if (cfg.include?.docsLink !== false) {
101
104
  // The docs cover every check and config key.
102
105
  logger.print(' DOCUMENTATION: https://pr-checkmate-docs.pages.dev/');
106
+ // Said once per project, and never in CI, where nobody is there to act on it.
107
+ if (!process.env.CI &&
108
+ readMcpSettings(process.cwd()).enabled &&
109
+ !isMcpRegistered(process.cwd())) {
110
+ logger.print(` AI AGENT: ${AGENT_SETUP_COMMAND} — your agent then writes code that passes.`);
111
+ }
103
112
  }
104
113
  }
105
114
  /** Network settings shared by every platform call. */
@@ -1,10 +1,11 @@
1
1
  import { isCiEnvironment, logger } from '../utils/index.js';
2
2
  import { packageVersion } from '../utils/package-version.js';
3
- import { Semaphore, resolveConcurrency, runPool, withTimeout } from '../utils/pool.js';
3
+ import { resolveConcurrency, runPool, Semaphore, withTimeout } from '../utils/pool.js';
4
4
  import { clearToolPaths } from '../utils/resolve-bin.js';
5
5
  import { ResultCollector } from '../utils/result-collector.js';
6
6
  import { buildContext } from './context.js';
7
- import { prepareTooling, noTooling } from './install/prepare.js';
7
+ import { collectFindings } from './finding-store.js';
8
+ import { noTooling, prepareTooling } from './install/prepare.js';
8
9
  import { REGISTRY } from './registry.js';
9
10
  import { report } from './reporters.js';
10
11
  import { PHASES, } from './types.js';
@@ -169,15 +170,24 @@ async function runOne(check, ctx, collector, heavy, tooling) {
169
170
  }
170
171
  const started = Date.now();
171
172
  const timeoutMs = ctx.config.run?.checkTimeoutMs ?? 300000;
172
- const execute = () => withTimeout(check.run(ctx), timeoutMs, () => {
173
- logger.warn(`[runChecks]: ⏱️ ${check.name} exceeded ${timeoutMs}ms`);
174
- return { status: 'warn', details: `timed out after ${timeoutMs}ms` };
175
- });
173
+ // Locations noted while this check runs, collected per check: the phase runs
174
+ // its checks in parallel, so a shared list would mix their findings.
175
+ let located = [];
176
+ const execute = async () => {
177
+ const { result, findings } = await collectFindings(() => withTimeout(check.run(ctx), timeoutMs, () => {
178
+ logger.warn(`[runChecks]: ⏱️ ${check.name} exceeded ${timeoutMs}ms`);
179
+ return { status: 'warn', details: `timed out after ${timeoutMs}ms` };
180
+ }));
181
+ located = findings;
182
+ return result;
183
+ };
176
184
  const outcome = check.weight === 'heavy' ? await heavy.run(execute) : await execute();
177
185
  if (ctx.config.run?.timings) {
178
186
  logger.info(`[runChecks]: ${check.name} took ${Date.now() - started}ms`);
179
187
  }
180
- collector.register(check.name, applySeverity(check.name, outcome.status, ctx), outcome.details);
188
+ collector.register(check.name, applySeverity(check.name, outcome.status, ctx), outcome.details,
189
+ // A clean result has nothing to locate, even when `failOn: never` filed some.
190
+ outcome.status === 'pass' ? undefined : (outcome.findings ?? located));
181
191
  }
182
192
  catch (err) {
183
193
  // An unexpected throw in a blocking check fails the run; in informational/format
@@ -0,0 +1,13 @@
1
+ /**
2
+ * A report as SARIF 2.1.0 — the format GitHub code scanning, VS Code and most
3
+ * security dashboards read, so a finding shows up inline on the line it names
4
+ * instead of only in a summary table.
5
+ *
6
+ * Only what a consumer can use is written. A failed or warned check that located
7
+ * its problems yields one result per location; one that could not yields a single
8
+ * result with no location, because a finding with nowhere to point is still a
9
+ * finding. Passes and skips are not results.
10
+ */
11
+ import type { CheckReport } from './types.js';
12
+ /** Convert a report to a SARIF log object, ready for `JSON.stringify`. */
13
+ export declare function toSarif(report: CheckReport, toolVersion: string): Record<string, unknown>;
@@ -0,0 +1,57 @@
1
+ const SARIF_SCHEMA = 'https://json.schemastore.org/sarif-2.1.0.json';
2
+ const ruleIdFor = (check, rule) => (rule ? `${check}/${rule}` : check);
3
+ function locatedResult(check, f) {
4
+ return {
5
+ ruleId: ruleIdFor(check.name, f.rule),
6
+ level: f.severity === 'error' ? 'error' : 'warning',
7
+ message: { text: f.snippet ? `${f.rule}: ${f.snippet}` : f.rule },
8
+ locations: [
9
+ {
10
+ physicalLocation: {
11
+ artifactLocation: { uri: f.file },
12
+ ...(f.line !== undefined && { region: { startLine: f.line } }),
13
+ },
14
+ },
15
+ ],
16
+ };
17
+ }
18
+ function summaryResult(check) {
19
+ return {
20
+ ruleId: ruleIdFor(check.name),
21
+ level: check.status === 'fail' ? 'error' : 'warning',
22
+ message: { text: check.details ?? `${check.name} reported a problem` },
23
+ };
24
+ }
25
+ /** Convert a report to a SARIF log object, ready for `JSON.stringify`. */
26
+ export function toSarif(report, toolVersion) {
27
+ const results = [];
28
+ const rules = new Map();
29
+ for (const check of report.results) {
30
+ if (check.status !== 'fail' && check.status !== 'warn')
31
+ continue;
32
+ const found = check.findings && check.findings.length > 0
33
+ ? check.findings.map(f => locatedResult(check, f))
34
+ : [summaryResult(check)];
35
+ for (const r of found) {
36
+ results.push(r);
37
+ rules.set(r.ruleId, { id: r.ruleId, name: r.ruleId });
38
+ }
39
+ }
40
+ return {
41
+ $schema: SARIF_SCHEMA,
42
+ version: '2.1.0',
43
+ runs: [
44
+ {
45
+ tool: {
46
+ driver: {
47
+ name: 'pr-checkmate',
48
+ version: toolVersion,
49
+ informationUri: 'https://www.npmjs.com/package/pr-checkmate',
50
+ rules: [...rules.values()],
51
+ },
52
+ },
53
+ results,
54
+ },
55
+ ],
56
+ };
57
+ }
@@ -1,7 +1,7 @@
1
1
  import type { PRCheckMateConfig, ReporterConfig } from '../interfaces/index.js';
2
2
  import type { Language, LanguageUsage } from '../utils/detect-language.js';
3
- import type { CheckResult, CheckStatus } from '../utils/result-collector.js';
4
- export type { CheckResult, CheckStatus, Language, LanguageUsage };
3
+ import type { CheckResult, CheckStatus, Finding } from '../utils/result-collector.js';
4
+ export type { CheckResult, CheckStatus, Finding, Language, LanguageUsage };
5
5
  /**
6
6
  * Execution phases, run strictly in order. Within a phase checks run in parallel.
7
7
  * `format` runs last because formatters (prettier) may write files.
@@ -67,6 +67,11 @@ export interface CheckContext {
67
67
  export interface CheckOutcome {
68
68
  status: CheckStatus;
69
69
  details?: string;
70
+ /**
71
+ * Where the problems are. Left to the orchestrator for pattern-based checks,
72
+ * which note locations as they scan; a check that knows better may set it.
73
+ */
74
+ findings?: Finding[];
70
75
  }
71
76
  /**
72
77
  * A single quality gate. `applies` decides relevance (language/marker gating);
@@ -4,8 +4,9 @@
4
4
  * @module pr-checkmate
5
5
  */
6
6
  export { runChecks, buildContext, REGISTRY } from './core/index.js';
7
+ export { toSarif } from './core/sarif.js';
7
8
  export { pass, warn, fail, skip, defineCheck } from './core/index.js';
8
- export type { Check, CheckContext, CheckOutcome, CheckReport, CheckResult, CheckStatus, Language, Phase, ReporterFn, ReporterKind, RunOptions, } from './core/index.js';
9
+ export type { Check, CheckContext, CheckOutcome, CheckReport, CheckResult, CheckStatus, Finding, Language, Phase, ReporterFn, ReporterKind, RunOptions, } from './core/index.js';
9
10
  export { getSourcePath, getSourcePaths, getIgnoredDirs, getPackageConfigPath, hasLocalConfig, } from './config/index.js';
10
11
  export type { PRCheckMateConfig } from './interfaces/index.js';
11
12
  export { Logger } from './utils/logger.js';
package/dist/esm/index.js CHANGED
@@ -6,6 +6,8 @@
6
6
  // Primary programmatic API: run checks and receive a structured report.
7
7
  // Never throws for violations, never calls process.exit — the caller decides.
8
8
  export { runChecks, buildContext, REGISTRY } from './core/index.js';
9
+ // SARIF 2.1.0 export of a report, for code-scanning dashboards and editors.
10
+ export { toSarif } from './core/sarif.js';
9
11
  // Authoring helpers for consumers writing their own checks (plugins).
10
12
  export { pass, warn, fail, skip, defineCheck } from './core/index.js';
11
13
  // Config helpers for consumers embedding pr-checkmate.
@@ -30,14 +30,6 @@ export declare function setupWorkflow(root: string, mode: GateMode): void;
30
30
  * heart about what should block.
31
31
  */
32
32
  export declare const BLOCKING_BY_DEFAULT: readonly ["Security Scan", "Sensitive Files", "Diff Security", "Workflow Security", "Merge Conflict", "NPM Audit", "License Check", "Dependencies", "TypeScript", "ESLint", "YAML Lint"];
33
- /**
34
- * Every option the template documents that the file does not already carry, at
35
- * its default. Without this, options such as `vulnScan` (off by default) or
36
- * `licenseCheck` exist only in the docs, and nobody edits what they cannot see.
37
- * Comment keys travel with the option they describe, section headers with the
38
- * first option after them.
39
- */
40
- export declare function templateExtras(existing: Record<string, unknown>): Record<string, unknown>;
41
33
  export declare function buildInitialConfig(sourcePath: string, languages: string[]): Record<string, unknown>;
42
34
  /**
43
35
  * Initialize (or refresh) pr-checkmate configuration in the current project.
package/dist/esm/init.js CHANGED
@@ -2,11 +2,11 @@ import { fileURLToPath as __fileURLToPath } from 'node:url';
2
2
  import { dirname as __dirnameFn } from 'node:path';
3
3
  const __dirname = __dirnameFn(__fileURLToPath(import.meta.url));
4
4
  import fs from 'fs';
5
- import path from 'path';
6
5
  import inquirer from 'inquirer';
7
- import { DEAD_CODE_IGNORE_DEFAULTS, DEFAULT_COMMANDS, DIFF_SECURITY_IGNORE_DEFAULTS, documentation, DOCS_URL, DUPLICATE_IGNORE_DEFAULTS, FULL_CONFIG_URL, GENERATED_DOC_FILES, IGNORED_DIRS, } from './config/index.js';
6
+ import path from 'path';
7
+ import { AGENT_SETUP_COMMAND, DEAD_CODE_IGNORE_DEFAULTS, DEFAULT_COMMANDS, DIFF_SECURITY_IGNORE_DEFAULTS, DOCS_URL, documentation, DUPLICATE_IGNORE_DEFAULTS, FULL_CONFIG_URL, GENERATED_DOC_FILES, IGNORED_DIRS, } from './config/index.js';
8
8
  import { DEFAULT_DATAFLOW_WINDOW } from './core/checks/findings.js';
9
- import { logger, detectLanguages, findOwnPackageRoot } from './utils/index.js';
9
+ import { detectLanguages, findOwnPackageRoot, logger } from './utils/index.js';
10
10
  const CONFIG_FILE = path.resolve(process.cwd(), 'pr-checkmate.json');
11
11
  /**
12
12
  * Points editors at the bundled JSON schema. With the generated config reduced
@@ -286,7 +286,7 @@ const GRYPE_SCAN_SEED = {
286
286
  * Comment keys travel with the option they describe, section headers with the
287
287
  * first option after them.
288
288
  */
289
- export function templateExtras(existing) {
289
+ function templateExtras(existing) {
290
290
  const templatePath = path.join(__dirname, 'config', 'pr-checkmate.template.json');
291
291
  if (!fs.existsSync(templatePath)) {
292
292
  return {};
@@ -413,6 +413,16 @@ async function createConfig(root) {
413
413
  * update notice insisted `init` must not be skipped after an upgrade. Defaults
414
414
  * now apply when the config is loaded, so there is nothing to top up.
415
415
  */
416
+ /** Adds the agent-setup command to a client's `commands` block when it is missing; nothing else in it is touched. */
417
+ function withAgentCommand(commands) {
418
+ if (commands === undefined)
419
+ return undefined;
420
+ if (typeof commands !== 'object' || commands === null || Array.isArray(commands))
421
+ return commands;
422
+ if (AGENT_SETUP_COMMAND in commands)
423
+ return commands;
424
+ return { ...commands, [AGENT_SETUP_COMMAND]: DEFAULT_COMMANDS[AGENT_SETUP_COMMAND] };
425
+ }
416
426
  async function updateConfig(root) {
417
427
  logger.info('[init]: pr-checkmate.json already exists — updating it.');
418
428
  try {
@@ -443,6 +453,7 @@ async function updateConfig(root) {
443
453
  // when missing; a client's own block is never touched.
444
454
  grypeScan: json.grypeScan ?? structuredClone(GRYPE_SCAN_SEED),
445
455
  ...templateExtras({ ...json, grypeScan: true }),
456
+ commands: withAgentCommand(json.commands),
446
457
  languages,
447
458
  };
448
459
  fs.writeFileSync(CONFIG_FILE, `${JSON.stringify(updated, null, 2)}\n`);
@@ -317,6 +317,18 @@ export interface PRCheckMateConfig {
317
317
  severityOverrides?: Record<string, 'error' | 'warn' | 'off'>;
318
318
  ignorePaths?: string[];
319
319
  };
320
+ mcp?: {
321
+ enabled?: boolean;
322
+ disabledTools?: string[];
323
+ readOnly?: boolean;
324
+ };
325
+ agentInstructions?: {
326
+ enabled?: boolean;
327
+ ignore?: string[];
328
+ failOn?: 'error' | 'warn' | 'never';
329
+ severityOverrides?: Record<string, 'error' | 'warn' | 'off'>;
330
+ ignorePaths?: string[];
331
+ };
320
332
  dockerfileSecurity?: {
321
333
  enabled?: boolean;
322
334
  ignore?: string[];
@@ -0,0 +1,30 @@
1
+ import type { ToolResult } from './protocol.js';
2
+ type Json = Record<string, unknown>;
3
+ /** What a key means, from the schema that ships with the package. */
4
+ export declare function explainConfig(key?: string): ToolResult;
5
+ /** Problems in a proposed config, phrased so the agent can correct them. Empty means it is acceptable. */
6
+ export declare function validateConfig(config: Json, cwd: string): string[];
7
+ /** Validate and write `config` into the repository's `pr-checkmate.json`. */
8
+ export declare function writeConfig(cwd: string, config: unknown, overwrite: boolean): ToolResult;
9
+ interface Suggestion {
10
+ proposed: Json;
11
+ notes: string[];
12
+ }
13
+ /**
14
+ * Look at the repository and propose a config.
15
+ *
16
+ * The baseline is a whole-repository run of the fast checks. A check that already
17
+ * fails is proposed as `warn`: the gate is on from the first commit, the existing
18
+ * debt is visible, and nothing new can slip in unnoticed — then each check is
19
+ * promoted back to blocking as it reaches zero. Proposing `error` everywhere would
20
+ * make the first CI run red for reasons nobody on the pull request caused, and the
21
+ * usual response to that is to switch the whole tool off.
22
+ */
23
+ export declare function suggestConfig(cwd: string): Promise<Suggestion & {
24
+ languages: string[];
25
+ }>;
26
+ /** `suggest_config` as the text an agent reads. */
27
+ export declare function formatSuggestion(s: Suggestion & {
28
+ languages: string[];
29
+ }): ToolResult;
30
+ export {};