@indemn/cli 1.0.0 → 1.1.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/.claude-plugin/marketplace.json +28 -0
- package/README.md +29 -23
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +20 -0
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/eval.d.ts.map +1 -1
- package/dist/cli/eval.js +38 -0
- package/dist/cli/eval.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +40 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/report/agent-card/cover.d.ts +20 -0
- package/dist/report/agent-card/cover.d.ts.map +1 -0
- package/dist/report/agent-card/cover.js +58 -0
- package/dist/report/agent-card/cover.js.map +1 -0
- package/dist/report/agent-card/document.d.ts +7 -0
- package/dist/report/agent-card/document.d.ts.map +1 -0
- package/dist/report/agent-card/document.js +144 -0
- package/dist/report/agent-card/document.js.map +1 -0
- package/dist/report/agent-card/types.d.ts +77 -0
- package/dist/report/agent-card/types.d.ts.map +1 -0
- package/dist/report/agent-card/types.js +3 -0
- package/dist/report/agent-card/types.js.map +1 -0
- package/dist/report/assets/Indemn_PrimaryLogo_Iris.png +0 -0
- package/dist/report/assets/assets/Indemn_PrimaryLogo_Iris.png +0 -0
- package/dist/report/assets/assets/fonts/Barlow-Bold.ttf +0 -0
- package/dist/report/assets/assets/fonts/Barlow-Medium.ttf +0 -0
- package/dist/report/assets/assets/fonts/Barlow-Regular.ttf +0 -0
- package/dist/report/assets/assets/fonts/Barlow-SemiBold.ttf +0 -0
- package/dist/report/assets/fonts/Barlow-Bold.ttf +0 -0
- package/dist/report/assets/fonts/Barlow-Medium.ttf +0 -0
- package/dist/report/assets/fonts/Barlow-Regular.ttf +0 -0
- package/dist/report/assets/fonts/Barlow-SemiBold.ttf +0 -0
- package/dist/report/eval-report/cover.d.ts +16 -0
- package/dist/report/eval-report/cover.d.ts.map +1 -0
- package/dist/report/eval-report/cover.js +8 -0
- package/dist/report/eval-report/cover.js.map +1 -0
- package/dist/report/eval-report/document.d.ts +19 -0
- package/dist/report/eval-report/document.d.ts.map +1 -0
- package/dist/report/eval-report/document.js +32 -0
- package/dist/report/eval-report/document.js.map +1 -0
- package/dist/report/eval-report/example-page.d.ts +11 -0
- package/dist/report/eval-report/example-page.d.ts.map +1 -0
- package/dist/report/eval-report/example-page.js +18 -0
- package/dist/report/eval-report/example-page.js.map +1 -0
- package/dist/report/eval-report/item-page.d.ts +9 -0
- package/dist/report/eval-report/item-page.d.ts.map +1 -0
- package/dist/report/eval-report/item-page.js +72 -0
- package/dist/report/eval-report/item-page.js.map +1 -0
- package/dist/report/eval-report/matrix-page.d.ts +8 -0
- package/dist/report/eval-report/matrix-page.d.ts.map +1 -0
- package/dist/report/eval-report/matrix-page.js +31 -0
- package/dist/report/eval-report/matrix-page.js.map +1 -0
- package/dist/report/eval-report/types.d.ts +69 -0
- package/dist/report/eval-report/types.d.ts.map +1 -0
- package/dist/report/eval-report/types.js +7 -0
- package/dist/report/eval-report/types.js.map +1 -0
- package/dist/report/eval-report/v2-cover.d.ts +9 -0
- package/dist/report/eval-report/v2-cover.d.ts.map +1 -0
- package/dist/report/eval-report/v2-cover.js +32 -0
- package/dist/report/eval-report/v2-cover.js.map +1 -0
- package/dist/report/export.d.ts +17 -0
- package/dist/report/export.d.ts.map +1 -0
- package/dist/report/export.js +327 -0
- package/dist/report/export.js.map +1 -0
- package/dist/report/generate.d.ts +7 -0
- package/dist/report/generate.d.ts.map +1 -0
- package/dist/report/generate.js +30 -0
- package/dist/report/generate.js.map +1 -0
- package/dist/report/scoring.d.ts +90 -0
- package/dist/report/scoring.d.ts.map +1 -0
- package/dist/report/scoring.js +174 -0
- package/dist/report/scoring.js.map +1 -0
- package/dist/report/styles.d.ts +111 -0
- package/dist/report/styles.d.ts.map +1 -0
- package/dist/report/styles.js +134 -0
- package/dist/report/styles.js.map +1 -0
- package/docs/plans/2026-03-13-cli-exports.md +819 -0
- package/package.json +14 -4
- package/skills/eval-analysis/SKILL.md +178 -0
- package/skills/eval-analysis/references/data-shapes.md +279 -0
- package/src/cli/agents.ts +22 -0
- package/src/cli/eval.ts +42 -0
- package/src/mcp/tools.ts +50 -0
- package/src/report/agent-card/cover.tsx +232 -0
- package/src/report/agent-card/document.tsx +582 -0
- package/src/report/agent-card/types.ts +86 -0
- package/src/report/assets/Indemn_PrimaryLogo_Iris.png +0 -0
- package/src/report/assets/fonts/Barlow-Bold.ttf +0 -0
- package/src/report/assets/fonts/Barlow-Medium.ttf +0 -0
- package/src/report/assets/fonts/Barlow-Regular.ttf +0 -0
- package/src/report/assets/fonts/Barlow-SemiBold.ttf +0 -0
- package/src/report/eval-report/cover.tsx +69 -0
- package/src/report/eval-report/document.tsx +105 -0
- package/src/report/eval-report/example-page.tsx +121 -0
- package/src/report/eval-report/item-page.tsx +211 -0
- package/src/report/eval-report/matrix-page.tsx +124 -0
- package/src/report/eval-report/types.ts +77 -0
- package/src/report/eval-report/v2-cover.tsx +102 -0
- package/src/report/export.ts +394 -0
- package/src/report/generate.tsx +37 -0
- package/src/report/scoring.ts +281 -0
- package/src/report/styles.ts +138 -0
- package/tsconfig.json +2 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// src/report/scoring.ts — Scoring utilities ported from dashboard
|
|
2
|
+
// Pure arithmetic, no browser dependencies
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Thresholds
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
export const SCORE_THRESHOLDS = {
|
|
9
|
+
SUCCESS: 0.70,
|
|
10
|
+
WARNING: 0.50,
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Types
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export interface ScoreMetrics {
|
|
18
|
+
criteriaRate: number | null; // 0-1, null when no data
|
|
19
|
+
rubricRate: number | null; // 0-1, null when no rubric data
|
|
20
|
+
criteriaPassed: number;
|
|
21
|
+
criteriaTotal: number;
|
|
22
|
+
rubricRulesPassed: number;
|
|
23
|
+
rubricRulesTotal: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type ScoreColor = 'success' | 'warning' | 'error';
|
|
27
|
+
|
|
28
|
+
export interface ScoreColorClasses {
|
|
29
|
+
text: string;
|
|
30
|
+
bg: string;
|
|
31
|
+
bar: string;
|
|
32
|
+
hex: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Minimal types for scoring functions
|
|
36
|
+
export interface ScoringRun {
|
|
37
|
+
status?: string;
|
|
38
|
+
passed?: number;
|
|
39
|
+
completed?: number;
|
|
40
|
+
criteria_passed?: number;
|
|
41
|
+
criteria_total?: number;
|
|
42
|
+
rubric_rules_passed?: number;
|
|
43
|
+
rubric_rules_total?: number;
|
|
44
|
+
component_scores?: Record<string, { score?: number; total?: number; passed?: number }>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ScoringResult {
|
|
48
|
+
criteria_scores?: Array<{ passed: boolean }>;
|
|
49
|
+
rubric_scores?: Array<{ passed: boolean }>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// V1 matrix types
|
|
53
|
+
export type Severity = 'High' | 'Medium' | 'Low';
|
|
54
|
+
|
|
55
|
+
export interface EvaluatorInfo {
|
|
56
|
+
key: string;
|
|
57
|
+
name: string;
|
|
58
|
+
severity: Severity;
|
|
59
|
+
prompt?: string;
|
|
60
|
+
model?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface MatrixCell {
|
|
64
|
+
score: number;
|
|
65
|
+
comment: string | null;
|
|
66
|
+
passed: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface MatrixRow {
|
|
70
|
+
resultId: string;
|
|
71
|
+
testCaseId: string;
|
|
72
|
+
question: string;
|
|
73
|
+
response: string;
|
|
74
|
+
cells: Record<string, MatrixCell>;
|
|
75
|
+
avgScore: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface MatrixData {
|
|
79
|
+
evaluators: EvaluatorInfo[];
|
|
80
|
+
rows: MatrixRow[];
|
|
81
|
+
columnAverages: Record<string, number>;
|
|
82
|
+
overallAverage: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface WeightConfig {
|
|
86
|
+
High: number;
|
|
87
|
+
Medium: number;
|
|
88
|
+
Low: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const DEFAULT_WEIGHTS: WeightConfig = {
|
|
92
|
+
High: 2,
|
|
93
|
+
Medium: 1,
|
|
94
|
+
Low: 0.5,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Helpers
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
function sumComponentScores(cs: Record<string, { score?: number; total?: number; passed?: number }>): { passed: number; total: number } {
|
|
102
|
+
const scopes = ['prompt', 'knowledge_base', 'function', 'general'] as const;
|
|
103
|
+
let passed = 0;
|
|
104
|
+
let total = 0;
|
|
105
|
+
for (const scope of scopes) {
|
|
106
|
+
passed += cs[scope]?.passed ?? 0;
|
|
107
|
+
total += cs[scope]?.total ?? 0;
|
|
108
|
+
}
|
|
109
|
+
return { passed, total };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Run-level scoring
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
export function getRunScoreMetrics(run: ScoringRun): ScoreMetrics {
|
|
117
|
+
let criteriaPassed: number;
|
|
118
|
+
let criteriaTotal: number;
|
|
119
|
+
let rubricRulesPassed: number;
|
|
120
|
+
let rubricRulesTotal: number;
|
|
121
|
+
|
|
122
|
+
if (run.criteria_total !== undefined && run.criteria_total > 0) {
|
|
123
|
+
criteriaPassed = run.criteria_passed ?? 0;
|
|
124
|
+
criteriaTotal = run.criteria_total;
|
|
125
|
+
} else {
|
|
126
|
+
criteriaPassed = run.passed ?? 0;
|
|
127
|
+
criteriaTotal = run.completed ?? 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const hasNewRubricFields = run.rubric_rules_total !== undefined;
|
|
131
|
+
if (hasNewRubricFields) {
|
|
132
|
+
rubricRulesPassed = run.rubric_rules_passed ?? 0;
|
|
133
|
+
rubricRulesTotal = run.rubric_rules_total ?? 0;
|
|
134
|
+
} else {
|
|
135
|
+
const cs = run.component_scores;
|
|
136
|
+
if (cs) {
|
|
137
|
+
const sums = sumComponentScores(cs);
|
|
138
|
+
rubricRulesPassed = sums.passed;
|
|
139
|
+
rubricRulesTotal = sums.total;
|
|
140
|
+
} else {
|
|
141
|
+
rubricRulesPassed = 0;
|
|
142
|
+
rubricRulesTotal = 0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const criteriaRate = criteriaTotal > 0 ? criteriaPassed / criteriaTotal : null;
|
|
147
|
+
const rubricRate = rubricRulesTotal > 0 ? rubricRulesPassed / rubricRulesTotal : null;
|
|
148
|
+
|
|
149
|
+
return { criteriaRate, rubricRate, criteriaPassed, criteriaTotal, rubricRulesPassed, rubricRulesTotal };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function getRunCriteriaScore(run: ScoringRun): number | null {
|
|
153
|
+
const { criteriaRate } = getRunScoreMetrics(run);
|
|
154
|
+
return criteriaRate !== null ? Math.round(criteriaRate * 100) : null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function getRunRubricScore(run: ScoringRun): number | null {
|
|
158
|
+
const { rubricRate } = getRunScoreMetrics(run);
|
|
159
|
+
return rubricRate !== null ? Math.round(rubricRate * 100) : null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Result-level scoring
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
export function getResultsScoreMetrics(results: ScoringResult[]): ScoreMetrics {
|
|
167
|
+
if (results.length === 0) {
|
|
168
|
+
return { criteriaRate: null, rubricRate: null, criteriaPassed: 0, criteriaTotal: 0, rubricRulesPassed: 0, rubricRulesTotal: 0 };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const allCriteria = results.flatMap((r) => r.criteria_scores || []);
|
|
172
|
+
const criteriaTotal = allCriteria.length;
|
|
173
|
+
const criteriaPassed = allCriteria.filter((c) => c.passed).length;
|
|
174
|
+
const criteriaRate = criteriaTotal > 0 ? criteriaPassed / criteriaTotal : null;
|
|
175
|
+
|
|
176
|
+
const allRubricScores = results.flatMap((r) => r.rubric_scores || []);
|
|
177
|
+
const rubricRulesTotal = allRubricScores.length;
|
|
178
|
+
const rubricRulesPassed = allRubricScores.filter((r) => r.passed).length;
|
|
179
|
+
const rubricRate = rubricRulesTotal > 0 ? rubricRulesPassed / rubricRulesTotal : null;
|
|
180
|
+
|
|
181
|
+
return { criteriaRate, rubricRate, criteriaPassed, criteriaTotal, rubricRulesPassed, rubricRulesTotal };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Aggregate pass rate
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
|
|
188
|
+
export function getAggregatePassRate(runs: ScoringRun[]): number | null {
|
|
189
|
+
const completed = runs.filter((r) => r.status === 'completed');
|
|
190
|
+
if (completed.length === 0) return null;
|
|
191
|
+
|
|
192
|
+
let totalPassed = 0;
|
|
193
|
+
let totalChecks = 0;
|
|
194
|
+
for (const run of completed) {
|
|
195
|
+
if (run.criteria_total !== undefined && run.criteria_total > 0) {
|
|
196
|
+
totalPassed += run.criteria_passed ?? 0;
|
|
197
|
+
totalChecks += run.criteria_total;
|
|
198
|
+
} else {
|
|
199
|
+
totalPassed += run.passed ?? 0;
|
|
200
|
+
totalChecks += run.completed ?? 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return totalChecks > 0 ? totalPassed / totalChecks : null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// Color utilities
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
export function getScoreColor(rate: number | null | undefined): ScoreColor {
|
|
211
|
+
if (rate === null || rate === undefined) return 'error';
|
|
212
|
+
if (rate >= SCORE_THRESHOLDS.SUCCESS) return 'success';
|
|
213
|
+
if (rate >= SCORE_THRESHOLDS.WARNING) return 'warning';
|
|
214
|
+
return 'error';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function getScoreColorClasses(rate: number | null | undefined): ScoreColorClasses {
|
|
218
|
+
const color = getScoreColor(rate);
|
|
219
|
+
switch (color) {
|
|
220
|
+
case 'success':
|
|
221
|
+
return { text: 'text-success', bg: 'bg-success/10', bar: 'bg-success', hex: '#22c55e' };
|
|
222
|
+
case 'warning':
|
|
223
|
+
return { text: 'text-warning', bg: 'bg-warning/10', bar: 'bg-warning', hex: '#f59e0b' };
|
|
224
|
+
case 'error':
|
|
225
|
+
return { text: 'text-error', bg: 'bg-error/10', bar: 'bg-error', hex: '#ef4444' };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function getScoreHexColor(rate: number | null | undefined): string {
|
|
230
|
+
return getScoreColorClasses(rate).hex;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
// Weighted score calculation (V1 reports)
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
export function calculateWeightedScores(
|
|
238
|
+
matrixData: MatrixData,
|
|
239
|
+
weights: WeightConfig,
|
|
240
|
+
): {
|
|
241
|
+
overall: number;
|
|
242
|
+
bySeverity: Record<Severity, { score: number; count: number }>;
|
|
243
|
+
} {
|
|
244
|
+
const bySeverity: Record<Severity, { total: number; weight: number; count: number }> = {
|
|
245
|
+
High: { total: 0, weight: 0, count: 0 },
|
|
246
|
+
Medium: { total: 0, weight: 0, count: 0 },
|
|
247
|
+
Low: { total: 0, weight: 0, count: 0 },
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
for (const evaluator of matrixData.evaluators) {
|
|
251
|
+
const avg = matrixData.columnAverages[evaluator.key] || 0;
|
|
252
|
+
const weight = weights[evaluator.severity];
|
|
253
|
+
bySeverity[evaluator.severity].total += avg * weight;
|
|
254
|
+
bySeverity[evaluator.severity].weight += weight;
|
|
255
|
+
bySeverity[evaluator.severity].count++;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let overallTotal = 0;
|
|
259
|
+
let overallWeight = 0;
|
|
260
|
+
|
|
261
|
+
const result: Record<Severity, { score: number; count: number }> = {
|
|
262
|
+
High: { score: 0, count: 0 },
|
|
263
|
+
Medium: { score: 0, count: 0 },
|
|
264
|
+
Low: { score: 0, count: 0 },
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
for (const severity of ['High', 'Medium', 'Low'] as Severity[]) {
|
|
268
|
+
const data = bySeverity[severity];
|
|
269
|
+
result[severity] = {
|
|
270
|
+
score: data.weight > 0 ? data.total / data.weight : 0,
|
|
271
|
+
count: data.count,
|
|
272
|
+
};
|
|
273
|
+
overallTotal += data.total;
|
|
274
|
+
overallWeight += data.weight;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
overall: overallWeight > 0 ? overallTotal / overallWeight : 0,
|
|
279
|
+
bySeverity: result,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// src/report/styles.ts — Brand styles and font registration for PDF reports
|
|
2
|
+
import { Font, StyleSheet } from '@react-pdf/renderer';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const assetsDir = join(__dirname, 'assets');
|
|
8
|
+
|
|
9
|
+
// Register Barlow font family from bundled files
|
|
10
|
+
Font.register({
|
|
11
|
+
family: 'Barlow',
|
|
12
|
+
fonts: [
|
|
13
|
+
{ src: join(assetsDir, 'fonts', 'Barlow-Regular.ttf'), fontWeight: 400 },
|
|
14
|
+
{ src: join(assetsDir, 'fonts', 'Barlow-Medium.ttf'), fontWeight: 500 },
|
|
15
|
+
{ src: join(assetsDir, 'fonts', 'Barlow-SemiBold.ttf'), fontWeight: 600 },
|
|
16
|
+
{ src: join(assetsDir, 'fonts', 'Barlow-Bold.ttf'), fontWeight: 700 },
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const logoPath = join(assetsDir, 'Indemn_PrimaryLogo_Iris.png');
|
|
21
|
+
|
|
22
|
+
// Brand colors from Indemn Brand Guide
|
|
23
|
+
export const colors = {
|
|
24
|
+
// Primary brand colors
|
|
25
|
+
iris: '#4752a3',
|
|
26
|
+
lilac: '#a67cb7',
|
|
27
|
+
eggplant: '#1e2553',
|
|
28
|
+
white: '#ffffff',
|
|
29
|
+
// Supporting brand colors
|
|
30
|
+
lime: '#e0da67',
|
|
31
|
+
olive: '#2a2b1a',
|
|
32
|
+
// Derived UI colors
|
|
33
|
+
background: '#f4f3f8',
|
|
34
|
+
muted: '#6b7094',
|
|
35
|
+
border: '#d4d7e3',
|
|
36
|
+
// Semantic colors
|
|
37
|
+
success: '#22c55e',
|
|
38
|
+
error: '#ef4444',
|
|
39
|
+
warning: '#f59e0b',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Shared styles
|
|
43
|
+
export const styles = StyleSheet.create({
|
|
44
|
+
page: {
|
|
45
|
+
fontFamily: 'Barlow',
|
|
46
|
+
fontSize: 11,
|
|
47
|
+
color: colors.eggplant,
|
|
48
|
+
backgroundColor: colors.white,
|
|
49
|
+
padding: 40,
|
|
50
|
+
},
|
|
51
|
+
pageHeader: {
|
|
52
|
+
flexDirection: 'row',
|
|
53
|
+
justifyContent: 'space-between',
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
marginBottom: 24,
|
|
56
|
+
paddingBottom: 12,
|
|
57
|
+
borderBottomWidth: 1,
|
|
58
|
+
borderBottomColor: colors.border,
|
|
59
|
+
},
|
|
60
|
+
pageTitle: {
|
|
61
|
+
fontSize: 18,
|
|
62
|
+
fontWeight: 600,
|
|
63
|
+
color: colors.iris,
|
|
64
|
+
},
|
|
65
|
+
pageNumber: {
|
|
66
|
+
fontSize: 9,
|
|
67
|
+
color: colors.muted,
|
|
68
|
+
},
|
|
69
|
+
sectionTitle: {
|
|
70
|
+
fontSize: 14,
|
|
71
|
+
fontWeight: 600,
|
|
72
|
+
color: colors.iris,
|
|
73
|
+
marginBottom: 12,
|
|
74
|
+
},
|
|
75
|
+
bodyText: {
|
|
76
|
+
fontSize: 11,
|
|
77
|
+
fontWeight: 400,
|
|
78
|
+
color: colors.eggplant,
|
|
79
|
+
lineHeight: 1.5,
|
|
80
|
+
marginBottom: 8,
|
|
81
|
+
},
|
|
82
|
+
caption: {
|
|
83
|
+
fontSize: 9,
|
|
84
|
+
fontWeight: 500,
|
|
85
|
+
color: colors.muted,
|
|
86
|
+
},
|
|
87
|
+
card: {
|
|
88
|
+
backgroundColor: colors.background,
|
|
89
|
+
borderRadius: 6,
|
|
90
|
+
padding: 16,
|
|
91
|
+
marginBottom: 12,
|
|
92
|
+
},
|
|
93
|
+
metricValue: {
|
|
94
|
+
fontSize: 28,
|
|
95
|
+
fontWeight: 700,
|
|
96
|
+
color: colors.eggplant,
|
|
97
|
+
},
|
|
98
|
+
metricLabel: {
|
|
99
|
+
fontSize: 10,
|
|
100
|
+
fontWeight: 500,
|
|
101
|
+
color: colors.muted,
|
|
102
|
+
marginTop: 4,
|
|
103
|
+
},
|
|
104
|
+
row: {
|
|
105
|
+
flexDirection: 'row',
|
|
106
|
+
},
|
|
107
|
+
col: {
|
|
108
|
+
flex: 1,
|
|
109
|
+
},
|
|
110
|
+
footer: {
|
|
111
|
+
position: 'absolute',
|
|
112
|
+
bottom: 30,
|
|
113
|
+
left: 40,
|
|
114
|
+
right: 40,
|
|
115
|
+
flexDirection: 'row',
|
|
116
|
+
justifyContent: 'space-between',
|
|
117
|
+
alignItems: 'center',
|
|
118
|
+
paddingTop: 12,
|
|
119
|
+
borderTopWidth: 1,
|
|
120
|
+
borderTopColor: colors.border,
|
|
121
|
+
},
|
|
122
|
+
// Evaluation-specific styles
|
|
123
|
+
scorePass: {
|
|
124
|
+
color: colors.success,
|
|
125
|
+
},
|
|
126
|
+
scoreFail: {
|
|
127
|
+
color: colors.error,
|
|
128
|
+
},
|
|
129
|
+
severityHigh: {
|
|
130
|
+
color: '#3a4389', // Dark iris
|
|
131
|
+
},
|
|
132
|
+
severityMedium: {
|
|
133
|
+
color: colors.iris, // Standard iris
|
|
134
|
+
},
|
|
135
|
+
severityLow: {
|
|
136
|
+
color: '#7c85c0', // Light iris
|
|
137
|
+
},
|
|
138
|
+
});
|