@vibecheckai/cli 3.1.0 → 3.1.1
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 +105 -105
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
- package/bin/runners/lib/analysis-core.js +271 -271
- package/bin/runners/lib/analyzers.js +579 -579
- package/bin/runners/lib/auth-truth.js +193 -193
- 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 +368 -368
- 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/detectors-v2.js +703 -703
- 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/entitlements-v2.js +490 -489
- 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/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/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/html-report.js +650 -650
- package/bin/runners/lib/init-wizard.js +308 -308
- package/bin/runners/lib/llm.js +75 -75
- package/bin/runners/lib/meter.js +61 -61
- package/bin/runners/lib/missions/evidence.js +126 -126
- package/bin/runners/lib/missions/plan.js +69 -69
- package/bin/runners/lib/missions/templates.js +192 -192
- 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-engine.js +447 -447
- package/bin/runners/lib/report-html.js +1499 -1499
- package/bin/runners/lib/report-templates.js +969 -969
- package/bin/runners/lib/report.js +135 -135
- package/bin/runners/lib/route-detection.js +1140 -1140
- package/bin/runners/lib/route-truth.js +477 -477
- 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/truth.js +667 -667
- package/bin/runners/lib/upsell.js +510 -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/runAuth.js +51 -0
- package/bin/runners/runClaimVerifier.js +483 -483
- package/bin/runners/runContext.js +56 -56
- package/bin/runners/runContextCompiler.js +385 -385
- package/bin/runners/runCtx.js +674 -674
- package/bin/runners/runCtxDiff.js +301 -301
- package/bin/runners/runCtxGuard.js +176 -176
- package/bin/runners/runCtxSync.js +116 -116
- package/bin/runners/runGate.js +17 -17
- package/bin/runners/runGraph.js +454 -454
- package/bin/runners/runGuard.js +168 -168
- package/bin/runners/runInitGha.js +164 -164
- package/bin/runners/runInstall.js +277 -277
- package/bin/runners/runInteractive.js +388 -388
- package/bin/runners/runLabs.js +340 -340
- package/bin/runners/runMissionGenerator.js +282 -282
- package/bin/runners/runPR.js +255 -255
- package/bin/runners/runPermissions.js +304 -304
- package/bin/runners/runPreflight.js +580 -553
- package/bin/runners/runProve.js +1252 -1252
- package/bin/runners/runReality.js +1328 -1328
- package/bin/runners/runReplay.js +499 -499
- package/bin/runners/runReport.js +584 -584
- package/bin/runners/runShare.js +212 -212
- package/bin/runners/runStatus.js +138 -138
- package/bin/runners/runTruthpack.js +636 -636
- package/bin/runners/runVerify.js +272 -272
- package/bin/runners/runWatch.js +407 -407
- package/bin/vibecheck.js +2 -1
- package/mcp-server/consolidated-tools.js +804 -804
- package/mcp-server/package.json +1 -1
- package/mcp-server/tools/index.js +72 -72
- package/mcp-server/truth-context.js +581 -581
- package/mcp-server/truth-firewall-tools.js +1500 -1500
- package/package.json +1 -1
- package/bin/runners/runProof.zip +0 -0
|
@@ -1,368 +1,368 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI Output Utilities - World-Class Consistency
|
|
3
|
-
*
|
|
4
|
-
* Provides standardized JSON output, run ID generation,
|
|
5
|
-
* and artifact management for all CLI commands.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
"use strict";
|
|
9
|
-
|
|
10
|
-
const fs = require("fs");
|
|
11
|
-
const path = require("path");
|
|
12
|
-
const crypto = require("crypto");
|
|
13
|
-
|
|
14
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
15
|
-
// RUN ID GENERATION
|
|
16
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Generate a unique run ID for tracking
|
|
20
|
-
*/
|
|
21
|
-
function generateRunId() {
|
|
22
|
-
return crypto.randomUUID();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
26
|
-
// OUTPUT DIRECTORY MANAGEMENT
|
|
27
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Get run directory paths
|
|
31
|
-
*/
|
|
32
|
-
function getRunPaths(runId, projectPath = process.cwd()) {
|
|
33
|
-
const runDir = path.join(projectPath, ".vibecheck", "runs", runId);
|
|
34
|
-
const artifactsDir = path.join(runDir, "artifacts");
|
|
35
|
-
|
|
36
|
-
// Ensure directories exist
|
|
37
|
-
if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
|
|
38
|
-
if (!fs.existsSync(artifactsDir)) fs.mkdirSync(artifactsDir, { recursive: true });
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
runDir,
|
|
42
|
-
artifactsDir,
|
|
43
|
-
manifestPath: path.join(runDir, "manifest.json"),
|
|
44
|
-
commandPath: path.join(runDir, "command.json"),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Save artifact to run directory
|
|
50
|
-
*/
|
|
51
|
-
function saveArtifact(runId, name, data, type = "json") {
|
|
52
|
-
const { artifactsDir } = getRunPaths(runId);
|
|
53
|
-
const artifactPath = path.join(artifactsDir, `${name}.${type}`);
|
|
54
|
-
|
|
55
|
-
if (type === "json") {
|
|
56
|
-
fs.writeFileSync(artifactPath, JSON.stringify(data, null, 2));
|
|
57
|
-
} else {
|
|
58
|
-
fs.writeFileSync(artifactPath, data);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return artifactPath;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
65
|
-
// JSON OUTPUT SCHEMA
|
|
66
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Create standardized JSON output
|
|
70
|
-
*/
|
|
71
|
-
function createJsonOutput(options) {
|
|
72
|
-
const {
|
|
73
|
-
runId,
|
|
74
|
-
command,
|
|
75
|
-
startTime,
|
|
76
|
-
exitCode,
|
|
77
|
-
verdict,
|
|
78
|
-
result = {},
|
|
79
|
-
tier = "free",
|
|
80
|
-
version = "1.0.0",
|
|
81
|
-
projectPath = process.cwd(),
|
|
82
|
-
artifacts = [],
|
|
83
|
-
} = options;
|
|
84
|
-
|
|
85
|
-
const output = {
|
|
86
|
-
runId,
|
|
87
|
-
command,
|
|
88
|
-
timestamp: new Date().toISOString(),
|
|
89
|
-
duration: startTime ? Date.now() - new Date(startTime).getTime() : null,
|
|
90
|
-
exitCode,
|
|
91
|
-
verdict,
|
|
92
|
-
result,
|
|
93
|
-
meta: {
|
|
94
|
-
tier,
|
|
95
|
-
version,
|
|
96
|
-
path: projectPath,
|
|
97
|
-
},
|
|
98
|
-
artifacts: artifacts.map(art => ({
|
|
99
|
-
type: art.type,
|
|
100
|
-
path: path.relative(projectPath, art.path),
|
|
101
|
-
description: art.description,
|
|
102
|
-
})),
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
return output;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Write JSON output to file or stdout
|
|
110
|
-
*/
|
|
111
|
-
function writeJsonOutput(output, outputPath) {
|
|
112
|
-
const jsonString = JSON.stringify(output, null, 2);
|
|
113
|
-
|
|
114
|
-
if (outputPath) {
|
|
115
|
-
fs.writeFileSync(outputPath, jsonString);
|
|
116
|
-
return outputPath;
|
|
117
|
-
} else {
|
|
118
|
-
console.log(jsonString);
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
124
|
-
// VERDCT MAPPING
|
|
125
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Map exit codes to verdict strings
|
|
129
|
-
*/
|
|
130
|
-
function exitCodeToVerdict(exitCode) {
|
|
131
|
-
switch (exitCode) {
|
|
132
|
-
case 0: return "SHIP";
|
|
133
|
-
case 1: return "WARN";
|
|
134
|
-
case 2: return "BLOCK";
|
|
135
|
-
case 3: return "FEATURE_DENIED";
|
|
136
|
-
case 4: return "INVALID_INPUT";
|
|
137
|
-
case 5: return "INTERNAL_ERROR";
|
|
138
|
-
default: return "UNKNOWN";
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Map verdict to exit code
|
|
144
|
-
*/
|
|
145
|
-
function verdictToExitCode(verdict) {
|
|
146
|
-
switch (verdict?.toUpperCase()) {
|
|
147
|
-
case "SHIP": return 0;
|
|
148
|
-
case "WARN": return 1;
|
|
149
|
-
case "BLOCK": return 2;
|
|
150
|
-
case "FEATURE_DENIED": return 3;
|
|
151
|
-
case "INVALID_INPUT": return 4;
|
|
152
|
-
case "INTERNAL_ERROR": return 5;
|
|
153
|
-
default: return 5;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
158
|
-
// COMMAND WRAPPER
|
|
159
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Wrap a command runner with standard output handling
|
|
163
|
-
*/
|
|
164
|
-
async function withStandardOutput(commandFn, options = {}) {
|
|
165
|
-
const {
|
|
166
|
-
command,
|
|
167
|
-
startTime = new Date().toISOString(),
|
|
168
|
-
runId = generateRunId(),
|
|
169
|
-
json = false,
|
|
170
|
-
output = null,
|
|
171
|
-
ci = false,
|
|
172
|
-
verbose = false,
|
|
173
|
-
tier = "free",
|
|
174
|
-
version = "1.0.0",
|
|
175
|
-
} = options;
|
|
176
|
-
|
|
177
|
-
// Initialize paths
|
|
178
|
-
const paths = getRunPaths(runId);
|
|
179
|
-
const artifacts = [];
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
// Run the command
|
|
183
|
-
const result = await commandFn({
|
|
184
|
-
runId,
|
|
185
|
-
paths,
|
|
186
|
-
saveArtifact: (name, data, type) => {
|
|
187
|
-
const artifactPath = saveArtifact(runId, name, data, type);
|
|
188
|
-
artifacts.push({
|
|
189
|
-
type,
|
|
190
|
-
path: artifactPath,
|
|
191
|
-
description: `${name} artifact`,
|
|
192
|
-
});
|
|
193
|
-
return artifactPath;
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// Extract exit code and verdict
|
|
198
|
-
const exitCode = typeof result === "number" ? result : result.exitCode || 0;
|
|
199
|
-
const verdict = result.verdict || exitCodeToVerdict(exitCode);
|
|
200
|
-
|
|
201
|
-
// Create JSON output if requested
|
|
202
|
-
if (json) {
|
|
203
|
-
const jsonOutput = createJsonOutput({
|
|
204
|
-
runId,
|
|
205
|
-
command,
|
|
206
|
-
startTime,
|
|
207
|
-
exitCode,
|
|
208
|
-
verdict,
|
|
209
|
-
result: typeof result === "object" ? result : {},
|
|
210
|
-
tier,
|
|
211
|
-
version,
|
|
212
|
-
artifacts,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
writeJsonOutput(jsonOutput, output);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Save command output to run directory
|
|
219
|
-
const commandOutput = {
|
|
220
|
-
exitCode,
|
|
221
|
-
verdict,
|
|
222
|
-
result: typeof result === "object" ? result : {},
|
|
223
|
-
artifacts,
|
|
224
|
-
};
|
|
225
|
-
fs.writeFileSync(paths.commandPath, JSON.stringify(commandOutput, null, 2));
|
|
226
|
-
|
|
227
|
-
// Update stable pointer
|
|
228
|
-
const lastPath = path.join(process.cwd(), ".vibecheck", "last", `${command}.json`);
|
|
229
|
-
if (!fs.existsSync(path.dirname(lastPath))) {
|
|
230
|
-
fs.mkdirSync(path.dirname(lastPath), { recursive: true });
|
|
231
|
-
}
|
|
232
|
-
fs.writeFileSync(lastPath, JSON.stringify(commandOutput, null, 2));
|
|
233
|
-
|
|
234
|
-
return exitCode;
|
|
235
|
-
} catch (error) {
|
|
236
|
-
// Handle errors consistently
|
|
237
|
-
const exitCode = error.exitCode || 5;
|
|
238
|
-
const verdict = "INTERNAL_ERROR";
|
|
239
|
-
|
|
240
|
-
if (json) {
|
|
241
|
-
const jsonOutput = createJsonOutput({
|
|
242
|
-
runId,
|
|
243
|
-
command,
|
|
244
|
-
startTime,
|
|
245
|
-
exitCode,
|
|
246
|
-
verdict,
|
|
247
|
-
result: {
|
|
248
|
-
error: error.message,
|
|
249
|
-
stack: error.stack,
|
|
250
|
-
},
|
|
251
|
-
tier,
|
|
252
|
-
version,
|
|
253
|
-
artifacts,
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
writeJsonOutput(jsonOutput, output);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Save error to run directory
|
|
260
|
-
const commandOutput = {
|
|
261
|
-
exitCode,
|
|
262
|
-
verdict,
|
|
263
|
-
error: error.message,
|
|
264
|
-
artifacts,
|
|
265
|
-
};
|
|
266
|
-
fs.writeFileSync(paths.commandPath, JSON.stringify(commandOutput, null, 2));
|
|
267
|
-
|
|
268
|
-
throw error;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
273
|
-
// STANDARD FLAGS PARSER
|
|
274
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Parse standard CLI flags
|
|
278
|
-
*/
|
|
279
|
-
function parseStandardFlags(args) {
|
|
280
|
-
const flags = {
|
|
281
|
-
json: false,
|
|
282
|
-
ci: false,
|
|
283
|
-
path: process.cwd(),
|
|
284
|
-
output: null,
|
|
285
|
-
verbose: false,
|
|
286
|
-
strict: false,
|
|
287
|
-
help: false,
|
|
288
|
-
version: false,
|
|
289
|
-
debug: false,
|
|
290
|
-
quiet: false,
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
const parsed = args.filter(arg => {
|
|
294
|
-
switch (arg) {
|
|
295
|
-
case "--json":
|
|
296
|
-
case "-j":
|
|
297
|
-
flags.json = true;
|
|
298
|
-
return false;
|
|
299
|
-
case "--ci":
|
|
300
|
-
flags.ci = true;
|
|
301
|
-
return false;
|
|
302
|
-
case "--verbose":
|
|
303
|
-
case "-v":
|
|
304
|
-
flags.verbose = true;
|
|
305
|
-
return false;
|
|
306
|
-
case "--strict":
|
|
307
|
-
flags.strict = true;
|
|
308
|
-
return false;
|
|
309
|
-
case "--help":
|
|
310
|
-
case "-h":
|
|
311
|
-
flags.help = true;
|
|
312
|
-
return false;
|
|
313
|
-
case "--version":
|
|
314
|
-
case "-V":
|
|
315
|
-
flags.version = true;
|
|
316
|
-
return false;
|
|
317
|
-
case "--debug":
|
|
318
|
-
case "-d":
|
|
319
|
-
flags.debug = true;
|
|
320
|
-
return false;
|
|
321
|
-
case "--quiet":
|
|
322
|
-
case "-q":
|
|
323
|
-
flags.quiet = true;
|
|
324
|
-
return false;
|
|
325
|
-
default:
|
|
326
|
-
if (arg.startsWith("--path=")) {
|
|
327
|
-
flags.path = arg.split("=")[1];
|
|
328
|
-
return false;
|
|
329
|
-
} else if (arg.startsWith("-p")) {
|
|
330
|
-
const idx = args.indexOf(arg);
|
|
331
|
-
if (idx < args.length - 1) {
|
|
332
|
-
flags.path = args[idx + 1];
|
|
333
|
-
args.splice(idx, 2);
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
} else if (arg.startsWith("--output=")) {
|
|
337
|
-
flags.output = arg.split("=")[1];
|
|
338
|
-
return false;
|
|
339
|
-
} else if (arg.startsWith("-o")) {
|
|
340
|
-
const idx = args.indexOf(arg);
|
|
341
|
-
if (idx < args.length - 1) {
|
|
342
|
-
flags.output = args[idx + 1];
|
|
343
|
-
args.splice(idx, 2);
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return true;
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
return { flags, parsed };
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
355
|
-
// EXPORTS
|
|
356
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
357
|
-
|
|
358
|
-
module.exports = {
|
|
359
|
-
generateRunId,
|
|
360
|
-
getRunPaths,
|
|
361
|
-
saveArtifact,
|
|
362
|
-
createJsonOutput,
|
|
363
|
-
writeJsonOutput,
|
|
364
|
-
exitCodeToVerdict,
|
|
365
|
-
verdictToExitCode,
|
|
366
|
-
withStandardOutput,
|
|
367
|
-
parseStandardFlags,
|
|
368
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* CLI Output Utilities - World-Class Consistency
|
|
3
|
+
*
|
|
4
|
+
* Provides standardized JSON output, run ID generation,
|
|
5
|
+
* and artifact management for all CLI commands.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const crypto = require("crypto");
|
|
13
|
+
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
15
|
+
// RUN ID GENERATION
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate a unique run ID for tracking
|
|
20
|
+
*/
|
|
21
|
+
function generateRunId() {
|
|
22
|
+
return crypto.randomUUID();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
26
|
+
// OUTPUT DIRECTORY MANAGEMENT
|
|
27
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get run directory paths
|
|
31
|
+
*/
|
|
32
|
+
function getRunPaths(runId, projectPath = process.cwd()) {
|
|
33
|
+
const runDir = path.join(projectPath, ".vibecheck", "runs", runId);
|
|
34
|
+
const artifactsDir = path.join(runDir, "artifacts");
|
|
35
|
+
|
|
36
|
+
// Ensure directories exist
|
|
37
|
+
if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
|
|
38
|
+
if (!fs.existsSync(artifactsDir)) fs.mkdirSync(artifactsDir, { recursive: true });
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
runDir,
|
|
42
|
+
artifactsDir,
|
|
43
|
+
manifestPath: path.join(runDir, "manifest.json"),
|
|
44
|
+
commandPath: path.join(runDir, "command.json"),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Save artifact to run directory
|
|
50
|
+
*/
|
|
51
|
+
function saveArtifact(runId, name, data, type = "json") {
|
|
52
|
+
const { artifactsDir } = getRunPaths(runId);
|
|
53
|
+
const artifactPath = path.join(artifactsDir, `${name}.${type}`);
|
|
54
|
+
|
|
55
|
+
if (type === "json") {
|
|
56
|
+
fs.writeFileSync(artifactPath, JSON.stringify(data, null, 2));
|
|
57
|
+
} else {
|
|
58
|
+
fs.writeFileSync(artifactPath, data);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return artifactPath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
65
|
+
// JSON OUTPUT SCHEMA
|
|
66
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create standardized JSON output
|
|
70
|
+
*/
|
|
71
|
+
function createJsonOutput(options) {
|
|
72
|
+
const {
|
|
73
|
+
runId,
|
|
74
|
+
command,
|
|
75
|
+
startTime,
|
|
76
|
+
exitCode,
|
|
77
|
+
verdict,
|
|
78
|
+
result = {},
|
|
79
|
+
tier = "free",
|
|
80
|
+
version = "1.0.0",
|
|
81
|
+
projectPath = process.cwd(),
|
|
82
|
+
artifacts = [],
|
|
83
|
+
} = options;
|
|
84
|
+
|
|
85
|
+
const output = {
|
|
86
|
+
runId,
|
|
87
|
+
command,
|
|
88
|
+
timestamp: new Date().toISOString(),
|
|
89
|
+
duration: startTime ? Date.now() - new Date(startTime).getTime() : null,
|
|
90
|
+
exitCode,
|
|
91
|
+
verdict,
|
|
92
|
+
result,
|
|
93
|
+
meta: {
|
|
94
|
+
tier,
|
|
95
|
+
version,
|
|
96
|
+
path: projectPath,
|
|
97
|
+
},
|
|
98
|
+
artifacts: artifacts.map(art => ({
|
|
99
|
+
type: art.type,
|
|
100
|
+
path: path.relative(projectPath, art.path),
|
|
101
|
+
description: art.description,
|
|
102
|
+
})),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return output;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Write JSON output to file or stdout
|
|
110
|
+
*/
|
|
111
|
+
function writeJsonOutput(output, outputPath) {
|
|
112
|
+
const jsonString = JSON.stringify(output, null, 2);
|
|
113
|
+
|
|
114
|
+
if (outputPath) {
|
|
115
|
+
fs.writeFileSync(outputPath, jsonString);
|
|
116
|
+
return outputPath;
|
|
117
|
+
} else {
|
|
118
|
+
console.log(jsonString);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
124
|
+
// VERDCT MAPPING
|
|
125
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Map exit codes to verdict strings
|
|
129
|
+
*/
|
|
130
|
+
function exitCodeToVerdict(exitCode) {
|
|
131
|
+
switch (exitCode) {
|
|
132
|
+
case 0: return "SHIP";
|
|
133
|
+
case 1: return "WARN";
|
|
134
|
+
case 2: return "BLOCK";
|
|
135
|
+
case 3: return "FEATURE_DENIED";
|
|
136
|
+
case 4: return "INVALID_INPUT";
|
|
137
|
+
case 5: return "INTERNAL_ERROR";
|
|
138
|
+
default: return "UNKNOWN";
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Map verdict to exit code
|
|
144
|
+
*/
|
|
145
|
+
function verdictToExitCode(verdict) {
|
|
146
|
+
switch (verdict?.toUpperCase()) {
|
|
147
|
+
case "SHIP": return 0;
|
|
148
|
+
case "WARN": return 1;
|
|
149
|
+
case "BLOCK": return 2;
|
|
150
|
+
case "FEATURE_DENIED": return 3;
|
|
151
|
+
case "INVALID_INPUT": return 4;
|
|
152
|
+
case "INTERNAL_ERROR": return 5;
|
|
153
|
+
default: return 5;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
158
|
+
// COMMAND WRAPPER
|
|
159
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Wrap a command runner with standard output handling
|
|
163
|
+
*/
|
|
164
|
+
async function withStandardOutput(commandFn, options = {}) {
|
|
165
|
+
const {
|
|
166
|
+
command,
|
|
167
|
+
startTime = new Date().toISOString(),
|
|
168
|
+
runId = generateRunId(),
|
|
169
|
+
json = false,
|
|
170
|
+
output = null,
|
|
171
|
+
ci = false,
|
|
172
|
+
verbose = false,
|
|
173
|
+
tier = "free",
|
|
174
|
+
version = "1.0.0",
|
|
175
|
+
} = options;
|
|
176
|
+
|
|
177
|
+
// Initialize paths
|
|
178
|
+
const paths = getRunPaths(runId);
|
|
179
|
+
const artifacts = [];
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
// Run the command
|
|
183
|
+
const result = await commandFn({
|
|
184
|
+
runId,
|
|
185
|
+
paths,
|
|
186
|
+
saveArtifact: (name, data, type) => {
|
|
187
|
+
const artifactPath = saveArtifact(runId, name, data, type);
|
|
188
|
+
artifacts.push({
|
|
189
|
+
type,
|
|
190
|
+
path: artifactPath,
|
|
191
|
+
description: `${name} artifact`,
|
|
192
|
+
});
|
|
193
|
+
return artifactPath;
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Extract exit code and verdict
|
|
198
|
+
const exitCode = typeof result === "number" ? result : result.exitCode || 0;
|
|
199
|
+
const verdict = result.verdict || exitCodeToVerdict(exitCode);
|
|
200
|
+
|
|
201
|
+
// Create JSON output if requested
|
|
202
|
+
if (json) {
|
|
203
|
+
const jsonOutput = createJsonOutput({
|
|
204
|
+
runId,
|
|
205
|
+
command,
|
|
206
|
+
startTime,
|
|
207
|
+
exitCode,
|
|
208
|
+
verdict,
|
|
209
|
+
result: typeof result === "object" ? result : {},
|
|
210
|
+
tier,
|
|
211
|
+
version,
|
|
212
|
+
artifacts,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
writeJsonOutput(jsonOutput, output);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Save command output to run directory
|
|
219
|
+
const commandOutput = {
|
|
220
|
+
exitCode,
|
|
221
|
+
verdict,
|
|
222
|
+
result: typeof result === "object" ? result : {},
|
|
223
|
+
artifacts,
|
|
224
|
+
};
|
|
225
|
+
fs.writeFileSync(paths.commandPath, JSON.stringify(commandOutput, null, 2));
|
|
226
|
+
|
|
227
|
+
// Update stable pointer
|
|
228
|
+
const lastPath = path.join(process.cwd(), ".vibecheck", "last", `${command}.json`);
|
|
229
|
+
if (!fs.existsSync(path.dirname(lastPath))) {
|
|
230
|
+
fs.mkdirSync(path.dirname(lastPath), { recursive: true });
|
|
231
|
+
}
|
|
232
|
+
fs.writeFileSync(lastPath, JSON.stringify(commandOutput, null, 2));
|
|
233
|
+
|
|
234
|
+
return exitCode;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
// Handle errors consistently
|
|
237
|
+
const exitCode = error.exitCode || 5;
|
|
238
|
+
const verdict = "INTERNAL_ERROR";
|
|
239
|
+
|
|
240
|
+
if (json) {
|
|
241
|
+
const jsonOutput = createJsonOutput({
|
|
242
|
+
runId,
|
|
243
|
+
command,
|
|
244
|
+
startTime,
|
|
245
|
+
exitCode,
|
|
246
|
+
verdict,
|
|
247
|
+
result: {
|
|
248
|
+
error: error.message,
|
|
249
|
+
stack: error.stack,
|
|
250
|
+
},
|
|
251
|
+
tier,
|
|
252
|
+
version,
|
|
253
|
+
artifacts,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
writeJsonOutput(jsonOutput, output);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Save error to run directory
|
|
260
|
+
const commandOutput = {
|
|
261
|
+
exitCode,
|
|
262
|
+
verdict,
|
|
263
|
+
error: error.message,
|
|
264
|
+
artifacts,
|
|
265
|
+
};
|
|
266
|
+
fs.writeFileSync(paths.commandPath, JSON.stringify(commandOutput, null, 2));
|
|
267
|
+
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
273
|
+
// STANDARD FLAGS PARSER
|
|
274
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Parse standard CLI flags
|
|
278
|
+
*/
|
|
279
|
+
function parseStandardFlags(args) {
|
|
280
|
+
const flags = {
|
|
281
|
+
json: false,
|
|
282
|
+
ci: false,
|
|
283
|
+
path: process.cwd(),
|
|
284
|
+
output: null,
|
|
285
|
+
verbose: false,
|
|
286
|
+
strict: false,
|
|
287
|
+
help: false,
|
|
288
|
+
version: false,
|
|
289
|
+
debug: false,
|
|
290
|
+
quiet: false,
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const parsed = args.filter(arg => {
|
|
294
|
+
switch (arg) {
|
|
295
|
+
case "--json":
|
|
296
|
+
case "-j":
|
|
297
|
+
flags.json = true;
|
|
298
|
+
return false;
|
|
299
|
+
case "--ci":
|
|
300
|
+
flags.ci = true;
|
|
301
|
+
return false;
|
|
302
|
+
case "--verbose":
|
|
303
|
+
case "-v":
|
|
304
|
+
flags.verbose = true;
|
|
305
|
+
return false;
|
|
306
|
+
case "--strict":
|
|
307
|
+
flags.strict = true;
|
|
308
|
+
return false;
|
|
309
|
+
case "--help":
|
|
310
|
+
case "-h":
|
|
311
|
+
flags.help = true;
|
|
312
|
+
return false;
|
|
313
|
+
case "--version":
|
|
314
|
+
case "-V":
|
|
315
|
+
flags.version = true;
|
|
316
|
+
return false;
|
|
317
|
+
case "--debug":
|
|
318
|
+
case "-d":
|
|
319
|
+
flags.debug = true;
|
|
320
|
+
return false;
|
|
321
|
+
case "--quiet":
|
|
322
|
+
case "-q":
|
|
323
|
+
flags.quiet = true;
|
|
324
|
+
return false;
|
|
325
|
+
default:
|
|
326
|
+
if (arg.startsWith("--path=")) {
|
|
327
|
+
flags.path = arg.split("=")[1];
|
|
328
|
+
return false;
|
|
329
|
+
} else if (arg.startsWith("-p")) {
|
|
330
|
+
const idx = args.indexOf(arg);
|
|
331
|
+
if (idx < args.length - 1) {
|
|
332
|
+
flags.path = args[idx + 1];
|
|
333
|
+
args.splice(idx, 2);
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
} else if (arg.startsWith("--output=")) {
|
|
337
|
+
flags.output = arg.split("=")[1];
|
|
338
|
+
return false;
|
|
339
|
+
} else if (arg.startsWith("-o")) {
|
|
340
|
+
const idx = args.indexOf(arg);
|
|
341
|
+
if (idx < args.length - 1) {
|
|
342
|
+
flags.output = args[idx + 1];
|
|
343
|
+
args.splice(idx, 2);
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
return { flags, parsed };
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
355
|
+
// EXPORTS
|
|
356
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
357
|
+
|
|
358
|
+
module.exports = {
|
|
359
|
+
generateRunId,
|
|
360
|
+
getRunPaths,
|
|
361
|
+
saveArtifact,
|
|
362
|
+
createJsonOutput,
|
|
363
|
+
writeJsonOutput,
|
|
364
|
+
exitCodeToVerdict,
|
|
365
|
+
verdictToExitCode,
|
|
366
|
+
withStandardOutput,
|
|
367
|
+
parseStandardFlags,
|
|
368
|
+
};
|