@vibecheckai/cli 3.2.6 → 3.3.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/bin/registry.js +192 -5
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/analyzers.js +81 -18
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/cli-output.js +7 -1
- package/bin/runners/lib/error-handler.js +16 -9
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/global-flags.js +37 -0
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/unified-cli-output.js +604 -0
- package/bin/runners/lib/upsell.js +148 -0
- package/bin/runners/runApprove.js +1200 -0
- package/bin/runners/runAuth.js +324 -95
- package/bin/runners/runCheckpoint.js +39 -21
- package/bin/runners/runClassify.js +859 -0
- package/bin/runners/runContext.js +136 -24
- package/bin/runners/runDoctor.js +108 -68
- package/bin/runners/runFix.js +6 -5
- package/bin/runners/runGuard.js +212 -118
- package/bin/runners/runInit.js +3 -2
- package/bin/runners/runMcp.js +130 -52
- package/bin/runners/runPolish.js +43 -20
- package/bin/runners/runProve.js +1 -2
- package/bin/runners/runReport.js +3 -2
- package/bin/runners/runScan.js +63 -44
- package/bin/runners/runShip.js +3 -4
- package/bin/runners/runValidate.js +19 -2
- package/bin/runners/runWatch.js +104 -53
- package/bin/vibecheck.js +106 -19
- package/mcp-server/HARDENING_SUMMARY.md +299 -0
- package/mcp-server/agent-firewall-interceptor.js +367 -31
- package/mcp-server/authority-tools.js +569 -0
- package/mcp-server/conductor/conflict-resolver.js +588 -0
- package/mcp-server/conductor/execution-planner.js +544 -0
- package/mcp-server/conductor/index.js +377 -0
- package/mcp-server/conductor/lock-manager.js +615 -0
- package/mcp-server/conductor/request-queue.js +550 -0
- package/mcp-server/conductor/session-manager.js +500 -0
- package/mcp-server/conductor/tools.js +510 -0
- package/mcp-server/index.js +1149 -243
- package/mcp-server/lib/{api-client.js → api-client.cjs} +40 -4
- package/mcp-server/lib/logger.cjs +30 -0
- package/mcp-server/logger.js +173 -0
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/tier-auth.js +245 -35
- package/mcp-server/truth-firewall-tools.js +145 -15
- package/mcp-server/vibecheck-tools.js +2 -2
- package/package.json +2 -3
- package/mcp-server/index.old.js +0 -4137
- package/mcp-server/package-lock.json +0 -165
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authority Badge Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates SVG badges for PROCEED verdicts from the Authority System.
|
|
5
|
+
* Part of the PRO tier - requires verified verdicts.
|
|
6
|
+
*
|
|
7
|
+
* Badge Types:
|
|
8
|
+
* - authority-approved: Standard approval badge
|
|
9
|
+
* - safe-consolidation: Safe Consolidation authority badge
|
|
10
|
+
* - inventory: Inventory analysis badge
|
|
11
|
+
*
|
|
12
|
+
* Output formats:
|
|
13
|
+
* - SVG (default, scalable)
|
|
14
|
+
* - Markdown (for README embedding)
|
|
15
|
+
* - HTML (for web embedding)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const path = require("path");
|
|
19
|
+
const fs = require("fs");
|
|
20
|
+
|
|
21
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
22
|
+
// COLOR PALETTE
|
|
23
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
24
|
+
|
|
25
|
+
const BADGE_COLORS = {
|
|
26
|
+
PROCEED: {
|
|
27
|
+
background: '#22C55E',
|
|
28
|
+
text: '#FFFFFF',
|
|
29
|
+
},
|
|
30
|
+
DEFER: {
|
|
31
|
+
background: '#F59E0B',
|
|
32
|
+
text: '#000000',
|
|
33
|
+
},
|
|
34
|
+
STOP: {
|
|
35
|
+
background: '#EF4444',
|
|
36
|
+
text: '#FFFFFF',
|
|
37
|
+
},
|
|
38
|
+
neutral: {
|
|
39
|
+
background: '#555555',
|
|
40
|
+
text: '#FFFFFF',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
45
|
+
// SVG TEMPLATES
|
|
46
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Generate an SVG badge
|
|
50
|
+
*/
|
|
51
|
+
function generateSVGBadge(options) {
|
|
52
|
+
const {
|
|
53
|
+
label = 'Authority Approved',
|
|
54
|
+
message,
|
|
55
|
+
color,
|
|
56
|
+
textColor = '#FFFFFF',
|
|
57
|
+
logo = null,
|
|
58
|
+
style = 'flat',
|
|
59
|
+
} = options;
|
|
60
|
+
|
|
61
|
+
// Calculate widths based on text length
|
|
62
|
+
const labelWidth = Math.max(label.length * 7 + 10, 80);
|
|
63
|
+
const messageWidth = Math.max(message.length * 7 + 10, 50);
|
|
64
|
+
const totalWidth = labelWidth + messageWidth;
|
|
65
|
+
|
|
66
|
+
if (style === 'flat-square') {
|
|
67
|
+
return generateFlatSquareBadge({ label, message, color, textColor, labelWidth, messageWidth, totalWidth, logo });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return generateFlatBadge({ label, message, color, textColor, labelWidth, messageWidth, totalWidth, logo });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function generateFlatBadge(opts) {
|
|
74
|
+
const { label, message, color, textColor, labelWidth, messageWidth, totalWidth, logo } = opts;
|
|
75
|
+
|
|
76
|
+
let logoSvg = '';
|
|
77
|
+
let logoOffset = 0;
|
|
78
|
+
|
|
79
|
+
if (logo === 'vibecheck') {
|
|
80
|
+
logoOffset = 16;
|
|
81
|
+
logoSvg = `
|
|
82
|
+
<g transform="translate(5, 3)">
|
|
83
|
+
<path fill="${textColor}" d="M7 1l7 12H0L7 1zm0 3l-4 7h8L7 4z"/>
|
|
84
|
+
</g>`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth + logoOffset}" height="20" role="img" aria-label="${label}: ${message}">
|
|
88
|
+
<title>${label}: ${message}</title>
|
|
89
|
+
<linearGradient id="s" x2="0" y2="100%">
|
|
90
|
+
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
|
91
|
+
<stop offset="1" stop-opacity=".1"/>
|
|
92
|
+
</linearGradient>
|
|
93
|
+
<clipPath id="r">
|
|
94
|
+
<rect width="${totalWidth + logoOffset}" height="20" rx="3" fill="#fff"/>
|
|
95
|
+
</clipPath>
|
|
96
|
+
<g clip-path="url(#r)">
|
|
97
|
+
<rect width="${labelWidth + logoOffset}" height="20" fill="#555"/>
|
|
98
|
+
<rect x="${labelWidth + logoOffset}" width="${messageWidth}" height="20" fill="${color}"/>
|
|
99
|
+
<rect width="${totalWidth + logoOffset}" height="20" fill="url(#s)"/>
|
|
100
|
+
</g>
|
|
101
|
+
${logoSvg}
|
|
102
|
+
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
|
103
|
+
<text aria-hidden="true" x="${(labelWidth + logoOffset) / 2 + logoOffset/2}" y="15" fill="#010101" fill-opacity=".3">${label}</text>
|
|
104
|
+
<text x="${(labelWidth + logoOffset) / 2 + logoOffset/2}" y="14" fill="#fff">${label}</text>
|
|
105
|
+
<text aria-hidden="true" x="${labelWidth + logoOffset + messageWidth / 2}" y="15" fill="#010101" fill-opacity=".3">${message}</text>
|
|
106
|
+
<text x="${labelWidth + logoOffset + messageWidth / 2}" y="14" fill="${textColor}">${message}</text>
|
|
107
|
+
</g>
|
|
108
|
+
</svg>`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function generateFlatSquareBadge(opts) {
|
|
112
|
+
const { label, message, color, textColor, labelWidth, messageWidth, totalWidth, logo } = opts;
|
|
113
|
+
|
|
114
|
+
let logoSvg = '';
|
|
115
|
+
let logoOffset = 0;
|
|
116
|
+
|
|
117
|
+
if (logo === 'vibecheck') {
|
|
118
|
+
logoOffset = 16;
|
|
119
|
+
logoSvg = `
|
|
120
|
+
<g transform="translate(5, 3)">
|
|
121
|
+
<path fill="${textColor}" d="M7 1l7 12H0L7 1zm0 3l-4 7h8L7 4z"/>
|
|
122
|
+
</g>`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth + logoOffset}" height="20" role="img" aria-label="${label}: ${message}">
|
|
126
|
+
<title>${label}: ${message}</title>
|
|
127
|
+
<g shape-rendering="crispEdges">
|
|
128
|
+
<rect width="${labelWidth + logoOffset}" height="20" fill="#555"/>
|
|
129
|
+
<rect x="${labelWidth + logoOffset}" width="${messageWidth}" height="20" fill="${color}"/>
|
|
130
|
+
</g>
|
|
131
|
+
${logoSvg}
|
|
132
|
+
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="11">
|
|
133
|
+
<text x="${(labelWidth + logoOffset) / 2 + logoOffset/2}" y="14" fill="#fff">${label}</text>
|
|
134
|
+
<text x="${labelWidth + logoOffset + messageWidth / 2}" y="14" fill="${textColor}">${message}</text>
|
|
135
|
+
</g>
|
|
136
|
+
</svg>`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
140
|
+
// BADGE GENERATORS
|
|
141
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Generate an authority verdict badge
|
|
145
|
+
*/
|
|
146
|
+
function generateVerdictBadge(verdict, options = {}) {
|
|
147
|
+
const {
|
|
148
|
+
style = 'flat',
|
|
149
|
+
logo = 'vibecheck',
|
|
150
|
+
includeConfidence = true,
|
|
151
|
+
} = options;
|
|
152
|
+
|
|
153
|
+
const action = verdict.action || 'UNKNOWN';
|
|
154
|
+
const confidence = verdict.confidence || 0;
|
|
155
|
+
const authorityId = verdict.authority || 'authority';
|
|
156
|
+
|
|
157
|
+
const colors = BADGE_COLORS[action] || BADGE_COLORS.neutral;
|
|
158
|
+
|
|
159
|
+
let message = action;
|
|
160
|
+
if (includeConfidence && action !== 'STOP') {
|
|
161
|
+
message = `${action} ${Math.round(confidence * 100)}%`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return generateSVGBadge({
|
|
165
|
+
label: `Authority: ${authorityId}`,
|
|
166
|
+
message,
|
|
167
|
+
color: colors.background,
|
|
168
|
+
textColor: colors.text,
|
|
169
|
+
logo,
|
|
170
|
+
style,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Generate a simple "Authority Approved" badge
|
|
176
|
+
*/
|
|
177
|
+
function generateApprovedBadge(options = {}) {
|
|
178
|
+
const {
|
|
179
|
+
authority = 'vibecheck',
|
|
180
|
+
confidence = 100,
|
|
181
|
+
version = '1.0',
|
|
182
|
+
style = 'flat',
|
|
183
|
+
} = options;
|
|
184
|
+
|
|
185
|
+
return generateSVGBadge({
|
|
186
|
+
label: 'Authority Approved',
|
|
187
|
+
message: `${authority} v${version}`,
|
|
188
|
+
color: BADGE_COLORS.PROCEED.background,
|
|
189
|
+
textColor: BADGE_COLORS.PROCEED.text,
|
|
190
|
+
logo: 'vibecheck',
|
|
191
|
+
style,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Generate a Safe Consolidation badge
|
|
197
|
+
*/
|
|
198
|
+
function generateSafeConsolidationBadge(verdict, options = {}) {
|
|
199
|
+
const {
|
|
200
|
+
style = 'flat',
|
|
201
|
+
} = options;
|
|
202
|
+
|
|
203
|
+
const action = verdict.action || 'PROCEED';
|
|
204
|
+
const confidence = verdict.confidence || 0.95;
|
|
205
|
+
const colors = BADGE_COLORS[action] || BADGE_COLORS.PROCEED;
|
|
206
|
+
|
|
207
|
+
return generateSVGBadge({
|
|
208
|
+
label: 'Safe Consolidation',
|
|
209
|
+
message: `${action} ${Math.round(confidence * 100)}%`,
|
|
210
|
+
color: colors.background,
|
|
211
|
+
textColor: colors.text,
|
|
212
|
+
logo: 'vibecheck',
|
|
213
|
+
style,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Generate a CI status badge
|
|
219
|
+
*/
|
|
220
|
+
function generateCIBadge(verdict, options = {}) {
|
|
221
|
+
const {
|
|
222
|
+
style = 'flat',
|
|
223
|
+
ciName = 'CI',
|
|
224
|
+
} = options;
|
|
225
|
+
|
|
226
|
+
const action = verdict.action || 'UNKNOWN';
|
|
227
|
+
const exitCode = verdict.exitCode ?? (action === 'PROCEED' ? 0 : action === 'DEFER' ? 1 : 2);
|
|
228
|
+
|
|
229
|
+
let status, color;
|
|
230
|
+
if (exitCode === 0) {
|
|
231
|
+
status = 'passing';
|
|
232
|
+
color = BADGE_COLORS.PROCEED.background;
|
|
233
|
+
} else if (exitCode === 1) {
|
|
234
|
+
status = 'review';
|
|
235
|
+
color = BADGE_COLORS.DEFER.background;
|
|
236
|
+
} else {
|
|
237
|
+
status = 'failing';
|
|
238
|
+
color = BADGE_COLORS.STOP.background;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return generateSVGBadge({
|
|
242
|
+
label: ciName,
|
|
243
|
+
message: status,
|
|
244
|
+
color,
|
|
245
|
+
textColor: '#FFFFFF',
|
|
246
|
+
style,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
251
|
+
// OUTPUT FORMATTERS
|
|
252
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Format badge for markdown embedding
|
|
256
|
+
*/
|
|
257
|
+
function formatBadgeMarkdown(badge, options = {}) {
|
|
258
|
+
const {
|
|
259
|
+
altText = 'Authority Approved by VibeCheck',
|
|
260
|
+
link = 'https://vibecheckai.dev',
|
|
261
|
+
} = options;
|
|
262
|
+
|
|
263
|
+
// Encode SVG for data URI
|
|
264
|
+
const encoded = encodeURIComponent(badge)
|
|
265
|
+
.replace(/'/g, '%27')
|
|
266
|
+
.replace(/"/g, '%22');
|
|
267
|
+
|
|
268
|
+
const dataUri = `data:image/svg+xml,${encoded}`;
|
|
269
|
+
|
|
270
|
+
if (link) {
|
|
271
|
+
return `[](${link})`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return ``;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Format badge for HTML embedding
|
|
279
|
+
*/
|
|
280
|
+
function formatBadgeHTML(badge, options = {}) {
|
|
281
|
+
const {
|
|
282
|
+
altText = 'Authority Approved by VibeCheck',
|
|
283
|
+
link = 'https://vibecheckai.dev',
|
|
284
|
+
className = 'vibecheck-badge',
|
|
285
|
+
} = options;
|
|
286
|
+
|
|
287
|
+
// Encode SVG for data URI
|
|
288
|
+
const encoded = encodeURIComponent(badge)
|
|
289
|
+
.replace(/'/g, '%27')
|
|
290
|
+
.replace(/"/g, '%22');
|
|
291
|
+
|
|
292
|
+
const dataUri = `data:image/svg+xml,${encoded}`;
|
|
293
|
+
|
|
294
|
+
const img = `<img src="${dataUri}" alt="${altText}" class="${className}">`;
|
|
295
|
+
|
|
296
|
+
if (link) {
|
|
297
|
+
return `<a href="${link}" target="_blank" rel="noopener noreferrer">${img}</a>`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return img;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
304
|
+
// FILE OUTPUT
|
|
305
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Save badge to file
|
|
309
|
+
*/
|
|
310
|
+
async function saveBadge(badge, filePath, format = 'svg') {
|
|
311
|
+
const dir = path.dirname(filePath);
|
|
312
|
+
|
|
313
|
+
// Ensure directory exists
|
|
314
|
+
if (!fs.existsSync(dir)) {
|
|
315
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let content = badge;
|
|
319
|
+
let ext = '.svg';
|
|
320
|
+
|
|
321
|
+
if (format === 'markdown' || format === 'md') {
|
|
322
|
+
content = formatBadgeMarkdown(badge);
|
|
323
|
+
ext = '.md';
|
|
324
|
+
} else if (format === 'html') {
|
|
325
|
+
content = formatBadgeHTML(badge);
|
|
326
|
+
ext = '.html';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Ensure file has correct extension
|
|
330
|
+
let finalPath = filePath;
|
|
331
|
+
if (!filePath.endsWith(ext) && format !== 'svg') {
|
|
332
|
+
finalPath = filePath.replace(/\.[^.]+$/, ext);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
await fs.promises.writeFile(finalPath, content);
|
|
336
|
+
|
|
337
|
+
return finalPath;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Generate and save all badge variants
|
|
342
|
+
*/
|
|
343
|
+
async function generateAllBadges(verdict, outputDir, options = {}) {
|
|
344
|
+
const {
|
|
345
|
+
prefix = verdict.authority || 'authority',
|
|
346
|
+
} = options;
|
|
347
|
+
|
|
348
|
+
const badges = {};
|
|
349
|
+
|
|
350
|
+
// Main verdict badge
|
|
351
|
+
const verdictBadge = generateVerdictBadge(verdict, options);
|
|
352
|
+
badges.verdict = await saveBadge(
|
|
353
|
+
verdictBadge,
|
|
354
|
+
path.join(outputDir, `${prefix}-badge.svg`)
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
// If PROCEED, also generate approved badge
|
|
358
|
+
if (verdict.action === 'PROCEED') {
|
|
359
|
+
const approvedBadge = generateApprovedBadge({
|
|
360
|
+
authority: verdict.authority,
|
|
361
|
+
confidence: verdict.confidence,
|
|
362
|
+
version: verdict.version,
|
|
363
|
+
});
|
|
364
|
+
badges.approved = await saveBadge(
|
|
365
|
+
approvedBadge,
|
|
366
|
+
path.join(outputDir, `${prefix}-approved-badge.svg`)
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
// CI badge
|
|
370
|
+
const ciBadge = generateCIBadge(verdict);
|
|
371
|
+
badges.ci = await saveBadge(
|
|
372
|
+
ciBadge,
|
|
373
|
+
path.join(outputDir, `${prefix}-ci-badge.svg`)
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Generate markdown snippet
|
|
378
|
+
const mdContent = `# ${verdict.authority || 'Authority'} Badge
|
|
379
|
+
|
|
380
|
+
${formatBadgeMarkdown(verdictBadge, { altText: \`\${verdict.authority} - \${verdict.action}\` })}
|
|
381
|
+
|
|
382
|
+
## Embed Code
|
|
383
|
+
|
|
384
|
+
### Markdown
|
|
385
|
+
\`\`\`markdown
|
|
386
|
+
${formatBadgeMarkdown(verdictBadge, { altText: \`\${verdict.authority} - \${verdict.action}\` })}
|
|
387
|
+
\`\`\`
|
|
388
|
+
|
|
389
|
+
### HTML
|
|
390
|
+
\`\`\`html
|
|
391
|
+
${formatBadgeHTML(verdictBadge, { altText: \`\${verdict.authority} - \${verdict.action}\` })}
|
|
392
|
+
\`\`\`
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
Generated: ${new Date().toISOString()}
|
|
396
|
+
`;
|
|
397
|
+
|
|
398
|
+
badges.readme = await saveBadge(mdContent, path.join(outputDir, `${prefix}-BADGE.md`), 'md');
|
|
399
|
+
|
|
400
|
+
return badges;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
404
|
+
// EXPORTS
|
|
405
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
406
|
+
|
|
407
|
+
module.exports = {
|
|
408
|
+
// Badge generators
|
|
409
|
+
generateSVGBadge,
|
|
410
|
+
generateVerdictBadge,
|
|
411
|
+
generateApprovedBadge,
|
|
412
|
+
generateSafeConsolidationBadge,
|
|
413
|
+
generateCIBadge,
|
|
414
|
+
|
|
415
|
+
// Formatters
|
|
416
|
+
formatBadgeMarkdown,
|
|
417
|
+
formatBadgeHTML,
|
|
418
|
+
|
|
419
|
+
// File operations
|
|
420
|
+
saveBadge,
|
|
421
|
+
generateAllBadges,
|
|
422
|
+
|
|
423
|
+
// Constants
|
|
424
|
+
BADGE_COLORS,
|
|
425
|
+
};
|
|
@@ -19,6 +19,9 @@ const os = require("os");
|
|
|
19
19
|
const childProcess = require("child_process");
|
|
20
20
|
const chalk = require("chalk"); // Added for premium error reporting
|
|
21
21
|
|
|
22
|
+
// Re-export exit codes for backward compatibility
|
|
23
|
+
const { EXIT, verdictToExitCode } = require("./exit-codes");
|
|
24
|
+
|
|
22
25
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
23
26
|
// CONFIGURATION
|
|
24
27
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -388,7 +391,10 @@ module.exports = {
|
|
|
388
391
|
saveArtifact,
|
|
389
392
|
createJsonOutput,
|
|
390
393
|
writeJsonOutput,
|
|
391
|
-
exitCodeToVerdict,
|
|
394
|
+
exitCodeToVerdict, // Local function
|
|
395
|
+
// Re-exported from exit-codes.js
|
|
396
|
+
verdictToExitCode,
|
|
397
|
+
EXIT,
|
|
392
398
|
withStandardOutput,
|
|
393
399
|
parseStandardFlags,
|
|
394
400
|
};
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Standardized error handling for CLI runners
|
|
3
3
|
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* World-Class Error Handling
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
*
|
|
4
8
|
* Design principles:
|
|
5
9
|
* - Every error has a human-readable message
|
|
6
10
|
* - Every error suggests a next step
|
|
7
11
|
* - Exit codes are consistent and documented
|
|
12
|
+
* - Errors include "receipt" (file:line evidence) where possible
|
|
13
|
+
* - Debug mode shows stack traces
|
|
8
14
|
*/
|
|
9
15
|
|
|
16
|
+
const { EXIT, getExitInfo, getHint } = require("./exit-codes");
|
|
17
|
+
|
|
10
18
|
const colors = {
|
|
11
19
|
reset: "\x1b[0m",
|
|
12
20
|
red: "\x1b[31m",
|
|
@@ -24,16 +32,15 @@ const c = {
|
|
|
24
32
|
dim: (text) => `\x1b[2m${text}${colors.reset}`,
|
|
25
33
|
};
|
|
26
34
|
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
// IMPORTANT: These codes are part of the CLI contract - do not change without migration guide
|
|
35
|
+
// Re-export EXIT for backward compatibility
|
|
36
|
+
// NOTE: Prefer importing from exit-codes.js directly
|
|
30
37
|
const EXIT_CODES = {
|
|
31
|
-
SUCCESS:
|
|
32
|
-
POLICY_FAIL:
|
|
33
|
-
USER_ERROR:
|
|
34
|
-
SYSTEM_ERROR:
|
|
35
|
-
AUTH_FAILURE:
|
|
36
|
-
NETWORK_FAILURE:
|
|
38
|
+
SUCCESS: EXIT.SUCCESS,
|
|
39
|
+
POLICY_FAIL: EXIT.WARNINGS, // Findings above threshold (policy fail)
|
|
40
|
+
USER_ERROR: EXIT.USER_ERROR, // User error: invalid args, bad config
|
|
41
|
+
SYSTEM_ERROR: EXIT.INTERNAL_ERROR, // System error: crash, unexpected exceptions
|
|
42
|
+
AUTH_FAILURE: EXIT.AUTH_REQUIRED, // Auth/entitlement failure
|
|
43
|
+
NETWORK_FAILURE: EXIT.NETWORK_ERROR, // Network/backend failure
|
|
37
44
|
};
|
|
38
45
|
|
|
39
46
|
// Error-specific guidance
|