@vibecheckai/cli 3.2.5 → 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/.generated +25 -25
- package/bin/dev/run-v2-torture.js +30 -30
- package/bin/registry.js +192 -5
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
- 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/api-client.js +269 -0
- package/bin/runners/lib/auth-truth.js +193 -193
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/backup.js +62 -62
- package/bin/runners/lib/billing.js +107 -107
- package/bin/runners/lib/claims.js +118 -118
- package/bin/runners/lib/cli-output.js +7 -1
- package/bin/runners/lib/cli-ui.js +540 -540
- package/bin/runners/lib/contracts/auth-contract.js +202 -202
- package/bin/runners/lib/contracts/env-contract.js +181 -181
- package/bin/runners/lib/contracts/external-contract.js +206 -206
- package/bin/runners/lib/contracts/guard.js +168 -168
- package/bin/runners/lib/contracts/index.js +89 -89
- package/bin/runners/lib/contracts/plan-validator.js +311 -311
- package/bin/runners/lib/contracts/route-contract.js +199 -199
- package/bin/runners/lib/contracts.js +804 -804
- package/bin/runners/lib/detect.js +89 -89
- package/bin/runners/lib/doctor/autofix.js +254 -254
- package/bin/runners/lib/doctor/index.js +37 -37
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
- package/bin/runners/lib/doctor/modules/index.js +46 -46
- package/bin/runners/lib/doctor/modules/network.js +250 -250
- package/bin/runners/lib/doctor/modules/project.js +312 -312
- package/bin/runners/lib/doctor/modules/runtime.js +224 -224
- package/bin/runners/lib/doctor/modules/security.js +348 -348
- package/bin/runners/lib/doctor/modules/system.js +213 -213
- package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
- package/bin/runners/lib/doctor/reporter.js +262 -262
- package/bin/runners/lib/doctor/service.js +262 -262
- package/bin/runners/lib/doctor/types.js +113 -113
- package/bin/runners/lib/doctor/ui.js +263 -263
- package/bin/runners/lib/doctor-v2.js +608 -608
- package/bin/runners/lib/drift.js +425 -425
- package/bin/runners/lib/enforcement.js +72 -72
- package/bin/runners/lib/enterprise-detect.js +603 -603
- package/bin/runners/lib/enterprise-init.js +942 -942
- package/bin/runners/lib/env-resolver.js +417 -417
- package/bin/runners/lib/env-template.js +66 -66
- package/bin/runners/lib/env.js +189 -189
- package/bin/runners/lib/error-handler.js +16 -9
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/extractors/client-calls.js +990 -990
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
- package/bin/runners/lib/extractors/fastify-routes.js +426 -426
- package/bin/runners/lib/extractors/index.js +363 -363
- package/bin/runners/lib/extractors/next-routes.js +524 -524
- package/bin/runners/lib/extractors/proof-graph.js +431 -431
- package/bin/runners/lib/extractors/route-matcher.js +451 -451
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
- package/bin/runners/lib/extractors/ui-bindings.js +547 -547
- package/bin/runners/lib/findings-schema.js +281 -281
- package/bin/runners/lib/firewall-prompt.js +50 -50
- package/bin/runners/lib/global-flags.js +37 -0
- package/bin/runners/lib/graph/graph-builder.js +265 -265
- package/bin/runners/lib/graph/html-renderer.js +413 -413
- package/bin/runners/lib/graph/index.js +32 -32
- package/bin/runners/lib/graph/runtime-collector.js +215 -215
- package/bin/runners/lib/graph/static-extractor.js +518 -518
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/html-report.js +650 -650
- package/bin/runners/lib/llm.js +75 -75
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/meter.js +61 -61
- package/bin/runners/lib/missions/evidence.js +126 -126
- package/bin/runners/lib/patch.js +40 -40
- package/bin/runners/lib/permissions/auth-model.js +213 -213
- package/bin/runners/lib/permissions/idor-prover.js +205 -205
- package/bin/runners/lib/permissions/index.js +45 -45
- package/bin/runners/lib/permissions/matrix-builder.js +198 -198
- package/bin/runners/lib/pkgjson.js +28 -28
- package/bin/runners/lib/policy.js +295 -295
- package/bin/runners/lib/preflight.js +142 -142
- package/bin/runners/lib/reality/correlation-detectors.js +359 -359
- package/bin/runners/lib/reality/index.js +318 -318
- package/bin/runners/lib/reality/request-hashing.js +416 -416
- package/bin/runners/lib/reality/request-mapper.js +453 -453
- package/bin/runners/lib/reality/safety-rails.js +463 -463
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
- package/bin/runners/lib/reality/toast-detector.js +393 -393
- package/bin/runners/lib/reality-findings.js +84 -84
- package/bin/runners/lib/receipts.js +179 -179
- package/bin/runners/lib/redact.js +29 -29
- package/bin/runners/lib/replay/capsule-manager.js +154 -154
- package/bin/runners/lib/replay/index.js +263 -263
- package/bin/runners/lib/replay/player.js +348 -348
- package/bin/runners/lib/replay/recorder.js +331 -331
- package/bin/runners/lib/report.js +135 -135
- package/bin/runners/lib/route-detection.js +1140 -1140
- package/bin/runners/lib/sandbox/index.js +59 -59
- package/bin/runners/lib/sandbox/proof-chain.js +399 -399
- package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
- package/bin/runners/lib/sandbox/worktree.js +174 -174
- package/bin/runners/lib/schema-validator.js +350 -350
- package/bin/runners/lib/schemas/contracts.schema.json +160 -160
- package/bin/runners/lib/schemas/finding.schema.json +100 -100
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
- package/bin/runners/lib/schemas/validator.js +438 -438
- package/bin/runners/lib/score-history.js +282 -282
- package/bin/runners/lib/share-pack.js +239 -239
- package/bin/runners/lib/snippets.js +67 -67
- package/bin/runners/lib/unified-cli-output.js +604 -0
- package/bin/runners/lib/upsell.js +658 -510
- package/bin/runners/lib/usage.js +153 -153
- package/bin/runners/lib/validate-patch.js +156 -156
- package/bin/runners/lib/verdict-engine.js +628 -628
- package/bin/runners/reality/engine.js +917 -917
- package/bin/runners/reality/flows.js +122 -122
- package/bin/runners/reality/report.js +378 -378
- package/bin/runners/reality/session.js +193 -193
- package/bin/runners/runAgent.d.ts +5 -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/runFirewall.d.ts +5 -0
- package/bin/runners/runFirewallHook.d.ts +5 -0
- package/bin/runners/runFix.js +6 -5
- package/bin/runners/runGuard.js +262 -168
- 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 +145 -44
- package/bin/runners/runShip.js +3 -4
- package/bin/runners/runTruth.d.ts +5 -0
- 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 +1199 -208
- package/mcp-server/lib/api-client.cjs +305 -0
- 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 +351 -136
- package/mcp-server/tools/index.js +72 -72
- 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
|
+
};
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
// bin/runners/lib/backup.js
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
|
|
5
|
-
function ensureDir(p) {
|
|
6
|
-
fs.mkdirSync(p, { recursive: true });
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function backupFiles(repoRoot, fileRelPaths, backupRoot) {
|
|
10
|
-
ensureDir(backupRoot);
|
|
11
|
-
|
|
12
|
-
const saved = [];
|
|
13
|
-
for (const rel of fileRelPaths) {
|
|
14
|
-
const abs = path.join(repoRoot, rel);
|
|
15
|
-
if (!fs.existsSync(abs)) {
|
|
16
|
-
saved.push({ rel, existed: false });
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const dest = path.join(backupRoot, rel);
|
|
21
|
-
ensureDir(path.dirname(dest));
|
|
22
|
-
fs.copyFileSync(abs, dest);
|
|
23
|
-
saved.push({ rel, existed: true });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
fs.writeFileSync(
|
|
27
|
-
path.join(backupRoot, "_manifest.json"),
|
|
28
|
-
JSON.stringify({ saved }, null, 2),
|
|
29
|
-
"utf8"
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
return saved;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function restoreBackup(repoRoot, backupRoot) {
|
|
36
|
-
const manifestPath = path.join(backupRoot, "_manifest.json");
|
|
37
|
-
if (!fs.existsSync(manifestPath)) {
|
|
38
|
-
return { ok: false, error: "backup manifest missing" };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
42
|
-
const saved = manifest.saved || [];
|
|
43
|
-
|
|
44
|
-
for (const s of saved) {
|
|
45
|
-
const abs = path.join(repoRoot, s.rel);
|
|
46
|
-
const bak = path.join(backupRoot, s.rel);
|
|
47
|
-
|
|
48
|
-
if (!s.existed) {
|
|
49
|
-
if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (fs.existsSync(bak)) {
|
|
54
|
-
ensureDir(path.dirname(abs));
|
|
55
|
-
fs.copyFileSync(bak, abs);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { ok: true };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
module.exports = { backupFiles, restoreBackup };
|
|
1
|
+
// bin/runners/lib/backup.js
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
function ensureDir(p) {
|
|
6
|
+
fs.mkdirSync(p, { recursive: true });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function backupFiles(repoRoot, fileRelPaths, backupRoot) {
|
|
10
|
+
ensureDir(backupRoot);
|
|
11
|
+
|
|
12
|
+
const saved = [];
|
|
13
|
+
for (const rel of fileRelPaths) {
|
|
14
|
+
const abs = path.join(repoRoot, rel);
|
|
15
|
+
if (!fs.existsSync(abs)) {
|
|
16
|
+
saved.push({ rel, existed: false });
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const dest = path.join(backupRoot, rel);
|
|
21
|
+
ensureDir(path.dirname(dest));
|
|
22
|
+
fs.copyFileSync(abs, dest);
|
|
23
|
+
saved.push({ rel, existed: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fs.writeFileSync(
|
|
27
|
+
path.join(backupRoot, "_manifest.json"),
|
|
28
|
+
JSON.stringify({ saved }, null, 2),
|
|
29
|
+
"utf8"
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return saved;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function restoreBackup(repoRoot, backupRoot) {
|
|
36
|
+
const manifestPath = path.join(backupRoot, "_manifest.json");
|
|
37
|
+
if (!fs.existsSync(manifestPath)) {
|
|
38
|
+
return { ok: false, error: "backup manifest missing" };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
42
|
+
const saved = manifest.saved || [];
|
|
43
|
+
|
|
44
|
+
for (const s of saved) {
|
|
45
|
+
const abs = path.join(repoRoot, s.rel);
|
|
46
|
+
const bak = path.join(backupRoot, s.rel);
|
|
47
|
+
|
|
48
|
+
if (!s.existed) {
|
|
49
|
+
if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(bak)) {
|
|
54
|
+
ensureDir(path.dirname(abs));
|
|
55
|
+
fs.copyFileSync(bak, abs);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { ok: true };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { backupFiles, restoreBackup };
|