pr-checkmate 1.23.24 → 2.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 (98) hide show
  1. package/README.md +61 -11
  2. package/cspell.json +3 -8
  3. package/dist/cli.js +37 -64
  4. package/dist/config/constants.d.ts +21 -3
  5. package/dist/config/constants.js +33 -6
  6. package/dist/config/pr-checkmate-workflow.yml +33 -327
  7. package/dist/core/checks/dependencies/banned-imports.js +23 -24
  8. package/dist/core/checks/dependencies/circular-deps.js +1 -0
  9. package/dist/core/checks/dependencies/dependency-check.js +1 -0
  10. package/dist/core/checks/dependencies/grype-scan.js +1 -0
  11. package/dist/core/checks/dependencies/npm-audit.js +6 -1
  12. package/dist/core/checks/dependencies/vuln-scan.js +1 -0
  13. package/dist/core/checks/findings.d.ts +198 -19
  14. package/dist/core/checks/findings.js +474 -22
  15. package/dist/core/checks/git/custom-rules.js +21 -16
  16. package/dist/core/checks/git/diff-smell.d.ts +17 -0
  17. package/dist/core/checks/git/diff-smell.js +43 -24
  18. package/dist/core/checks/git/large-files.js +14 -2
  19. package/dist/core/checks/git/leftover-debug.js +23 -14
  20. package/dist/core/checks/git/lockfile-drift.js +2 -1
  21. package/dist/core/checks/git/merge-conflict.js +19 -8
  22. package/dist/core/checks/git/missing-tests.js +22 -6
  23. package/dist/core/checks/git/todo-fixme.js +10 -9
  24. package/dist/core/checks/languages/shellcheck.d.ts +1 -1
  25. package/dist/core/checks/languages/shellcheck.js +1 -1
  26. package/dist/core/checks/languages/typecheck.js +1 -0
  27. package/dist/core/checks/pr/pr-size-check.js +2 -1
  28. package/dist/core/checks/quality/config-validation.d.ts +14 -4
  29. package/dist/core/checks/quality/config-validation.js +119 -17
  30. package/dist/core/checks/quality/dead-code.js +1 -0
  31. package/dist/core/checks/quality/duplicate-check.js +1 -0
  32. package/dist/core/checks/quality/license-header.js +12 -2
  33. package/dist/core/checks/quality/spellcheck.d.ts +50 -0
  34. package/dist/core/checks/quality/spellcheck.js +141 -13
  35. package/dist/core/checks/quality/yaml-lint.js +22 -9
  36. package/dist/core/checks/security/diff-security.js +111 -28
  37. package/dist/core/checks/security/dockerfile-security.js +23 -20
  38. package/dist/core/checks/security/migration-safety.js +19 -17
  39. package/dist/core/checks/security/sensitive-file-guard.js +37 -5
  40. package/dist/core/checks/security/workflow-security.d.ts +10 -0
  41. package/dist/core/checks/security/workflow-security.js +48 -26
  42. package/dist/core/commands.d.ts +27 -0
  43. package/dist/core/commands.js +91 -0
  44. package/dist/core/context.d.ts +12 -3
  45. package/dist/core/context.js +118 -16
  46. package/dist/core/install/cache.d.ts +39 -0
  47. package/dist/core/install/cache.js +99 -0
  48. package/dist/core/install/doctor.d.ts +35 -0
  49. package/dist/core/install/doctor.js +145 -0
  50. package/dist/core/install/ensure.d.ts +60 -0
  51. package/dist/core/install/ensure.js +169 -0
  52. package/dist/core/install/lock.d.ts +33 -0
  53. package/dist/core/install/lock.js +99 -0
  54. package/dist/core/install/profiles.d.ts +64 -0
  55. package/dist/core/install/profiles.js +170 -0
  56. package/dist/core/reporters.d.ts +13 -2
  57. package/dist/core/reporters.js +145 -104
  58. package/dist/core/run-checks.js +91 -14
  59. package/dist/core/targets.js +26 -4
  60. package/dist/core/types.d.ts +49 -1
  61. package/dist/init.d.ts +29 -14
  62. package/dist/init.js +204 -262
  63. package/dist/interfaces/index.d.ts +120 -0
  64. package/dist/scripts/generate-install-manifests.d.ts +39 -0
  65. package/dist/scripts/generate-install-manifests.js +121 -0
  66. package/dist/scripts/publish-github.js +18 -4
  67. package/dist/utils/detect-language.d.ts +37 -4
  68. package/dist/utils/detect-language.js +113 -19
  69. package/dist/utils/http.d.ts +59 -0
  70. package/dist/utils/http.js +119 -0
  71. package/dist/utils/logger.d.ts +52 -6
  72. package/dist/utils/logger.js +125 -33
  73. package/dist/utils/pool.d.ts +49 -0
  74. package/dist/utils/pool.js +124 -0
  75. package/dist/utils/update-notifier.d.ts +9 -0
  76. package/dist/utils/update-notifier.js +57 -3
  77. package/eslint.config.mjs +14 -2
  78. package/install-manifests/commitlint/package-lock.json +1028 -0
  79. package/install-manifests/commitlint/package.json +9 -0
  80. package/install-manifests/core/package-lock.json +1335 -0
  81. package/install-manifests/core/package.json +11 -0
  82. package/install-manifests/cpp/package-lock.json +29 -0
  83. package/install-manifests/cpp/package.json +8 -0
  84. package/install-manifests/duplicate/package-lock.json +113 -0
  85. package/install-manifests/duplicate/package.json +8 -0
  86. package/install-manifests/js/package-lock.json +5099 -0
  87. package/install-manifests/js/package.json +26 -0
  88. package/install-manifests/markdown/package-lock.json +1281 -0
  89. package/install-manifests/markdown/package.json +8 -0
  90. package/install-manifests/python/package-lock.json +21 -0
  91. package/install-manifests/python/package.json +8 -0
  92. package/install-manifests/spellcheck/package-lock.json +1047 -0
  93. package/install-manifests/spellcheck/package.json +8 -0
  94. package/package.json +13 -28
  95. package/pr-checkmate.schema.json +1062 -104
  96. package/src/config/cspell.json +3 -8
  97. package/src/config/pr-checkmate-workflow.yml +33 -327
  98. package/src/config/pr-checkmate.schema.json +1062 -104
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runChecks = runChecks;
4
4
  const utils_1 = require("../utils");
5
+ const pool_1 = require("../utils/pool");
5
6
  const result_collector_1 = require("../utils/result-collector");
6
7
  const context_1 = require("./context");
7
8
  const registry_1 = require("./registry");
@@ -27,13 +28,19 @@ function resolveChecks(opts) {
27
28
  byName.set(c.name, c); // custom wins on name clash
28
29
  return [...byName.values()];
29
30
  }
30
- /** Emit the report via a preset channel or a custom reporter function. */
31
- async function emitReport(reporter, result) {
31
+ /**
32
+ * Emit the report via a preset channel or a custom reporter function.
33
+ *
34
+ * Returns whether delivery succeeded so the caller can honour
35
+ * `reporter.onPostFailure`. A custom function owns its own error handling, so it
36
+ * is always treated as delivered.
37
+ */
38
+ async function emitReport(reporter, result, cfg) {
32
39
  if (typeof reporter === 'function') {
33
40
  await reporter(result);
34
- return;
41
+ return { attempted: false, ok: true };
35
42
  }
36
- await (0, reporters_1.report)(reporter ?? 'stdout', result);
43
+ return (0, reporters_1.report)(reporter ?? 'stdout', result, cfg);
37
44
  }
38
45
  /** Apply only/skip filters to the resolved check set. */
39
46
  function selectChecks(checks, opts) {
@@ -64,9 +71,34 @@ function applySeverity(name, status, ctx) {
64
71
  return 'warn';
65
72
  return status;
66
73
  }
67
- /** Run one check: gate on `applies`, execute, translate throws into `fail`. */
68
- async function runOne(check, ctx, collector) {
74
+ /**
75
+ * Why a `requiresDiff` check could not run, phrased for the person reading the
76
+ * report. A full scan the client asked for is expected; one we fell back to is
77
+ * a configuration problem, and the message says which.
78
+ */
79
+ function noDiffReason(ctx) {
80
+ const scope = ctx.scope;
81
+ if (scope?.degraded)
82
+ return `no diff range (${scope.reason}) — set fetch-depth: 0`;
83
+ return 'full scan — this check reviews a diff';
84
+ }
85
+ /**
86
+ * Run one check: gate on `applies`, execute, translate throws into `fail`.
87
+ *
88
+ * `heavy` admits only a couple of expensive checks at a time, and the per-check
89
+ * timeout means one that never returns costs a warning rather than the run.
90
+ */
91
+ async function runOne(check, ctx, collector, heavy) {
69
92
  try {
93
+ // A diff-only check without a range is a hole in coverage, not an
94
+ // irrelevance: report it as a skip so the gap is visible in the summary.
95
+ if (check.requiresDiff && !ctx.baseSha) {
96
+ const show = ctx.config.run?.reportSkipped ?? 'auto';
97
+ if (show !== 'never' && (await check.applies(ctx))) {
98
+ collector.register(check.name, 'skip', noDiffReason(ctx));
99
+ }
100
+ return;
101
+ }
70
102
  if (!(await check.applies(ctx))) {
71
103
  // A check that doesn't apply is irrelevant to this project/run — e.g. a
72
104
  // language-specific check (SwiftLint, ktlint, Ruff, C++) in a repo of a
@@ -76,7 +108,16 @@ async function runOne(check, ctx, collector) {
76
108
  // from run() (e.g. "no relevant files changed") are still reported.
77
109
  return;
78
110
  }
79
- const outcome = await check.run(ctx);
111
+ const started = Date.now();
112
+ const timeoutMs = ctx.config.run?.checkTimeoutMs ?? 300000;
113
+ const execute = () => (0, pool_1.withTimeout)(check.run(ctx), timeoutMs, () => {
114
+ utils_1.logger.warn(`[runChecks]: ⏱️ ${check.name} exceeded ${timeoutMs}ms`);
115
+ return { status: 'warn', details: `timed out after ${timeoutMs}ms` };
116
+ });
117
+ const outcome = check.weight === 'heavy' ? await heavy.run(execute) : await execute();
118
+ if (ctx.config.run?.timings) {
119
+ utils_1.logger.info(`[runChecks]: ${check.name} took ${Date.now() - started}ms`);
120
+ }
80
121
  collector.register(check.name, applySeverity(check.name, outcome.status, ctx), outcome.details);
81
122
  }
82
123
  catch (err) {
@@ -102,16 +143,52 @@ async function runChecks(opts = {}) {
102
143
  const off = ctx.config.severity ?? {};
103
144
  const selected = selectChecks(resolveChecks(opts), opts).filter(c => off[c.name] !== 'off');
104
145
  const collector = new result_collector_1.ResultCollector();
146
+ // Config Validation verifies that `severity` keys name real checks. It reads
147
+ // the list from here rather than importing the registry, which would make
148
+ // registry → check → registry a cycle.
149
+ ctx.checkNames = resolveChecks(opts).map(c => c.name);
150
+ const limit = (0, pool_1.resolveConcurrency)(ctx.config.run?.concurrency);
151
+ const heavyLimit = Math.max(1, ctx.config.run?.heavyConcurrency ?? 1);
152
+ const heavy = new pool_1.Semaphore(heavyLimit);
105
153
  for (const phase of types_1.PHASES) {
106
154
  const inPhase = selected.filter(c => c.phase === phase);
107
- await Promise.all(inPhase.map(c => runOne(c, ctx, collector)));
155
+ await (0, pool_1.runPool)(inPhase.map(c => () => runOne(c, ctx, collector, heavy)), limit);
108
156
  }
109
- const summary = collector.getSummary();
110
- const result = {
111
- results: collector.getResults(),
112
- summary,
113
- ok: summary.failed === 0,
157
+ reportDegradedScope(ctx, collector);
158
+ const build = () => {
159
+ const summary = collector.getSummary();
160
+ return { results: collector.getResults(), summary, ok: summary.failed === 0 };
114
161
  };
115
- await emitReport(opts.reporter, result);
162
+ const result = build();
163
+ const posted = await emitReport(opts.reporter, result, ctx.config.reporter ?? {});
164
+ // A summary that never reached the PR can matter as much as a finding. The row
165
+ // is added after the report was rendered — the printed table is what the run
166
+ // actually found — and the returned report carries it so the exit code can.
167
+ const onFailure = ctx.config.reporter?.onPostFailure ?? 'warn';
168
+ if (posted.attempted && !posted.ok && onFailure !== 'off') {
169
+ collector.register('Reporting', onFailure === 'error' ? 'fail' : 'warn', posted.error);
170
+ return build();
171
+ }
116
172
  return result;
117
173
  }
174
+ /**
175
+ * Surface a scope that silently narrowed the run.
176
+ *
177
+ * Falling back to a full scan keeps the file-based checks working, but it drops
178
+ * every diff-only check — most of the security surface — and the report gives no
179
+ * sign of it. Outside CI a full scan is simply the default, so this stays quiet
180
+ * there; inside CI it means the range could not be built, which is a
181
+ * configuration problem the client should hear about.
182
+ *
183
+ * `run.onDegradedScope: "error"` turns it into a gate, for repos where losing
184
+ * the security checks silently is worse than a red build.
185
+ */
186
+ function reportDegradedScope(ctx, collector) {
187
+ const mode = ctx.config.run?.onDegradedScope ?? 'warn';
188
+ if (mode === 'off' || !ctx.scope?.degraded || !(0, utils_1.isCiEnvironment)())
189
+ return;
190
+ const dropped = collector.getResults().filter(r => r.status === 'skip').length;
191
+ const detail = `${ctx.scope.reason}; ${dropped} diff-only check(s) did not run — set fetch-depth: 0`;
192
+ utils_1.logger.error(`[runChecks]: ${mode === 'error' ? '❌' : '⚠️'} Degraded scope: ${detail}`);
193
+ collector.register('Scan Scope', mode === 'error' ? 'fail' : 'warn', detail);
194
+ }
@@ -9,6 +9,7 @@ exports.listTrackedFiles = listTrackedFiles;
9
9
  const node_fs_1 = __importDefault(require("node:fs"));
10
10
  const node_path_1 = __importDefault(require("node:path"));
11
11
  const config_1 = require("../config");
12
+ const loader_1 = require("../config/loader");
12
13
  const utils_1 = require("../utils");
13
14
  const execa_1 = require("../utils/execa");
14
15
  /**
@@ -21,6 +22,27 @@ const execa_1 = require("../utils/execa");
21
22
  * keeps the CI dirs (`.github`, `.gitlab`, `.circleci`), which are ignored
22
23
  * globally but hold the workflow files a YAML linter most needs to see.
23
24
  */
25
+ /**
26
+ * Drop files the client excluded by path.
27
+ *
28
+ * Separate from `ignoreDirs`, which matches a directory *name* on any segment:
29
+ * that cannot express "this one file" and cannot express "this one path" —
30
+ * `ignoreDirs: ["generated"]` silences every `generated/` in the repository, not
31
+ * the one that is actually generated. Globs answer both, and because this sits
32
+ * in the one function every file-scanning check calls, a client writes the rule
33
+ * once instead of hunting for the right key on each check.
34
+ */
35
+ function excludeConfiguredPaths(files) {
36
+ let patterns = [];
37
+ try {
38
+ patterns = (0, loader_1.loadProjectConfig)().excludePaths ?? [];
39
+ }
40
+ catch {
41
+ // A config that cannot be read is the loader's problem to report, not a
42
+ // reason to scan nothing.
43
+ }
44
+ return patterns.length > 0 ? files.filter(f => !(0, utils_1.matchesAnyGlob)(f, patterns)) : files;
45
+ }
24
46
  function excludeIgnoredDirs(files, keepDirs = []) {
25
47
  const ignored = new Set((0, config_1.getIgnoredDirs)());
26
48
  for (const dir of keepDirs)
@@ -60,10 +82,10 @@ async function resolveTargetFiles(ctx, globs, opts = {}) {
60
82
  stdout = (await (0, execa_1.execa)('git', args, { cwd: ctx.cwd, reject: false })).stdout;
61
83
  ctx.cache?.set(cacheKey, stdout);
62
84
  }
63
- const files = excludeIgnoredDirs(stdout
85
+ const files = excludeConfiguredPaths(excludeIgnoredDirs(stdout
64
86
  .split('\n')
65
87
  .map(f => f.trim())
66
- .filter(Boolean), opts.keepDirs).filter(f => node_fs_1.default.existsSync(node_path_1.default.join(ctx.cwd, f)));
88
+ .filter(Boolean), opts.keepDirs)).filter(f => node_fs_1.default.existsSync(node_path_1.default.join(ctx.cwd, f)));
67
89
  utils_1.logger.info(`[targets]: ${ctx.baseSha ? '📂 Delta' : 'Full scan'}: ${files.length} file(s) for ${globs.join(', ')}`);
68
90
  return files;
69
91
  }
@@ -103,10 +125,10 @@ async function resolveScopedTargetFiles(ctx, globs, sourcePaths) {
103
125
  async function listTrackedFiles(ctx, globs, sourcePaths) {
104
126
  try {
105
127
  const { stdout } = await (0, execa_1.execa)('git', ['ls-files', ...globs], { cwd: ctx.cwd, reject: false });
106
- const files = excludeIgnoredDirs(stdout
128
+ const files = excludeConfiguredPaths(excludeIgnoredDirs(stdout
107
129
  .split('\n')
108
130
  .map(f => f.trim())
109
- .filter(Boolean));
131
+ .filter(Boolean)));
110
132
  return scopeToSourcePaths(files, sourcePaths);
111
133
  }
112
134
  catch (err) {
@@ -1,4 +1,4 @@
1
- import type { PRCheckMateConfig } from '../interfaces';
1
+ import type { PRCheckMateConfig, ReporterConfig } from '../interfaces';
2
2
  import type { Language } from '../utils/detect-language';
3
3
  import type { CheckResult, CheckStatus } from '../utils/result-collector';
4
4
  export type { CheckResult, CheckStatus, Language };
@@ -8,6 +8,21 @@ export type { CheckResult, CheckStatus, Language };
8
8
  */
9
9
  export type Phase = 'blocking' | 'informational' | 'format';
10
10
  export declare const PHASES: readonly Phase[];
11
+ /**
12
+ * What this run is looking at, and whether that is what was asked for.
13
+ *
14
+ * `degraded` is the field that earns this its own type: a full scan requested by
15
+ * a human and a full scan we fell back to because the PR base was missing are
16
+ * indistinguishable in the results — both just omit every delta-only check — but
17
+ * only one of them is a problem worth telling anyone about.
18
+ */
19
+ export interface RunScope {
20
+ kind: 'delta' | 'full' | 'staged';
21
+ /** Short explanation for the log line, e.g. `PR base unavailable`. */
22
+ reason?: string;
23
+ /** True when a diff range was wanted but could not be built. */
24
+ degraded: boolean;
25
+ }
11
26
  /**
12
27
  * Everything a check needs to run. Assembled once by `buildContext` and shared
13
28
  * across all checks — no check reads `process.cwd()` or `process.env` directly.
@@ -24,6 +39,17 @@ export interface CheckContext {
24
39
  /** Diff range for delta-aware checks; undefined → full-repo scan. */
25
40
  baseSha?: string;
26
41
  headSha?: string;
42
+ /** What this run is looking at, and why. Optional so hand-built contexts stay terse. */
43
+ scope?: RunScope;
44
+ /**
45
+ * Display names of the checks in this run, for the one check that reasons about
46
+ * the others (Config Validation, verifying `severity` keys).
47
+ *
48
+ * Passed down rather than imported: a check importing the registry would close
49
+ * the loop registry → check → registry, and it also lets custom checks supplied
50
+ * through `RunOptions.checks` be validated like built-in ones.
51
+ */
52
+ checkNames?: string[];
27
53
  /**
28
54
  * Per-run memoization cache for identical git invocations (many checks diff
29
55
  * the same range). Created once per `runChecks`; safe because git state is
@@ -45,12 +71,34 @@ export interface CheckOutcome {
45
71
  export interface Check {
46
72
  name: string;
47
73
  phase: Phase;
74
+ /**
75
+ * The check reviews a diff and has nothing to say without one. Declared here
76
+ * rather than folded into `applies` so the orchestrator can tell the two kinds
77
+ * of "not applicable" apart:
78
+ *
79
+ * - a check that does not apply (SwiftLint in a Python repo) is noise, and is
80
+ * left out of the report entirely;
81
+ * - a check that *would* have applied but had no diff range is a gap in
82
+ * coverage, and is reported as a skip with the reason.
83
+ *
84
+ * Before this existed, both simply vanished — so a shallow clone removed most
85
+ * of the security surface and still printed a clean, complete-looking report.
86
+ */
87
+ requiresDiff?: boolean;
88
+ /**
89
+ * The check spawns something expensive — a whole-project analyser like knip,
90
+ * jscpd, dpdm, tsc or grype. The orchestrator admits only a couple of these at
91
+ * once, independently of the overall concurrency limit: four regex scans in
92
+ * parallel are free, four project-wide analysers are not.
93
+ */
94
+ weight?: 'heavy';
48
95
  applies(ctx: CheckContext): boolean | Promise<boolean>;
49
96
  run(ctx: CheckContext): Promise<CheckOutcome>;
50
97
  }
51
98
  export type ReporterKind = 'none' | 'stdout' | 'github' | 'gitlab' | 'bitbucket' | 'auto';
52
99
  /** Custom reporter: receives the final report to emit however the consumer wants. */
53
100
  export type ReporterFn = (report: CheckReport) => void | Promise<void>;
101
+ export type { ReporterConfig };
54
102
  export interface RunOptions {
55
103
  cwd?: string;
56
104
  /** Override language detection (e.g. PRValidator passes its already-detected type). */
package/dist/init.d.ts CHANGED
@@ -1,23 +1,38 @@
1
+ /** How strictly the generated workflow treats a failed run. */
2
+ type GateMode = 'strict' | 'advisory';
1
3
  /**
2
- * Merge current defaults into an existing config, recursively.
4
+ * Write the bundled GitHub Actions workflow into the consumer repo.
3
5
  *
4
- * The user's value always wins, so hand-tuned settings survive an `init` re-run,
5
- * while every new default field — at any nesting depth — gets added. Arrays are
6
- * replaced wholesale rather than concatenated: lists like `ignoreDirs` or
7
- * `cspell.words` are meant to be edited, and merging them would resurrect entries
8
- * the user deliberately removed. {@link REPLACED_OBJECT_PATHS} extends that rule to
9
- * the object-shaped lists.
6
+ * Never overwrites an existing file. `init` is not a one-time command — the
7
+ * update notice asks people to re-run it after every upgrade — so clobbering
8
+ * would quietly discard whatever they had tuned, including the gate setting they
9
+ * were just asked about.
10
+ */
11
+ export declare function setupWorkflow(root: string, mode: GateMode): void;
12
+ /**
13
+ * Every check that fails the run out of the box, written into the generated
14
+ * config at its real default.
15
+ *
16
+ * Not a copy of a default for its own sake — this one is the gate's teeth, and
17
+ * the client is entitled to see which checks can stop their merge without
18
+ * reading our source or discovering it from a red pipeline. Written as `"error"`
19
+ * so the edit is in place: change the value, or delete the line to inherit
20
+ * whatever we ship next.
10
21
  *
11
- * Informational `//`-prefixed keys are the one exception — they are documentation,
12
- * not settings, so the refreshed default text wins whenever a default exists.
22
+ * Two things are deliberately absent. `Custom Rules` and `Banned Imports` can
23
+ * block too, but only for rules the client writes themselves, so listing them
24
+ * would suggest a gate that is inert until they act. And `Dockerfile Security`
25
+ * looks like it belongs here and does not: every one of its patterns is rated
26
+ * `warn`, so it never fails on its own.
13
27
  *
14
- * @param defaults Current defaults for this level of the config tree.
15
- * @param user The existing pr-checkmate.json content for the same level.
16
- * @param path Dot-joined position of `defaults` in the config tree, used to match
17
- * {@link REPLACED_OBJECT_PATHS}. Internal to the recursion; callers pass nothing.
28
+ * Keep in step with the checks' own defaults — `blocking-checks.test.ts` pins
29
+ * every name here to the registry, which catches a rename but not a change of
30
+ * heart about what should block.
18
31
  */
19
- export declare function mergeWithDefaults(defaults: Record<string, unknown>, user: Record<string, unknown>, path?: string): Record<string, unknown>;
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
+ export declare function buildInitialConfig(sourcePath: string, languages: string[]): Record<string, unknown>;
20
34
  /**
21
35
  * Initialize (or refresh) pr-checkmate configuration in the current project.
22
36
  */
23
37
  export declare function init(): Promise<void>;
38
+ export {};