@shrkcrft/quality-gates 0.1.0-alpha.21 → 0.1.0-alpha.23
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/dist/gates/arch-gate.d.ts +7 -3
- package/dist/gates/arch-gate.d.ts.map +1 -1
- package/dist/gates/arch-gate.js +31 -9
- package/dist/gates/impact-gate.d.ts +16 -4
- package/dist/gates/impact-gate.d.ts.map +1 -1
- package/dist/gates/impact-gate.js +34 -11
- package/dist/gates/knowledge-symbol-gate.d.ts +27 -0
- package/dist/gates/knowledge-symbol-gate.d.ts.map +1 -0
- package/dist/gates/knowledge-symbol-gate.js +80 -0
- package/dist/gates/policy-lint-gate.d.ts +25 -0
- package/dist/gates/policy-lint-gate.d.ts.map +1 -0
- package/dist/gates/policy-lint-gate.js +80 -0
- package/dist/gates/wiring-gate.d.ts +23 -0
- package/dist/gates/wiring-gate.d.ts.map +1 -0
- package/dist/gates/wiring-gate.js +75 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/runner/run-gates.d.ts +12 -0
- package/dist/runner/run-gates.d.ts.map +1 -1
- package/dist/runner/run-gates.js +12 -0
- package/package.json +10 -9
|
@@ -9,9 +9,13 @@ import type { IGateResult } from '../schema/quality-gate.js';
|
|
|
9
9
|
* This stops the gate from being a perpetual red on baseline debt the current
|
|
10
10
|
* diff never introduced (an agent learns to ignore a gate that's always red).
|
|
11
11
|
*
|
|
12
|
-
* When no baseline is frozen
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* When no baseline is frozen, errors are reported as `warn` (not `fail`) so the
|
|
13
|
+
* gate isn't a perpetual red on inherited debt the current diff never
|
|
14
|
+
* introduced — an agent learns to ignore a gate that's always red. `--strict`
|
|
15
|
+
* still escalates the warn to a failure for CI, and freezing a baseline switches
|
|
16
|
+
* on NEW-only gating. When `baselineRelative: false` (the `--arch-all` opt-in),
|
|
17
|
+
* the gate fails on ANY error regardless of the baseline, keeping a clean-tree
|
|
18
|
+
* CI demand expressible.
|
|
15
19
|
*
|
|
16
20
|
* Warnings never fail the gate; they are reported as `warn`.
|
|
17
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arch-gate.d.ts","sourceRoot":"","sources":["../../src/gates/arch-gate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D
|
|
1
|
+
{"version":3,"file":"arch-gate.d.ts","sourceRoot":"","sources":["../../src/gates/arch-gate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,WAAW,CA+GzF"}
|
package/dist/gates/arch-gate.js
CHANGED
|
@@ -8,9 +8,13 @@ import { ArchReportStore, diffSnapshots, runArchCheck, snapshotFromReport, viola
|
|
|
8
8
|
* This stops the gate from being a perpetual red on baseline debt the current
|
|
9
9
|
* diff never introduced (an agent learns to ignore a gate that's always red).
|
|
10
10
|
*
|
|
11
|
-
* When no baseline is frozen
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* When no baseline is frozen, errors are reported as `warn` (not `fail`) so the
|
|
12
|
+
* gate isn't a perpetual red on inherited debt the current diff never
|
|
13
|
+
* introduced — an agent learns to ignore a gate that's always red. `--strict`
|
|
14
|
+
* still escalates the warn to a failure for CI, and freezing a baseline switches
|
|
15
|
+
* on NEW-only gating. When `baselineRelative: false` (the `--arch-all` opt-in),
|
|
16
|
+
* the gate fails on ANY error regardless of the baseline, keeping a clean-tree
|
|
17
|
+
* CI demand expressible.
|
|
14
18
|
*
|
|
15
19
|
* Warnings never fail the gate; they are reported as `warn`.
|
|
16
20
|
*/
|
|
@@ -71,16 +75,34 @@ export function archGate(projectRoot, options = {}) {
|
|
|
71
75
|
durationMs: Date.now() - start,
|
|
72
76
|
};
|
|
73
77
|
}
|
|
74
|
-
// No baseline
|
|
75
|
-
//
|
|
78
|
+
// No baseline available: either none is frozen (the default state of a fresh
|
|
79
|
+
// repo) or the caller disabled baseline-relative gating via `--arch-all`.
|
|
76
80
|
if (errors > 0) {
|
|
81
|
+
if (options.baselineRelative === false) {
|
|
82
|
+
// Explicit opt-in (`--arch-all`): fail on TOTAL errors so a clean-tree CI
|
|
83
|
+
// demand stays expressible.
|
|
84
|
+
return {
|
|
85
|
+
id: 'arch',
|
|
86
|
+
label: 'Architecture',
|
|
87
|
+
status: 'fail',
|
|
88
|
+
message: `${errors} architecture error(s).`,
|
|
89
|
+
details: { errors, warnings, kinds: report.countsByKind },
|
|
90
|
+
nextCommands: ['shrk arch check', 'shrk arch baseline write'],
|
|
91
|
+
durationMs: Date.now() - start,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Default: no baseline frozen. Don't hard-fail on pre-existing debt the
|
|
95
|
+
// current diff never introduced — warn (so the signal stays visible) and
|
|
96
|
+
// point at freezing a baseline to switch on NEW-only gating. `--strict`
|
|
97
|
+
// still turns this warn into a hard failure for CI, and `--arch-all` fails
|
|
98
|
+
// on the total.
|
|
77
99
|
return {
|
|
78
100
|
id: 'arch',
|
|
79
101
|
label: 'Architecture',
|
|
80
|
-
status: '
|
|
81
|
-
message: `${errors} architecture error(s).`,
|
|
82
|
-
details: { errors, warnings, kinds: report.countsByKind },
|
|
83
|
-
nextCommands: ['shrk arch
|
|
102
|
+
status: 'warn',
|
|
103
|
+
message: `${errors} architecture error(s), no baseline frozen — not failing the gate (freeze one with \`shrk arch baseline write\` to track regressions; use \`--arch-all\` or \`--strict\` to fail).`,
|
|
104
|
+
details: { errors, warnings, kinds: report.countsByKind, noBaseline: true },
|
|
105
|
+
nextCommands: ['shrk arch baseline write', 'shrk arch check'],
|
|
84
106
|
durationMs: Date.now() - start,
|
|
85
107
|
};
|
|
86
108
|
}
|
|
@@ -4,12 +4,24 @@ export interface IImpactGateOptions {
|
|
|
4
4
|
sinceRef?: string;
|
|
5
5
|
/** Risk levels that fail the gate. Default ['critical']. */
|
|
6
6
|
failOn?: readonly ('high' | 'critical')[];
|
|
7
|
+
/**
|
|
8
|
+
* Explicit changed-file set to analyze. Used by `--changed-only` / `--staged`
|
|
9
|
+
* / `--files` when no `sinceRef` gitref is given. Ignored when `sinceRef` is
|
|
10
|
+
* set (the gitref diff wins). An empty array yields the `skipped` path.
|
|
11
|
+
*/
|
|
12
|
+
files?: readonly string[];
|
|
7
13
|
}
|
|
8
14
|
/**
|
|
9
|
-
* Impact-engine gate.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
15
|
+
* Impact-engine gate. Analyzes the changeset and runs `analyzeGraphImpact`.
|
|
16
|
+
* When `files` is provided (and no `sinceRef`), the given changed-file set is
|
|
17
|
+
* analyzed directly; otherwise `git diff --name-only` is run against `sinceRef`
|
|
18
|
+
* (default 'main').
|
|
19
|
+
*
|
|
20
|
+
* Failure is THRESHOLD-based, not exact set-membership: the gate ranks
|
|
21
|
+
* low<medium<high<critical and fails when the computed risk is at least as
|
|
22
|
+
* severe as the *least* severe entry in `failOn`. So `--fail-on high` also
|
|
23
|
+
* fails a `critical` change. With the default `['critical']`, `critical` fails
|
|
24
|
+
* and `high` warns. Skipped when no files changed or the graph isn't indexed.
|
|
13
25
|
*/
|
|
14
26
|
export declare function impactGate(projectRoot: string, options?: IImpactGateOptions): IGateResult;
|
|
15
27
|
//# sourceMappingURL=impact-gate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impact-gate.d.ts","sourceRoot":"","sources":["../../src/gates/impact-gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"impact-gate.d.ts","sourceRoot":"","sources":["../../src/gates/impact-gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC;IAC1C;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAcD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAyD7F"}
|
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
import { analyzeGraphImpact } from '@shrkcrft/impact-engine';
|
|
2
|
+
/** low < medium < high < critical — used for threshold comparison. */
|
|
3
|
+
const RISK_RANK = {
|
|
4
|
+
low: 0,
|
|
5
|
+
medium: 1,
|
|
6
|
+
high: 2,
|
|
7
|
+
critical: 3,
|
|
8
|
+
};
|
|
9
|
+
function rankOf(risk) {
|
|
10
|
+
return RISK_RANK[risk] ?? 0;
|
|
11
|
+
}
|
|
2
12
|
/**
|
|
3
|
-
* Impact-engine gate.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
13
|
+
* Impact-engine gate. Analyzes the changeset and runs `analyzeGraphImpact`.
|
|
14
|
+
* When `files` is provided (and no `sinceRef`), the given changed-file set is
|
|
15
|
+
* analyzed directly; otherwise `git diff --name-only` is run against `sinceRef`
|
|
16
|
+
* (default 'main').
|
|
17
|
+
*
|
|
18
|
+
* Failure is THRESHOLD-based, not exact set-membership: the gate ranks
|
|
19
|
+
* low<medium<high<critical and fails when the computed risk is at least as
|
|
20
|
+
* severe as the *least* severe entry in `failOn`. So `--fail-on high` also
|
|
21
|
+
* fails a `critical` change. With the default `['critical']`, `critical` fails
|
|
22
|
+
* and `high` warns. Skipped when no files changed or the graph isn't indexed.
|
|
7
23
|
*/
|
|
8
24
|
export function impactGate(projectRoot, options = {}) {
|
|
9
25
|
const start = Date.now();
|
|
26
|
+
const failOn = options.failOn && options.failOn.length > 0 ? options.failOn : ['critical'];
|
|
27
|
+
const failThreshold = Math.min(...failOn.map((f) => rankOf(f)));
|
|
28
|
+
// Scope: an explicit changed-file set (when no gitref is given) is analyzed
|
|
29
|
+
// directly; otherwise diff against the gitref (default 'main').
|
|
30
|
+
const useFiles = !options.sinceRef && options.files !== undefined;
|
|
10
31
|
const sinceRef = options.sinceRef ?? 'main';
|
|
11
|
-
const
|
|
12
|
-
const analysis =
|
|
32
|
+
const label = useFiles ? 'Impact (changed files)' : 'Impact (since ' + sinceRef + ')';
|
|
33
|
+
const analysis = useFiles
|
|
34
|
+
? analyzeGraphImpact({ kind: 'files', files: options.files ?? [] }, { projectRoot })
|
|
35
|
+
: analyzeGraphImpact({ kind: 'gitref', ref: sinceRef }, { projectRoot });
|
|
13
36
|
if (analysis.diagnostics.some((d) => d.includes('code-graph store missing'))) {
|
|
14
37
|
return {
|
|
15
38
|
id: 'impact',
|
|
16
|
-
label
|
|
39
|
+
label,
|
|
17
40
|
status: 'skipped',
|
|
18
41
|
message: 'Skipped — graph index missing.',
|
|
19
42
|
nextCommands: ['shrk graph index'],
|
|
@@ -23,13 +46,13 @@ export function impactGate(projectRoot, options = {}) {
|
|
|
23
46
|
if (analysis.normalizedTargets.length === 0) {
|
|
24
47
|
return {
|
|
25
48
|
id: 'impact',
|
|
26
|
-
label
|
|
49
|
+
label,
|
|
27
50
|
status: 'skipped',
|
|
28
|
-
message: `No files changed since ${sinceRef}.`,
|
|
51
|
+
message: useFiles ? 'No files changed.' : `No files changed since ${sinceRef}.`,
|
|
29
52
|
durationMs: Date.now() - start,
|
|
30
53
|
};
|
|
31
54
|
}
|
|
32
|
-
const status =
|
|
55
|
+
const status = rankOf(analysis.risk) >= failThreshold ? 'fail' : analysis.risk === 'high' ? 'warn' : 'pass';
|
|
33
56
|
const message = status === 'fail'
|
|
34
57
|
? `Risk: ${analysis.risk}. ${analysis.directDependents.length} direct dependents.`
|
|
35
58
|
: status === 'warn'
|
|
@@ -37,7 +60,7 @@ export function impactGate(projectRoot, options = {}) {
|
|
|
37
60
|
: `Risk: ${analysis.risk}. Looks safe.`;
|
|
38
61
|
return {
|
|
39
62
|
id: 'impact',
|
|
40
|
-
label
|
|
63
|
+
label,
|
|
41
64
|
status,
|
|
42
65
|
message,
|
|
43
66
|
details: {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ISharkcraftInspection } from '@shrkcrft/inspector';
|
|
2
|
+
import type { IGateResult } from '../schema/quality-gate.js';
|
|
3
|
+
export interface IKnowledgeSymbolGateOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Pre-loaded inspection (knowledge entries + project root). Loading the
|
|
6
|
+
* inspection is async, so the caller (the gate command) builds it and
|
|
7
|
+
* injects it here. The gate is skipped when omitted.
|
|
8
|
+
*/
|
|
9
|
+
inspection?: ISharkcraftInspection;
|
|
10
|
+
/** Restrict to entries whose references touch one of these changed files. */
|
|
11
|
+
changedFiles?: readonly string[];
|
|
12
|
+
/**
|
|
13
|
+
* When true (default), a moved / renamed / missing symbol or file ref fails
|
|
14
|
+
* the gate; otherwise it warns.
|
|
15
|
+
*/
|
|
16
|
+
failOnStale?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Knowledge symbol-ref integrity gate. Walks every knowledge entry's symbol
|
|
20
|
+
* and file references and verifies each still resolves. Resolution is
|
|
21
|
+
* graph-backed: when the code graph is indexed it is passed to the stale-check
|
|
22
|
+
* so a *moved* symbol (now declared in a different file) is detected as stale
|
|
23
|
+
* rather than silently passing — single-file AST cannot see that. Skipped when
|
|
24
|
+
* no inspection is supplied or there are no symbol/file references in scope.
|
|
25
|
+
*/
|
|
26
|
+
export declare function knowledgeSymbolGate(projectRoot: string, options?: IKnowledgeSymbolGateOptions): IGateResult;
|
|
27
|
+
//# sourceMappingURL=knowledge-symbol-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-symbol-gate.d.ts","sourceRoot":"","sources":["../../src/gates/knowledge-symbol-gate.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAK7D,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,UAAU,CAAC,EAAE,qBAAqB,CAAC;IACnC,6EAA6E;IAC7E,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,2BAAgC,GACxC,WAAW,CA0Eb"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { loadGraphApiCached } from '@shrkcrft/graph';
|
|
2
|
+
import { buildKnowledgeStaleReport, ReferenceCheckOutcome, } from '@shrkcrft/inspector';
|
|
3
|
+
/** Reference kinds this gate is responsible for (symbol-ref integrity). */
|
|
4
|
+
const SCOPED_REF_KINDS = new Set(['symbol', 'file']);
|
|
5
|
+
/**
|
|
6
|
+
* Knowledge symbol-ref integrity gate. Walks every knowledge entry's symbol
|
|
7
|
+
* and file references and verifies each still resolves. Resolution is
|
|
8
|
+
* graph-backed: when the code graph is indexed it is passed to the stale-check
|
|
9
|
+
* so a *moved* symbol (now declared in a different file) is detected as stale
|
|
10
|
+
* rather than silently passing — single-file AST cannot see that. Skipped when
|
|
11
|
+
* no inspection is supplied or there are no symbol/file references in scope.
|
|
12
|
+
*/
|
|
13
|
+
export function knowledgeSymbolGate(projectRoot, options = {}) {
|
|
14
|
+
const start = Date.now();
|
|
15
|
+
const inspection = options.inspection;
|
|
16
|
+
if (!inspection) {
|
|
17
|
+
return {
|
|
18
|
+
id: 'knowledge-symbol',
|
|
19
|
+
label: 'Knowledge symbol refs',
|
|
20
|
+
status: 'skipped',
|
|
21
|
+
message: 'Skipped — no knowledge inspection supplied.',
|
|
22
|
+
durationMs: Date.now() - start,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (inspection.knowledgeEntries.length === 0) {
|
|
26
|
+
return {
|
|
27
|
+
id: 'knowledge-symbol',
|
|
28
|
+
label: 'Knowledge symbol refs',
|
|
29
|
+
status: 'skipped',
|
|
30
|
+
message: 'No knowledge entries — nothing to verify.',
|
|
31
|
+
durationMs: Date.now() - start,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Graph-resolved when available; null falls the stale-check back to AST.
|
|
35
|
+
const graph = loadGraphApiCached(projectRoot) ?? undefined;
|
|
36
|
+
const report = buildKnowledgeStaleReport(inspection, {
|
|
37
|
+
...(options.changedFiles ? { changedFiles: options.changedFiles } : {}),
|
|
38
|
+
...(graph ? { graph } : {}),
|
|
39
|
+
});
|
|
40
|
+
const scoped = report.referenceChecks.filter((c) => SCOPED_REF_KINDS.has(c.reference.kind));
|
|
41
|
+
const evaluated = scoped.length;
|
|
42
|
+
if (evaluated === 0) {
|
|
43
|
+
return {
|
|
44
|
+
id: 'knowledge-symbol',
|
|
45
|
+
label: 'Knowledge symbol refs',
|
|
46
|
+
status: 'skipped',
|
|
47
|
+
message: 'No symbol/file references in scope — nothing evaluated.',
|
|
48
|
+
details: { evaluated: 0, graphResolved: Boolean(graph) },
|
|
49
|
+
durationMs: Date.now() - start,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const broken = scoped.filter((c) => c.outcome === ReferenceCheckOutcome.Stale || c.outcome === ReferenceCheckOutcome.Missing);
|
|
53
|
+
if (broken.length === 0) {
|
|
54
|
+
return {
|
|
55
|
+
id: 'knowledge-symbol',
|
|
56
|
+
label: 'Knowledge symbol refs',
|
|
57
|
+
status: 'pass',
|
|
58
|
+
message: `${evaluated} symbol/file reference(s) resolve.`,
|
|
59
|
+
details: { evaluated, graphResolved: Boolean(graph) },
|
|
60
|
+
durationMs: Date.now() - start,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const samples = broken.slice(0, 8).map((c) => {
|
|
64
|
+
const target = c.reference.symbol
|
|
65
|
+
? `symbol \`${c.reference.symbol}\``
|
|
66
|
+
: (c.reference.path ?? '?');
|
|
67
|
+
const where = c.reference.path && c.reference.symbol ? ` (${c.reference.path})` : '';
|
|
68
|
+
return `${c.entryId}: ${target}${where} — ${c.message}`;
|
|
69
|
+
});
|
|
70
|
+
const failOnStale = options.failOnStale ?? true;
|
|
71
|
+
return {
|
|
72
|
+
id: 'knowledge-symbol',
|
|
73
|
+
label: 'Knowledge symbol refs',
|
|
74
|
+
status: failOnStale ? 'fail' : 'warn',
|
|
75
|
+
message: `${broken.length}/${evaluated} symbol/file reference(s) stale or missing (moved/renamed).`,
|
|
76
|
+
details: { evaluated, broken: broken.length, samples, graphResolved: Boolean(graph) },
|
|
77
|
+
nextCommands: ['shrk knowledge audit', 'shrk doctor'],
|
|
78
|
+
durationMs: Date.now() - start,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IPolicyRule } from '@shrkcrft/core';
|
|
2
|
+
import type { IGateResult } from '../schema/quality-gate.js';
|
|
3
|
+
export interface IPolicyLintGateOptions {
|
|
4
|
+
/** The project's policy rules (from `sharkcraft.config.ts` `policyRules[]`). */
|
|
5
|
+
rules?: readonly IPolicyRule[];
|
|
6
|
+
/** Restrict to rules whose globs match one of these (project-relative) changed files. */
|
|
7
|
+
changedFiles?: readonly string[];
|
|
8
|
+
/** When true, only run rules touched by `changedFiles`. */
|
|
9
|
+
changedOnly?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Set when the project config could not be loaded/validated. The gate surfaces
|
|
12
|
+
* it (warn) instead of silently skipping — a malformed config must not quietly
|
|
13
|
+
* disable the policy plane.
|
|
14
|
+
*/
|
|
15
|
+
configError?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The "policy plane" gate: runs the project's data-defined policy-lint rules
|
|
19
|
+
* (template / markup / stylesheet / AOT-invisible TS surfaces that tsc cannot
|
|
20
|
+
* see). Skipped — never red — when no rules are configured, so it's inert for
|
|
21
|
+
* projects that don't opt in. Honors the loud-zero contract: rules that exist
|
|
22
|
+
* but fall out of the changed-only scope report `skipped`, never a silent pass.
|
|
23
|
+
*/
|
|
24
|
+
export declare function policyLintGate(projectRoot: string, options?: IPolicyLintGateOptions): IGateResult;
|
|
25
|
+
//# sourceMappingURL=policy-lint-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-lint-gate.d.ts","sourceRoot":"","sources":["../../src/gates/policy-lint-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,sBAAsB;IACrC,gFAAgF;IAChF,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,yFAAyF;IACzF,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,WAAW,CA2ErG"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { runPolicyLint } from '@shrkcrft/boundaries';
|
|
2
|
+
/**
|
|
3
|
+
* The "policy plane" gate: runs the project's data-defined policy-lint rules
|
|
4
|
+
* (template / markup / stylesheet / AOT-invisible TS surfaces that tsc cannot
|
|
5
|
+
* see). Skipped — never red — when no rules are configured, so it's inert for
|
|
6
|
+
* projects that don't opt in. Honors the loud-zero contract: rules that exist
|
|
7
|
+
* but fall out of the changed-only scope report `skipped`, never a silent pass.
|
|
8
|
+
*/
|
|
9
|
+
export function policyLintGate(projectRoot, options = {}) {
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
if (options.configError) {
|
|
12
|
+
return {
|
|
13
|
+
id: 'policy',
|
|
14
|
+
label: 'Policy lint',
|
|
15
|
+
status: 'warn',
|
|
16
|
+
message: `Config could not be loaded — policy rules not evaluated: ${options.configError}`,
|
|
17
|
+
nextCommands: ['shrk doctor'],
|
|
18
|
+
durationMs: Date.now() - start,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const rules = options.rules ?? [];
|
|
22
|
+
if (rules.length === 0) {
|
|
23
|
+
return {
|
|
24
|
+
id: 'policy',
|
|
25
|
+
label: 'Policy lint',
|
|
26
|
+
status: 'skipped',
|
|
27
|
+
message: 'No policy rules configured (sharkcraft.config.ts policyRules[]).',
|
|
28
|
+
durationMs: Date.now() - start,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const report = runPolicyLint(projectRoot, rules, {
|
|
32
|
+
...(options.changedOnly ? { changedOnly: true, changedFiles: options.changedFiles ?? [] } : {}),
|
|
33
|
+
});
|
|
34
|
+
// Loud zero case: rules exist but none actually scanned a file (their globs
|
|
35
|
+
// matched no files — e.g. a `style` rule in a project with no stylesheets — or
|
|
36
|
+
// `--changed-only` filtered them all out). Surface it as skipped rather than a
|
|
37
|
+
// silent green pass.
|
|
38
|
+
if (report.rules.length === 0 || report.evaluated === 0) {
|
|
39
|
+
return {
|
|
40
|
+
id: 'policy',
|
|
41
|
+
label: 'Policy lint',
|
|
42
|
+
status: 'skipped',
|
|
43
|
+
message: 'No policy rules in scope — nothing evaluated.',
|
|
44
|
+
details: { evaluated: 0 },
|
|
45
|
+
durationMs: Date.now() - start,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const errors = report.findings.filter((f) => f.severity === 'error').length;
|
|
49
|
+
const warnings = report.findings.filter((f) => f.severity === 'warning').length;
|
|
50
|
+
const samples = report.findings
|
|
51
|
+
.slice(0, 8)
|
|
52
|
+
.map((f) => `${f.ruleId}: ${f.match} (${f.file}:${f.line})`);
|
|
53
|
+
const diagnostics = report.diagnostics;
|
|
54
|
+
if (report.verdict === 'pass') {
|
|
55
|
+
return {
|
|
56
|
+
id: 'policy',
|
|
57
|
+
label: 'Policy lint',
|
|
58
|
+
status: 'pass',
|
|
59
|
+
message: `${report.rules.length} policy rule(s) — no violations.`,
|
|
60
|
+
details: { rules: report.rules.length, evaluated: report.evaluated },
|
|
61
|
+
durationMs: Date.now() - start,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const misconfig = diagnostics.length > 0 ? `, ${diagnostics.length} misconfigured rule(s)` : '';
|
|
65
|
+
return {
|
|
66
|
+
id: 'policy',
|
|
67
|
+
label: 'Policy lint',
|
|
68
|
+
status: report.verdict === 'errors' ? 'fail' : 'warn',
|
|
69
|
+
message: `${errors} error(s), ${warnings} warning(s)${misconfig}: policy violation(s).`,
|
|
70
|
+
details: {
|
|
71
|
+
errors,
|
|
72
|
+
warnings,
|
|
73
|
+
samples,
|
|
74
|
+
evaluated: report.evaluated,
|
|
75
|
+
...(diagnostics.length > 0 ? { diagnostics } : {}),
|
|
76
|
+
},
|
|
77
|
+
nextCommands: ['shrk policy-lint'],
|
|
78
|
+
durationMs: Date.now() - start,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IWiringRule } from '@shrkcrft/core';
|
|
2
|
+
import type { IGateResult } from '../schema/quality-gate.js';
|
|
3
|
+
export interface IWiringGateOptions {
|
|
4
|
+
/** The project's wiring rules (from `sharkcraft.config.ts` `wiringRules[]`). */
|
|
5
|
+
rules?: readonly IWiringRule[];
|
|
6
|
+
/** Restrict to rules touched by these (project-relative) changed files. */
|
|
7
|
+
changedFiles?: readonly string[];
|
|
8
|
+
/** When true, only run rules touched by `changedFiles`. */
|
|
9
|
+
changedOnly?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Set when the project config could not be loaded/validated. The gate surfaces
|
|
12
|
+
* it (warn) instead of silently skipping — a malformed config must not quietly
|
|
13
|
+
* disable the wiring plane.
|
|
14
|
+
*/
|
|
15
|
+
configError?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The "completeness plane" gate: runs the project's data-defined wiring rules
|
|
19
|
+
* (declared token set ⊆ registered token set). Skipped — never red — when no
|
|
20
|
+
* rules are configured, so it's inert for projects that don't opt in.
|
|
21
|
+
*/
|
|
22
|
+
export declare function wiringGate(projectRoot: string, options?: IWiringGateOptions): IGateResult;
|
|
23
|
+
//# sourceMappingURL=wiring-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiring-gate.d.ts","sourceRoot":"","sources":["../../src/gates/wiring-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAwE7F"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { runWiring } from '@shrkcrft/boundaries';
|
|
2
|
+
/**
|
|
3
|
+
* The "completeness plane" gate: runs the project's data-defined wiring rules
|
|
4
|
+
* (declared token set ⊆ registered token set). Skipped — never red — when no
|
|
5
|
+
* rules are configured, so it's inert for projects that don't opt in.
|
|
6
|
+
*/
|
|
7
|
+
export function wiringGate(projectRoot, options = {}) {
|
|
8
|
+
const start = Date.now();
|
|
9
|
+
if (options.configError) {
|
|
10
|
+
return {
|
|
11
|
+
id: 'wiring',
|
|
12
|
+
label: 'Wiring (completeness)',
|
|
13
|
+
status: 'warn',
|
|
14
|
+
message: `Config could not be loaded — wiring rules not evaluated: ${options.configError}`,
|
|
15
|
+
nextCommands: ['shrk doctor'],
|
|
16
|
+
durationMs: Date.now() - start,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const rules = options.rules ?? [];
|
|
20
|
+
if (rules.length === 0) {
|
|
21
|
+
return {
|
|
22
|
+
id: 'wiring',
|
|
23
|
+
label: 'Wiring (completeness)',
|
|
24
|
+
status: 'skipped',
|
|
25
|
+
message: 'No wiring rules configured (sharkcraft.config.ts wiringRules[]).',
|
|
26
|
+
durationMs: Date.now() - start,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const report = runWiring(projectRoot, rules, {
|
|
30
|
+
...(options.changedOnly ? { changedOnly: true, changedFiles: options.changedFiles ?? [] } : {}),
|
|
31
|
+
});
|
|
32
|
+
// Loud zero case: rules exist but none actually ran a comparison (their globs
|
|
33
|
+
// matched no files, or `--changed-only` filtered them all out). Surface it as
|
|
34
|
+
// skipped rather than a silent green pass.
|
|
35
|
+
if (report.rules.length === 0 || report.evaluated === 0) {
|
|
36
|
+
return {
|
|
37
|
+
id: 'wiring',
|
|
38
|
+
label: 'Wiring (completeness)',
|
|
39
|
+
status: 'skipped',
|
|
40
|
+
message: 'No wiring rules in scope — nothing evaluated.',
|
|
41
|
+
details: { evaluated: 0 },
|
|
42
|
+
durationMs: Date.now() - start,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const errors = report.violations.filter((v) => v.severity === 'error').length;
|
|
46
|
+
const warnings = report.violations.filter((v) => v.severity === 'warning').length;
|
|
47
|
+
const samples = report.violations.slice(0, 8).map((v) => `${v.ruleId}: ${v.token} (${v.file}:${v.line})`);
|
|
48
|
+
const diagnostics = report.diagnostics;
|
|
49
|
+
if (report.verdict === 'pass') {
|
|
50
|
+
return {
|
|
51
|
+
id: 'wiring',
|
|
52
|
+
label: 'Wiring (completeness)',
|
|
53
|
+
status: 'pass',
|
|
54
|
+
message: `${report.rules.length} wiring rule(s) — every declared token is wired.`,
|
|
55
|
+
details: { rules: report.rules.length, evaluated: report.evaluated },
|
|
56
|
+
durationMs: Date.now() - start,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const misconfig = diagnostics.length > 0 ? `, ${diagnostics.length} misconfigured rule(s)` : '';
|
|
60
|
+
return {
|
|
61
|
+
id: 'wiring',
|
|
62
|
+
label: 'Wiring (completeness)',
|
|
63
|
+
status: report.verdict === 'errors' ? 'fail' : 'warn',
|
|
64
|
+
message: `${errors} error(s), ${warnings} warning(s)${misconfig}: declared but not wired.`,
|
|
65
|
+
details: {
|
|
66
|
+
errors,
|
|
67
|
+
warnings,
|
|
68
|
+
samples,
|
|
69
|
+
evaluated: report.evaluated,
|
|
70
|
+
...(diagnostics.length > 0 ? { diagnostics } : {}),
|
|
71
|
+
},
|
|
72
|
+
nextCommands: ['shrk check wiring'],
|
|
73
|
+
durationMs: Date.now() - start,
|
|
74
|
+
};
|
|
75
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,9 @@ export * from './gates/graph-unresolved-gate.js';
|
|
|
9
9
|
export * from './gates/impact-baseline-gate.js';
|
|
10
10
|
export * from './gates/structural-patterns-gate.js';
|
|
11
11
|
export * from './gates/intent-classifier-gate.js';
|
|
12
|
+
export * from './gates/wiring-gate.js';
|
|
13
|
+
export * from './gates/policy-lint-gate.js';
|
|
14
|
+
export * from './gates/knowledge-symbol-gate.js';
|
|
12
15
|
export * from './runner/run-gates.js';
|
|
13
16
|
export * from './runner/report-store.js';
|
|
14
17
|
export * from './runner/render-markdown.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAClD,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,mCAAmC,CAAC;AAClD,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,9 @@ export * from "./gates/graph-unresolved-gate.js";
|
|
|
9
9
|
export * from "./gates/impact-baseline-gate.js";
|
|
10
10
|
export * from "./gates/structural-patterns-gate.js";
|
|
11
11
|
export * from "./gates/intent-classifier-gate.js";
|
|
12
|
+
export * from "./gates/wiring-gate.js";
|
|
13
|
+
export * from "./gates/policy-lint-gate.js";
|
|
14
|
+
export * from "./gates/knowledge-symbol-gate.js";
|
|
12
15
|
export * from "./runner/run-gates.js";
|
|
13
16
|
export * from "./runner/report-store.js";
|
|
14
17
|
export * from "./runner/render-markdown.js";
|
|
@@ -6,6 +6,9 @@ import { type IImpactGateOptions } from '../gates/impact-gate.js';
|
|
|
6
6
|
import { type IImpactBaselineGateOptions } from '../gates/impact-baseline-gate.js';
|
|
7
7
|
import { type IIntentClassifierGateOptions } from '../gates/intent-classifier-gate.js';
|
|
8
8
|
import { type IStructuralPatternsGateOptions } from '../gates/structural-patterns-gate.js';
|
|
9
|
+
import { type IWiringGateOptions } from '../gates/wiring-gate.js';
|
|
10
|
+
import { type IPolicyLintGateOptions } from '../gates/policy-lint-gate.js';
|
|
11
|
+
import { type IKnowledgeSymbolGateOptions } from '../gates/knowledge-symbol-gate.js';
|
|
9
12
|
import { type IQualityGateReport } from '../schema/quality-gate.js';
|
|
10
13
|
export interface IRunGatesOptions {
|
|
11
14
|
projectRoot: string;
|
|
@@ -28,6 +31,15 @@ export interface IRunGatesOptions {
|
|
|
28
31
|
structuralPatterns?: IStructuralPatternsGateOptions;
|
|
29
32
|
/** Optional intent-classifier gate config. */
|
|
30
33
|
intentClassifier?: IIntentClassifierGateOptions;
|
|
34
|
+
/** Optional wiring gate config (the project's wiringRules + change scope). */
|
|
35
|
+
wiring?: IWiringGateOptions;
|
|
36
|
+
/** Optional policy-lint gate config (the project's policyRules + change scope). */
|
|
37
|
+
policy?: IPolicyLintGateOptions;
|
|
38
|
+
/**
|
|
39
|
+
* Optional knowledge symbol-ref gate config. When omitted, the gate is
|
|
40
|
+
* skipped — the inspection (async to load) is what opts a project in.
|
|
41
|
+
*/
|
|
42
|
+
knowledgeSymbol?: IKnowledgeSymbolGateOptions;
|
|
31
43
|
/** Disable specific gates by id. */
|
|
32
44
|
disable?: readonly string[];
|
|
33
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-gates.d.ts","sourceRoot":"","sources":["../../src/runner/run-gates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAElF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAmB,KAAK,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAE9F,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,sDAAsD;IACtD,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,yCAAyC;IACzC,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,6CAA6C;IAC7C,eAAe,CAAC,EAAE,2BAA2B,CAAC;IAC9C,4CAA4C;IAC5C,cAAc,CAAC,EAAE,0BAA0B,CAAC;IAC5C,gDAAgD;IAChD,kBAAkB,CAAC,EAAE,8BAA8B,CAAC;IACpD,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,4BAA4B,CAAC;IAChD,oCAAoC;IACpC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"run-gates.d.ts","sourceRoot":"","sources":["../../src/runner/run-gates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAElF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAmB,KAAK,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAE9F,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,sDAAsD;IACtD,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,yCAAyC;IACzC,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,6CAA6C;IAC7C,eAAe,CAAC,EAAE,2BAA2B,CAAC;IAC9C,4CAA4C;IAC5C,cAAc,CAAC,EAAE,0BAA0B,CAAC;IAC5C,gDAAgD;IAChD,kBAAkB,CAAC,EAAE,8BAA8B,CAAC;IACpD,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,4BAA4B,CAAC;IAChD,8EAA8E;IAC9E,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,mFAAmF;IACnF,MAAM,CAAC,EAAE,sBAAsB,CAAC;IAChC;;;OAGG;IACH,eAAe,CAAC,EAAE,2BAA2B,CAAC;IAC9C,oCAAoC;IACpC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,CA2D7E"}
|
package/dist/runner/run-gates.js
CHANGED
|
@@ -7,6 +7,9 @@ import { impactGate } from "../gates/impact-gate.js";
|
|
|
7
7
|
import { impactBaselineGate, } from "../gates/impact-baseline-gate.js";
|
|
8
8
|
import { intentClassifierGate, } from "../gates/intent-classifier-gate.js";
|
|
9
9
|
import { structuralPatternsGate, } from "../gates/structural-patterns-gate.js";
|
|
10
|
+
import { wiringGate } from "../gates/wiring-gate.js";
|
|
11
|
+
import { policyLintGate } from "../gates/policy-lint-gate.js";
|
|
12
|
+
import { knowledgeSymbolGate, } from "../gates/knowledge-symbol-gate.js";
|
|
10
13
|
import { QUALITY_GATE_SCHEMA, } from "../schema/quality-gate.js";
|
|
11
14
|
/**
|
|
12
15
|
* Run the quality-gate aggregator over a project.
|
|
@@ -60,6 +63,15 @@ export function runQualityGates(options) {
|
|
|
60
63
|
if (!disabled.has('intent-classifier')) {
|
|
61
64
|
gates.push(intentClassifierGate(options.projectRoot, options.intentClassifier ?? {}));
|
|
62
65
|
}
|
|
66
|
+
if (!disabled.has('wiring')) {
|
|
67
|
+
gates.push(wiringGate(options.projectRoot, options.wiring ?? {}));
|
|
68
|
+
}
|
|
69
|
+
if (!disabled.has('policy')) {
|
|
70
|
+
gates.push(policyLintGate(options.projectRoot, options.policy ?? {}));
|
|
71
|
+
}
|
|
72
|
+
if (!disabled.has('knowledge-symbol') && options.knowledgeSymbol) {
|
|
73
|
+
gates.push(knowledgeSymbolGate(options.projectRoot, options.knowledgeSymbol));
|
|
74
|
+
}
|
|
63
75
|
if (!disabled.has('api-diff') && options.apiDiff) {
|
|
64
76
|
gates.push(apiDiffGate(options.projectRoot, options.apiDiff));
|
|
65
77
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/quality-gates",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.23",
|
|
4
4
|
"description": "SharkCraft quality gates: single aggregator that runs the code-intelligence checks (graph index, boundaries, architecture, impact summary) and emits one pass/fail report. The pre-merge gate for AI-agent-authored changes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -43,14 +43,15 @@
|
|
|
43
43
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
47
|
-
"@shrkcrft/graph": "^0.1.0-alpha.
|
|
48
|
-
"@shrkcrft/architecture-guard": "^0.1.0-alpha.
|
|
49
|
-
"@shrkcrft/impact-engine": "^0.1.0-alpha.
|
|
50
|
-
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/structural-search": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/context-planner": "^0.1.0-alpha.
|
|
46
|
+
"@shrkcrft/core": "^0.1.0-alpha.23",
|
|
47
|
+
"@shrkcrft/graph": "^0.1.0-alpha.23",
|
|
48
|
+
"@shrkcrft/architecture-guard": "^0.1.0-alpha.23",
|
|
49
|
+
"@shrkcrft/impact-engine": "^0.1.0-alpha.23",
|
|
50
|
+
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.23",
|
|
51
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.23",
|
|
52
|
+
"@shrkcrft/structural-search": "^0.1.0-alpha.23",
|
|
53
|
+
"@shrkcrft/context-planner": "^0.1.0-alpha.23",
|
|
54
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.23"
|
|
54
55
|
},
|
|
55
56
|
"publishConfig": {
|
|
56
57
|
"access": "public"
|