@eduardbar/drift 1.4.0 → 1.5.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.
- package/.github/actions/drift-review/README.md +4 -2
- package/.github/actions/drift-review/action.yml +22 -5
- package/.github/actions/drift-scan/README.md +3 -3
- package/.github/actions/drift-scan/action.yml +1 -1
- package/.github/workflows/publish-vscode.yml +1 -3
- package/.github/workflows/publish.yml +8 -0
- package/.github/workflows/quality.yml +15 -0
- package/.github/workflows/reusable-quality-checks.yml +95 -0
- package/.github/workflows/review-pr.yml +0 -1
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +14 -1
- package/README.md +30 -3
- package/benchmarks/fixtures/critical/drift.config.ts +21 -0
- package/benchmarks/fixtures/critical/src/app/user-service.ts +30 -0
- package/benchmarks/fixtures/critical/src/domain/entities.ts +19 -0
- package/benchmarks/fixtures/critical/src/domain/policies.ts +22 -0
- package/benchmarks/fixtures/critical/src/index.ts +10 -0
- package/benchmarks/fixtures/critical/src/infra/memory-user-repo.ts +14 -0
- package/benchmarks/perf-budget.v1.json +27 -0
- package/dist/benchmark.js +12 -0
- package/dist/cli.js +2 -2
- package/dist/doctor.d.ts +21 -0
- package/dist/doctor.js +10 -3
- package/dist/guard-baseline.d.ts +12 -0
- package/dist/guard-baseline.js +57 -0
- package/dist/guard-metrics.d.ts +6 -0
- package/dist/guard-metrics.js +39 -0
- package/dist/guard-types.d.ts +2 -1
- package/dist/guard.d.ts +3 -1
- package/dist/guard.js +9 -70
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/init.js +1 -1
- package/dist/output-metadata.d.ts +2 -0
- package/dist/output-metadata.js +2 -0
- package/dist/trust.d.ts +2 -1
- package/dist/trust.js +1 -1
- package/dist/types.d.ts +1 -1
- package/docs/AGENTS.md +1 -1
- package/package.json +10 -4
- package/schemas/drift-doctor.v1.json +57 -0
- package/schemas/drift-guard.v1.json +298 -0
- package/scripts/check-docs-drift.mjs +154 -0
- package/scripts/check-performance-budget.mjs +360 -0
- package/scripts/check-runtime-policy.mjs +66 -0
- package/src/benchmark.ts +17 -0
- package/src/cli.ts +2 -2
- package/src/doctor.ts +15 -3
- package/src/guard-baseline.ts +74 -0
- package/src/guard-metrics.ts +52 -0
- package/src/guard-types.ts +3 -1
- package/src/guard.ts +14 -90
- package/src/index.ts +1 -0
- package/src/init.ts +1 -1
- package/src/output-metadata.ts +2 -0
- package/src/trust.ts +1 -1
- package/src/types.ts +1 -0
- package/tests/ci-quality-matrix.test.ts +37 -0
- package/tests/ci-smoke-gate.test.ts +26 -0
- package/tests/ci-version-alignment.test.ts +93 -0
- package/tests/docs-drift-check.test.ts +115 -0
- package/tests/new-features.test.ts +2 -2
- package/tests/perf-budget-check.test.ts +146 -0
- package/tests/phase1-init-doctor-guard.test.ts +104 -2
- package/tests/runtime-policy-alignment.test.ts +46 -0
- package/vitest.config.ts +2 -0
package/dist/doctor.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import kleur from 'kleur';
|
|
4
|
+
import { OUTPUT_SCHEMA, withOutputMetadata } from './output-metadata.js';
|
|
4
5
|
const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx']);
|
|
5
6
|
const IGNORED_DIRECTORIES = new Set(['node_modules', '.git', 'dist', '.next', 'coverage']);
|
|
6
7
|
const DECIMAL_RADIX = 10;
|
|
7
|
-
const MIN_SUPPORTED_NODE_MAJOR =
|
|
8
|
+
const MIN_SUPPORTED_NODE_MAJOR = 20;
|
|
8
9
|
const LOW_MEMORY_SOURCE_FILE_THRESHOLD = 500;
|
|
9
10
|
const DRIFT_CONFIG_CANDIDATES = [
|
|
10
11
|
'drift.config.ts',
|
|
@@ -92,7 +93,7 @@ function printConsoleReport(report) {
|
|
|
92
93
|
process.stdout.write(`${kleur.bold().white('drift doctor')} ${kleur.gray('- environment diagnostics')}\n\n`);
|
|
93
94
|
const nodeStatus = report.node.supported
|
|
94
95
|
? `${icons.check} ${kleur.green('Node runtime supported')}`
|
|
95
|
-
: `${icons.warn} ${kleur.yellow('Node runtime below
|
|
96
|
+
: `${icons.warn} ${kleur.yellow('Node runtime below supported minimum (>=20)')}`;
|
|
96
97
|
process.stdout.write(`${nodeStatus} ${kleur.gray(`(${report.node.version})`)}\n`);
|
|
97
98
|
if (report.project.packageJsonFound) {
|
|
98
99
|
process.stdout.write(`${icons.check} package.json found\n`);
|
|
@@ -120,10 +121,16 @@ function printConsoleReport(report) {
|
|
|
120
121
|
}
|
|
121
122
|
process.stdout.write('\n');
|
|
122
123
|
}
|
|
124
|
+
export function formatDoctorJsonObject(report) {
|
|
125
|
+
return withOutputMetadata(report, OUTPUT_SCHEMA.doctor);
|
|
126
|
+
}
|
|
127
|
+
export function formatDoctorJson(report) {
|
|
128
|
+
return JSON.stringify(formatDoctorJsonObject(report), null, 2);
|
|
129
|
+
}
|
|
123
130
|
export async function runDoctor(projectPath, options) {
|
|
124
131
|
const report = buildDoctorReport(projectPath);
|
|
125
132
|
if (options?.json) {
|
|
126
|
-
process.stdout.write(`${
|
|
133
|
+
process.stdout.write(`${formatDoctorJson(report)}\n`);
|
|
127
134
|
}
|
|
128
135
|
else {
|
|
129
136
|
printConsoleReport(report);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GuardBaseline, IssueSeverity } from './guard-types.js';
|
|
2
|
+
export interface NormalizedBaseline {
|
|
3
|
+
score?: number;
|
|
4
|
+
totalIssues?: number;
|
|
5
|
+
bySeverity: Partial<Record<IssueSeverity, number>>;
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeBaseline(baseline: GuardBaseline): NormalizedBaseline;
|
|
8
|
+
export declare function readBaselineFromFile(projectPath: string, baselinePath?: string): {
|
|
9
|
+
baseline: NormalizedBaseline;
|
|
10
|
+
path: string;
|
|
11
|
+
} | undefined;
|
|
12
|
+
//# sourceMappingURL=guard-baseline.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
function parseNumber(value) {
|
|
4
|
+
return typeof value === 'number' && !Number.isNaN(value) ? value : undefined;
|
|
5
|
+
}
|
|
6
|
+
function firstDefinedNumber(values) {
|
|
7
|
+
for (const value of values) {
|
|
8
|
+
const parsed = parseNumber(value);
|
|
9
|
+
if (parsed !== undefined) {
|
|
10
|
+
return parsed;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
function normalizeSeverity(baseline, severity) {
|
|
16
|
+
const summaryBySeverity = baseline.summary?.[`${severity}s`];
|
|
17
|
+
return firstDefinedNumber([
|
|
18
|
+
baseline.bySeverity?.[severity],
|
|
19
|
+
severity === 'error' ? baseline.errors : undefined,
|
|
20
|
+
severity === 'warning' ? baseline.warnings : undefined,
|
|
21
|
+
severity === 'info' ? baseline.infos : undefined,
|
|
22
|
+
summaryBySeverity,
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
function hasAnchor(baseline) {
|
|
26
|
+
if (baseline.score !== undefined || baseline.totalIssues !== undefined) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
const severities = ['error', 'warning', 'info'];
|
|
30
|
+
return severities.some((severity) => baseline.bySeverity[severity] !== undefined);
|
|
31
|
+
}
|
|
32
|
+
export function normalizeBaseline(baseline) {
|
|
33
|
+
const normalized = {
|
|
34
|
+
score: parseNumber(baseline.score),
|
|
35
|
+
totalIssues: parseNumber(baseline.totalIssues),
|
|
36
|
+
bySeverity: {
|
|
37
|
+
error: normalizeSeverity(baseline, 'error'),
|
|
38
|
+
warning: normalizeSeverity(baseline, 'warning'),
|
|
39
|
+
info: normalizeSeverity(baseline, 'info'),
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
if (!hasAnchor(normalized)) {
|
|
43
|
+
throw new Error('Invalid guard baseline: expected score, totalIssues, or severity counters (error/warning/info).');
|
|
44
|
+
}
|
|
45
|
+
return normalized;
|
|
46
|
+
}
|
|
47
|
+
export function readBaselineFromFile(projectPath, baselinePath) {
|
|
48
|
+
const resolvedBaselinePath = resolve(projectPath, baselinePath ?? 'drift-baseline.json');
|
|
49
|
+
if (!existsSync(resolvedBaselinePath))
|
|
50
|
+
return undefined;
|
|
51
|
+
const raw = JSON.parse(readFileSync(resolvedBaselinePath, 'utf8'));
|
|
52
|
+
return {
|
|
53
|
+
baseline: normalizeBaseline(raw),
|
|
54
|
+
path: resolvedBaselinePath,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=guard-baseline.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DriftDiff, DriftReport } from './types.js';
|
|
2
|
+
import type { GuardMetrics } from './guard-types.js';
|
|
3
|
+
import type { NormalizedBaseline } from './guard-baseline.js';
|
|
4
|
+
export declare function buildMetricsFromDiff(diff: DriftDiff): GuardMetrics;
|
|
5
|
+
export declare function buildMetricsFromBaseline(current: DriftReport, baseline: NormalizedBaseline): GuardMetrics;
|
|
6
|
+
//# sourceMappingURL=guard-metrics.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
function createSeverityDelta() {
|
|
2
|
+
return {
|
|
3
|
+
error: 0,
|
|
4
|
+
warning: 0,
|
|
5
|
+
info: 0,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function applySeverityDelta(delta, issues, direction) {
|
|
9
|
+
for (const issue of issues) {
|
|
10
|
+
delta[issue.severity] += direction;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function countSeverityDeltaFromDiff(diff) {
|
|
14
|
+
const severityDelta = createSeverityDelta();
|
|
15
|
+
for (const file of diff.files) {
|
|
16
|
+
applySeverityDelta(severityDelta, file.newIssues, 1);
|
|
17
|
+
applySeverityDelta(severityDelta, file.resolvedIssues, -1);
|
|
18
|
+
}
|
|
19
|
+
return severityDelta;
|
|
20
|
+
}
|
|
21
|
+
export function buildMetricsFromDiff(diff) {
|
|
22
|
+
return {
|
|
23
|
+
scoreDelta: diff.totalDelta,
|
|
24
|
+
totalIssuesDelta: diff.newIssuesCount - diff.resolvedIssuesCount,
|
|
25
|
+
severityDelta: countSeverityDeltaFromDiff(diff),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function buildMetricsFromBaseline(current, baseline) {
|
|
29
|
+
return {
|
|
30
|
+
scoreDelta: current.totalScore - (baseline.score ?? current.totalScore),
|
|
31
|
+
totalIssuesDelta: current.totalIssues - (baseline.totalIssues ?? current.totalIssues),
|
|
32
|
+
severityDelta: {
|
|
33
|
+
error: current.summary.errors - (baseline.bySeverity.error ?? current.summary.errors),
|
|
34
|
+
warning: current.summary.warnings - (baseline.bySeverity.warning ?? current.summary.warnings),
|
|
35
|
+
info: current.summary.infos - (baseline.bySeverity.info ?? current.summary.infos),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=guard-metrics.js.map
|
package/dist/guard-types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DriftAnalysisOptions, DriftDiff, DriftIssue, DriftReport } from './types.js';
|
|
1
|
+
import type { DriftAnalysisOptions, DriftDiff, DriftIssue, DriftOutputMetadata, DriftReport } from './types.js';
|
|
2
2
|
export type IssueSeverity = DriftIssue['severity'];
|
|
3
3
|
export interface GuardBaseline {
|
|
4
4
|
score?: number;
|
|
@@ -54,4 +54,5 @@ export interface GuardResult {
|
|
|
54
54
|
current: DriftReport;
|
|
55
55
|
diff?: DriftDiff;
|
|
56
56
|
}
|
|
57
|
+
export type GuardResultJson = GuardResult & DriftOutputMetadata;
|
|
57
58
|
//# sourceMappingURL=guard-types.d.ts.map
|
package/dist/guard.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GuardEvaluation, GuardMetrics, GuardOptions, GuardResult, GuardThresholds } from './guard-types.js';
|
|
1
|
+
import type { GuardEvaluation, GuardMetrics, GuardOptions, GuardResult, GuardResultJson, GuardThresholds } from './guard-types.js';
|
|
2
2
|
interface GuardEvalInput {
|
|
3
3
|
metrics: GuardMetrics;
|
|
4
4
|
budget?: number;
|
|
@@ -9,6 +9,8 @@ interface GuardEvalInput {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
export declare function evaluateGuard(input: GuardEvalInput): GuardEvaluation;
|
|
12
|
+
export declare function formatGuardJsonObject(result: GuardResult): GuardResultJson;
|
|
13
|
+
export declare function formatGuardJson(result: GuardResult): string;
|
|
12
14
|
export declare function runGuard(targetPath: string, options?: GuardOptions): Promise<GuardResult>;
|
|
13
15
|
export {};
|
|
14
16
|
//# sourceMappingURL=guard.d.ts.map
|
package/dist/guard.js
CHANGED
|
@@ -1,45 +1,12 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
1
|
import { relative, resolve } from 'node:path';
|
|
3
2
|
import { analyzeProject } from './analyzer.js';
|
|
4
3
|
import { loadConfig } from './config.js';
|
|
5
4
|
import { computeDiff } from './diff.js';
|
|
6
5
|
import { cleanupTempDir, extractFilesAtRef } from './git.js';
|
|
6
|
+
import { normalizeBaseline, readBaselineFromFile } from './guard-baseline.js';
|
|
7
|
+
import { buildMetricsFromBaseline, buildMetricsFromDiff } from './guard-metrics.js';
|
|
8
|
+
import { OUTPUT_SCHEMA, withOutputMetadata } from './output-metadata.js';
|
|
7
9
|
import { buildReport } from './reporter.js';
|
|
8
|
-
function parseNumber(value) {
|
|
9
|
-
return typeof value === 'number' && !Number.isNaN(value) ? value : undefined;
|
|
10
|
-
}
|
|
11
|
-
function normalizeBaseline(baseline) {
|
|
12
|
-
const bySeverityFromRoot = baseline.bySeverity;
|
|
13
|
-
const bySeverity = {
|
|
14
|
-
error: parseNumber(bySeverityFromRoot?.error) ?? parseNumber(baseline.errors) ?? parseNumber(baseline.summary?.errors),
|
|
15
|
-
warning: parseNumber(bySeverityFromRoot?.warning) ?? parseNumber(baseline.warnings) ?? parseNumber(baseline.summary?.warnings),
|
|
16
|
-
info: parseNumber(bySeverityFromRoot?.info) ?? parseNumber(baseline.infos) ?? parseNumber(baseline.summary?.infos),
|
|
17
|
-
};
|
|
18
|
-
const normalized = {
|
|
19
|
-
score: parseNumber(baseline.score),
|
|
20
|
-
totalIssues: parseNumber(baseline.totalIssues),
|
|
21
|
-
bySeverity,
|
|
22
|
-
};
|
|
23
|
-
const hasAnyAnchor = normalized.score !== undefined ||
|
|
24
|
-
normalized.totalIssues !== undefined ||
|
|
25
|
-
normalized.bySeverity.error !== undefined ||
|
|
26
|
-
normalized.bySeverity.warning !== undefined ||
|
|
27
|
-
normalized.bySeverity.info !== undefined;
|
|
28
|
-
if (!hasAnyAnchor) {
|
|
29
|
-
throw new Error('Invalid guard baseline: expected score, totalIssues, or severity counters (error/warning/info).');
|
|
30
|
-
}
|
|
31
|
-
return normalized;
|
|
32
|
-
}
|
|
33
|
-
function readBaselineFromFile(projectPath, baselinePath) {
|
|
34
|
-
const resolvedBaselinePath = resolve(projectPath, baselinePath ?? 'drift-baseline.json');
|
|
35
|
-
if (!existsSync(resolvedBaselinePath))
|
|
36
|
-
return undefined;
|
|
37
|
-
const raw = JSON.parse(readFileSync(resolvedBaselinePath, 'utf8'));
|
|
38
|
-
return {
|
|
39
|
-
baseline: normalizeBaseline(raw),
|
|
40
|
-
path: resolvedBaselinePath,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
10
|
function remapBaseReportPaths(baseReport, tempDir, projectPath) {
|
|
44
11
|
return {
|
|
45
12
|
...baseReport,
|
|
@@ -49,40 +16,6 @@ function remapBaseReportPaths(baseReport, tempDir, projectPath) {
|
|
|
49
16
|
})),
|
|
50
17
|
};
|
|
51
18
|
}
|
|
52
|
-
function countSeverityDeltaFromDiff(diff) {
|
|
53
|
-
const severityDelta = {
|
|
54
|
-
error: 0,
|
|
55
|
-
warning: 0,
|
|
56
|
-
info: 0,
|
|
57
|
-
};
|
|
58
|
-
for (const file of diff.files) {
|
|
59
|
-
for (const issue of file.newIssues) {
|
|
60
|
-
severityDelta[issue.severity] += 1;
|
|
61
|
-
}
|
|
62
|
-
for (const issue of file.resolvedIssues) {
|
|
63
|
-
severityDelta[issue.severity] -= 1;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return severityDelta;
|
|
67
|
-
}
|
|
68
|
-
function buildMetricsFromDiff(diff) {
|
|
69
|
-
return {
|
|
70
|
-
scoreDelta: diff.totalDelta,
|
|
71
|
-
totalIssuesDelta: diff.newIssuesCount - diff.resolvedIssuesCount,
|
|
72
|
-
severityDelta: countSeverityDeltaFromDiff(diff),
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function buildMetricsFromBaseline(current, baseline) {
|
|
76
|
-
return {
|
|
77
|
-
scoreDelta: current.totalScore - (baseline.score ?? current.totalScore),
|
|
78
|
-
totalIssuesDelta: current.totalIssues - (baseline.totalIssues ?? current.totalIssues),
|
|
79
|
-
severityDelta: {
|
|
80
|
-
error: current.summary.errors - (baseline.bySeverity.error ?? current.summary.errors),
|
|
81
|
-
warning: current.summary.warnings - (baseline.bySeverity.warning ?? current.summary.warnings),
|
|
82
|
-
info: current.summary.infos - (baseline.bySeverity.info ?? current.summary.infos),
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
19
|
function addCheck(checks, input) {
|
|
87
20
|
checks.push({
|
|
88
21
|
id: input.id,
|
|
@@ -138,6 +71,12 @@ export function evaluateGuard(input) {
|
|
|
138
71
|
checks,
|
|
139
72
|
};
|
|
140
73
|
}
|
|
74
|
+
export function formatGuardJsonObject(result) {
|
|
75
|
+
return withOutputMetadata(result, OUTPUT_SCHEMA.guard);
|
|
76
|
+
}
|
|
77
|
+
export function formatGuardJson(result) {
|
|
78
|
+
return JSON.stringify(formatGuardJsonObject(result), null, 2);
|
|
79
|
+
}
|
|
141
80
|
export async function runGuard(targetPath, options = {}) {
|
|
142
81
|
const runtimeState = await initializeGuardRuntime(targetPath, options);
|
|
143
82
|
const { projectPath, config, currentReport } = runtimeState;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { GuardBaseline, GuardThresholds, GuardOptions, GuardMetrics, GuardC
|
|
|
6
6
|
export { generateReview, formatReviewMarkdown } from './review.js';
|
|
7
7
|
export { runDoctor } from './doctor.js';
|
|
8
8
|
export type { DoctorOptions } from './doctor.js';
|
|
9
|
-
export { buildTrustReport, formatTrustConsole, formatTrustMarkdown, formatTrustJson, resolveTrustGatePolicy, evaluateTrustGate, shouldFailByMaxRisk, shouldFailTrustGate, normalizeMergeRiskLevel, MERGE_RISK_ORDER, } from './trust.js';
|
|
9
|
+
export { buildTrustReport, formatTrustConsole, formatTrustMarkdown, formatTrustJsonObject, formatTrustJson, resolveTrustGatePolicy, evaluateTrustGate, shouldFailByMaxRisk, shouldFailTrustGate, normalizeMergeRiskLevel, MERGE_RISK_ORDER, } from './trust.js';
|
|
10
10
|
export type { TrustGateOptions, TrustGatePolicyResolutionOptions, TrustGatePolicyResolutionStep, TrustGateEvaluation, } from './trust.js';
|
|
11
11
|
export { computeTrustKpis, computeTrustKpisFromReports, formatTrustKpiConsole, formatTrustKpiJson, } from './trust-kpi.js';
|
|
12
12
|
export { toSarif, diffToSarif } from './sarif.js';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { computeDiff } from './diff.js';
|
|
|
4
4
|
export { runGuard, evaluateGuard } from './guard.js';
|
|
5
5
|
export { generateReview, formatReviewMarkdown } from './review.js';
|
|
6
6
|
export { runDoctor } from './doctor.js';
|
|
7
|
-
export { buildTrustReport, formatTrustConsole, formatTrustMarkdown, formatTrustJson, resolveTrustGatePolicy, evaluateTrustGate, shouldFailByMaxRisk, shouldFailTrustGate, normalizeMergeRiskLevel, MERGE_RISK_ORDER, } from './trust.js';
|
|
7
|
+
export { buildTrustReport, formatTrustConsole, formatTrustMarkdown, formatTrustJsonObject, formatTrustJson, resolveTrustGatePolicy, evaluateTrustGate, shouldFailByMaxRisk, shouldFailTrustGate, normalizeMergeRiskLevel, MERGE_RISK_ORDER, } from './trust.js';
|
|
8
8
|
export { computeTrustKpis, computeTrustKpisFromReports, formatTrustKpiConsole, formatTrustKpiJson, } from './trust-kpi.js';
|
|
9
9
|
export { toSarif, diffToSarif } from './sarif.js';
|
|
10
10
|
export { generateArchitectureMap, generateArchitectureSvg } from './map.js';
|
package/dist/init.js
CHANGED
|
@@ -2,6 +2,8 @@ export declare const OUTPUT_SCHEMA: {
|
|
|
2
2
|
readonly report: "schemas/drift-report.v1.json";
|
|
3
3
|
readonly trust: "schemas/drift-trust.v1.json";
|
|
4
4
|
readonly ai: "schemas/drift-ai-output.v1.json";
|
|
5
|
+
readonly doctor: "schemas/drift-doctor.v1.json";
|
|
6
|
+
readonly guard: "schemas/drift-guard.v1.json";
|
|
5
7
|
};
|
|
6
8
|
type OutputMetadata = {
|
|
7
9
|
$schema: string;
|
package/dist/output-metadata.js
CHANGED
|
@@ -6,6 +6,8 @@ export const OUTPUT_SCHEMA = {
|
|
|
6
6
|
report: 'schemas/drift-report.v1.json',
|
|
7
7
|
trust: 'schemas/drift-trust.v1.json',
|
|
8
8
|
ai: 'schemas/drift-ai-output.v1.json',
|
|
9
|
+
doctor: 'schemas/drift-doctor.v1.json',
|
|
10
|
+
guard: 'schemas/drift-guard.v1.json',
|
|
9
11
|
};
|
|
10
12
|
export function withOutputMetadata(payload, schema) {
|
|
11
13
|
return {
|
package/dist/trust.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DriftDiff, DriftReport, DriftTrustReport, MergeRiskLevel } from './types.js';
|
|
1
|
+
import type { DriftDiff, DriftReport, DriftTrustReport, DriftTrustReportJson, MergeRiskLevel } from './types.js';
|
|
2
2
|
import type { SnapshotEntry } from './snapshot.js';
|
|
3
3
|
import type { TrustGateOptions } from './trust-policy.js';
|
|
4
4
|
export { MERGE_RISK_ORDER, detectBranchName, explainTrustGatePolicy, formatTrustGatePolicyExplanation, normalizeMergeRiskLevel, resolveTrustGatePolicy, } from './trust-policy.js';
|
|
@@ -29,6 +29,7 @@ export interface TrustGateEvaluation {
|
|
|
29
29
|
export declare function buildTrustReport(report: DriftReport, options?: BuildTrustOptions): DriftTrustReport;
|
|
30
30
|
export declare function formatTrustConsole(trust: DriftTrustReport): string;
|
|
31
31
|
export declare function formatTrustMarkdown(trust: DriftTrustReport): string;
|
|
32
|
+
export declare function formatTrustJsonObject(trust: DriftTrustReport): DriftTrustReportJson;
|
|
32
33
|
export declare function formatTrustJson(trust: DriftTrustReport): string;
|
|
33
34
|
export declare function renderTrustOutput(trust: DriftTrustReport, options?: TrustRenderOptions): string;
|
|
34
35
|
export declare function shouldFailByMaxRisk(actual: MergeRiskLevel, allowedMaxRisk: MergeRiskLevel): boolean;
|
package/dist/trust.js
CHANGED
|
@@ -109,7 +109,7 @@ export function formatTrustMarkdown(trust) {
|
|
|
109
109
|
}
|
|
110
110
|
return sections.join('\n');
|
|
111
111
|
}
|
|
112
|
-
function formatTrustJsonObject(trust) {
|
|
112
|
+
export function formatTrustJsonObject(trust) {
|
|
113
113
|
return withOutputMetadata(trust, OUTPUT_SCHEMA.trust);
|
|
114
114
|
}
|
|
115
115
|
export function formatTrustJson(trust) {
|
package/dist/types.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export type { LayerDefinition, ModuleBoundary, DriftPerformanceConfig, DriftAnal
|
|
|
4
4
|
export type { DriftConfig } from './types/app.js';
|
|
5
5
|
export type { PluginRuleContext, DriftPluginRule, DriftPlugin, LoadedPlugin, PluginLoadError, PluginLoadWarning, } from './types/plugin.js';
|
|
6
6
|
export type { FileDiff, DriftDiff, HistoricalAnalysis, TrendDataPoint, BlameAttribution, DriftTrendReport, DriftBlameReport, } from './types/diff.js';
|
|
7
|
-
export type { GuardBaseline, GuardThresholds, GuardOptions, GuardMetrics, GuardCheck, GuardEvaluation, GuardResult, } from './guard-types.js';
|
|
7
|
+
export type { GuardBaseline, GuardThresholds, GuardOptions, GuardMetrics, GuardCheck, GuardEvaluation, GuardResult, GuardResultJson, } from './guard-types.js';
|
|
8
8
|
export type { SarifLevel, DriftSarifRule, DriftSarifResult, DriftSarifRun, DriftSarifLog, } from './sarif.js';
|
|
9
9
|
//# sourceMappingURL=types.d.ts.map
|
package/docs/AGENTS.md
CHANGED
|
@@ -10,7 +10,7 @@ Esta guia define como colaborar en `drift` para mantener calidad tecnica, consis
|
|
|
10
10
|
|
|
11
11
|
### Stack real
|
|
12
12
|
|
|
13
|
-
- Runtime: Node.js
|
|
13
|
+
- Runtime: Node.js 20.x and 22.x (LTS)
|
|
14
14
|
- Lenguaje: TypeScript (`type: module`)
|
|
15
15
|
- Analisis AST: `ts-morph`
|
|
16
16
|
- CLI: `commander`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eduardbar/drift",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "AI Code Audit CLI for merge trust in AI-assisted PRs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
"test:watch": "vitest",
|
|
17
17
|
"test:coverage": "vitest run --coverage",
|
|
18
18
|
"benchmark": "node --import tsx src/benchmark.ts",
|
|
19
|
-
"smoke:repo": "node ./scripts/smoke-repo.mjs"
|
|
19
|
+
"smoke:repo": "node ./scripts/smoke-repo.mjs",
|
|
20
|
+
"check:runtime-policy": "node ./scripts/check-runtime-policy.mjs",
|
|
21
|
+
"check:docs-drift": "node ./scripts/check-docs-drift.mjs",
|
|
22
|
+
"check:perf-budget": "node ./scripts/check-performance-budget.mjs"
|
|
20
23
|
},
|
|
21
24
|
"keywords": [
|
|
22
25
|
"vibe-coding",
|
|
@@ -28,6 +31,9 @@
|
|
|
28
31
|
],
|
|
29
32
|
"author": "eduardbar",
|
|
30
33
|
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": "^20.0.0 || ^22.0.0"
|
|
36
|
+
},
|
|
31
37
|
"homepage": "https://github.com/eduardbar/drift#readme",
|
|
32
38
|
"repository": {
|
|
33
39
|
"type": "git",
|
|
@@ -43,9 +49,9 @@
|
|
|
43
49
|
},
|
|
44
50
|
"devDependencies": {
|
|
45
51
|
"@types/node": "^25.3.0",
|
|
46
|
-
"@vitest/coverage-v8": "^4.
|
|
52
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
47
53
|
"tsx": "^4.21.0",
|
|
48
54
|
"typescript": "^5.9.3",
|
|
49
|
-
"vitest": "^4.
|
|
55
|
+
"vitest": "^4.1.2"
|
|
50
56
|
}
|
|
51
57
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "schemas/drift-doctor.v1.json",
|
|
4
|
+
"title": "drift doctor v1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"$schema",
|
|
9
|
+
"toolVersion",
|
|
10
|
+
"targetPath",
|
|
11
|
+
"node",
|
|
12
|
+
"project"
|
|
13
|
+
],
|
|
14
|
+
"properties": {
|
|
15
|
+
"$schema": {
|
|
16
|
+
"const": "schemas/drift-doctor.v1.json"
|
|
17
|
+
},
|
|
18
|
+
"toolVersion": {
|
|
19
|
+
"type": "string"
|
|
20
|
+
},
|
|
21
|
+
"targetPath": {
|
|
22
|
+
"type": "string"
|
|
23
|
+
},
|
|
24
|
+
"node": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"additionalProperties": false,
|
|
27
|
+
"required": ["version", "major", "supported"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"version": { "type": "string" },
|
|
30
|
+
"major": { "type": "number" },
|
|
31
|
+
"supported": { "type": "boolean" }
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"project": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"required": [
|
|
38
|
+
"packageJsonFound",
|
|
39
|
+
"esm",
|
|
40
|
+
"tsconfigFound",
|
|
41
|
+
"sourceFilesCount",
|
|
42
|
+
"lowMemorySuggested",
|
|
43
|
+
"driftConfigFile"
|
|
44
|
+
],
|
|
45
|
+
"properties": {
|
|
46
|
+
"packageJsonFound": { "type": "boolean" },
|
|
47
|
+
"esm": { "type": "boolean" },
|
|
48
|
+
"tsconfigFound": { "type": "boolean" },
|
|
49
|
+
"sourceFilesCount": { "type": "number" },
|
|
50
|
+
"lowMemorySuggested": { "type": "boolean" },
|
|
51
|
+
"driftConfigFile": {
|
|
52
|
+
"type": ["string", "null"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|