@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
package/bin/runners/runAuth.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibecheck auth commands - Login, Logout, Whoami
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* World-Class Authentication Experience
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
const readline = require("readline");
|
|
2
10
|
const {
|
|
3
11
|
saveApiKey,
|
|
@@ -5,17 +13,22 @@ const {
|
|
|
5
13
|
getApiKey,
|
|
6
14
|
getEntitlements,
|
|
7
15
|
} = require("./lib/auth");
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const { EXIT } = require("./lib/exit-codes");
|
|
17
|
+
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = require("./lib/global-flags");
|
|
18
|
+
const {
|
|
19
|
+
ansi,
|
|
20
|
+
sym,
|
|
21
|
+
renderMinimalHeader,
|
|
22
|
+
renderSectionHeader,
|
|
23
|
+
renderSuccess,
|
|
24
|
+
renderError,
|
|
25
|
+
renderWarning,
|
|
26
|
+
renderKeyValue,
|
|
27
|
+
renderFooter,
|
|
28
|
+
Spinner,
|
|
29
|
+
getTierBadge,
|
|
30
|
+
TIER,
|
|
31
|
+
} = require("./lib/unified-cli-output");
|
|
19
32
|
|
|
20
33
|
async function prompt(question) {
|
|
21
34
|
const rl = readline.createInterface({
|
|
@@ -31,127 +44,343 @@ async function prompt(question) {
|
|
|
31
44
|
});
|
|
32
45
|
}
|
|
33
46
|
|
|
47
|
+
function isValidKeyFormat(key) {
|
|
48
|
+
if (!key || typeof key !== "string") return false;
|
|
49
|
+
return key.length >= 20 && /^[a-zA-Z0-9_-]+$/.test(key);
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
async function runLogin(args) {
|
|
35
|
-
|
|
53
|
+
const { flags } = parseGlobalFlags(args);
|
|
54
|
+
const quiet = shouldSuppressOutput(flags);
|
|
55
|
+
const json = isJsonMode(flags);
|
|
56
|
+
|
|
57
|
+
if (flags.help) {
|
|
36
58
|
console.log(`
|
|
37
|
-
${
|
|
59
|
+
${ansi.bold}USAGE${ansi.reset}
|
|
60
|
+
${ansi.cyan}vibecheck login${ansi.reset} [options]
|
|
38
61
|
|
|
39
|
-
${
|
|
40
|
-
vibecheck login
|
|
62
|
+
${ansi.dim}Aliases: auth, signin${ansi.reset}
|
|
41
63
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Get your API key from https://vibecheckai.dev/settings/keys
|
|
64
|
+
Authenticate with your Vibecheck API key to unlock paid features
|
|
65
|
+
and sync with the dashboard.
|
|
45
66
|
|
|
46
|
-
${
|
|
47
|
-
${
|
|
67
|
+
${ansi.bold}OPTIONS${ansi.reset}
|
|
68
|
+
${ansi.cyan}--key <key>${ansi.reset} Provide API key directly (non-interactive)
|
|
69
|
+
${ansi.cyan}--json${ansi.reset} Output result as JSON
|
|
70
|
+
${ansi.cyan}--quiet, -q${ansi.reset} Suppress non-essential output
|
|
71
|
+
${ansi.cyan}--help, -h${ansi.reset} Show this help
|
|
48
72
|
|
|
49
|
-
${
|
|
73
|
+
${ansi.bold}EXAMPLES${ansi.reset}
|
|
74
|
+
${ansi.dim}# Interactive login${ansi.reset}
|
|
50
75
|
vibecheck login
|
|
76
|
+
|
|
77
|
+
${ansi.dim}# Non-interactive (CI/scripts)${ansi.reset}
|
|
78
|
+
vibecheck login --key YOUR_API_KEY
|
|
79
|
+
|
|
80
|
+
${ansi.dim}# Using environment variable${ansi.reset}
|
|
81
|
+
VIBECHECK_API_KEY=xxx vibecheck whoami
|
|
82
|
+
|
|
83
|
+
${ansi.bold}GET YOUR API KEY${ansi.reset}
|
|
84
|
+
https://vibecheckai.dev/settings/keys
|
|
85
|
+
|
|
86
|
+
${ansi.dim}────────────────────────────────────────────────────────────────────${ansi.reset}
|
|
87
|
+
${ansi.dim}Documentation: https://docs.vibecheckai.dev/authentication${ansi.reset}
|
|
51
88
|
`);
|
|
52
|
-
return
|
|
89
|
+
return EXIT.SUCCESS;
|
|
53
90
|
}
|
|
54
|
-
|
|
55
|
-
console.log("\n 🔐 vibecheck LOGIN\n");
|
|
56
91
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
92
|
+
try {
|
|
93
|
+
let key = null;
|
|
94
|
+
const keyIndex = args.indexOf("--key");
|
|
95
|
+
if (keyIndex !== -1 && args[keyIndex + 1]) {
|
|
96
|
+
key = args[keyIndex + 1];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!quiet && !json) {
|
|
100
|
+
renderMinimalHeader("login", "free");
|
|
64
101
|
}
|
|
65
|
-
}
|
|
66
102
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
103
|
+
const existing = getApiKey();
|
|
104
|
+
if (existing.key && !key) {
|
|
105
|
+
if (!quiet && !json) {
|
|
106
|
+
renderWarning(`Already logged in (source: ${existing.source})`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (process.env.CI || !process.stdin.isTTY) {
|
|
110
|
+
if (json) {
|
|
111
|
+
console.log(JSON.stringify({ success: true, message: "Already logged in", source: existing.source }));
|
|
112
|
+
}
|
|
113
|
+
return EXIT.SUCCESS;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const answer = await prompt(` Overwrite existing credentials? (y/N) `);
|
|
117
|
+
if (answer.toLowerCase() !== "y") {
|
|
118
|
+
if (!quiet && !json) console.log(` ${ansi.dim}Cancelled.${ansi.reset}\n`);
|
|
119
|
+
if (json) console.log(JSON.stringify({ success: false, message: "Cancelled by user" }));
|
|
120
|
+
return EXIT.SUCCESS;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
71
123
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
124
|
+
if (!key) {
|
|
125
|
+
if (process.env.CI || !process.stdin.isTTY) {
|
|
126
|
+
const errorMsg = "No API key provided. Use --key flag or set VIBECHECK_API_KEY environment variable.";
|
|
127
|
+
if (json) {
|
|
128
|
+
console.log(JSON.stringify({ success: false, error: errorMsg }));
|
|
129
|
+
} else {
|
|
130
|
+
renderError(errorMsg);
|
|
131
|
+
}
|
|
132
|
+
return EXIT.USER_ERROR;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!quiet && !json) {
|
|
136
|
+
console.log(` ${ansi.dim}Get your API key at: https://vibecheckai.dev/settings/keys${ansi.reset}\n`);
|
|
137
|
+
}
|
|
138
|
+
key = await prompt(` ${sym.key} API Key: `);
|
|
139
|
+
}
|
|
76
140
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
141
|
+
if (!key) {
|
|
142
|
+
if (json) {
|
|
143
|
+
console.log(JSON.stringify({ success: false, error: "No API key provided" }));
|
|
144
|
+
} else {
|
|
145
|
+
renderError("No API key provided");
|
|
146
|
+
}
|
|
147
|
+
return EXIT.USER_ERROR;
|
|
148
|
+
}
|
|
80
149
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
150
|
+
if (!isValidKeyFormat(key)) {
|
|
151
|
+
if (json) {
|
|
152
|
+
console.log(JSON.stringify({ success: false, error: "Invalid API key format" }));
|
|
153
|
+
} else {
|
|
154
|
+
renderError("Invalid API key format");
|
|
155
|
+
console.log(` ${ansi.dim}API keys should be at least 20 characters.${ansi.reset}`);
|
|
156
|
+
}
|
|
157
|
+
return EXIT.USER_ERROR;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const spinner = !quiet && !json ? new Spinner("Verifying API key").start() : null;
|
|
161
|
+
|
|
162
|
+
let entitlements;
|
|
163
|
+
try {
|
|
164
|
+
entitlements = await getEntitlements(key);
|
|
165
|
+
} catch (apiError) {
|
|
166
|
+
spinner?.fail(`Failed to verify: ${apiError.message}`);
|
|
167
|
+
if (json) {
|
|
168
|
+
console.log(JSON.stringify({ success: false, error: apiError.message }));
|
|
169
|
+
}
|
|
170
|
+
return EXIT.NETWORK_ERROR;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!entitlements) {
|
|
174
|
+
spinner?.fail("Invalid API key or server unreachable");
|
|
175
|
+
if (json) {
|
|
176
|
+
console.log(JSON.stringify({ success: false, error: "Invalid API key" }));
|
|
177
|
+
}
|
|
178
|
+
return EXIT.AUTH_FAILED;
|
|
179
|
+
}
|
|
88
180
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
181
|
+
saveApiKey(key);
|
|
182
|
+
|
|
183
|
+
const result = {
|
|
184
|
+
success: true,
|
|
185
|
+
user: entitlements?.user?.name || "User",
|
|
186
|
+
plan: entitlements?.plan || "free",
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
if (json) {
|
|
190
|
+
console.log(JSON.stringify(result));
|
|
191
|
+
} else if (!quiet) {
|
|
192
|
+
spinner?.succeed(`Logged in as ${ansi.bold}${result.user}${ansi.reset}`);
|
|
193
|
+
console.log(` ${ansi.dim}Plan:${ansi.reset} ${getTierBadge(result.plan)}\n`);
|
|
194
|
+
}
|
|
94
195
|
|
|
95
|
-
|
|
196
|
+
return EXIT.SUCCESS;
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (json) {
|
|
199
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
200
|
+
} else {
|
|
201
|
+
renderError(`Login failed: ${error.message}`);
|
|
202
|
+
}
|
|
203
|
+
return EXIT.INTERNAL_ERROR;
|
|
204
|
+
}
|
|
96
205
|
}
|
|
97
206
|
|
|
98
207
|
async function runLogout(args) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
208
|
+
const { flags } = parseGlobalFlags(args);
|
|
209
|
+
const quiet = shouldSuppressOutput(flags);
|
|
210
|
+
const json = isJsonMode(flags);
|
|
211
|
+
|
|
212
|
+
if (flags.help) {
|
|
213
|
+
console.log(`
|
|
214
|
+
${ansi.bold}USAGE${ansi.reset}
|
|
215
|
+
${ansi.cyan}vibecheck logout${ansi.reset}
|
|
216
|
+
|
|
217
|
+
${ansi.dim}Aliases: signout${ansi.reset}
|
|
218
|
+
|
|
219
|
+
Remove stored API credentials from local config.
|
|
220
|
+
|
|
221
|
+
${ansi.bold}OPTIONS${ansi.reset}
|
|
222
|
+
${ansi.cyan}--json${ansi.reset} Output result as JSON
|
|
223
|
+
${ansi.cyan}--quiet, -q${ansi.reset} Suppress non-essential output
|
|
224
|
+
${ansi.cyan}--help, -h${ansi.reset} Show this help
|
|
225
|
+
`);
|
|
226
|
+
return EXIT.SUCCESS;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
if (!quiet && !json) {
|
|
231
|
+
renderMinimalHeader("logout", "free");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
deleteApiKey();
|
|
235
|
+
|
|
236
|
+
if (json) {
|
|
237
|
+
console.log(JSON.stringify({ success: true, message: "Logged out" }));
|
|
238
|
+
} else if (!quiet) {
|
|
239
|
+
renderSuccess("API key removed from local config");
|
|
240
|
+
console.log();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return EXIT.SUCCESS;
|
|
244
|
+
} catch (error) {
|
|
245
|
+
if (json) {
|
|
246
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
247
|
+
} else {
|
|
248
|
+
renderError(`Logout failed: ${error.message}`);
|
|
249
|
+
}
|
|
250
|
+
return EXIT.INTERNAL_ERROR;
|
|
251
|
+
}
|
|
103
252
|
}
|
|
104
253
|
|
|
105
254
|
async function runWhoami(args) {
|
|
106
|
-
|
|
255
|
+
const { flags } = parseGlobalFlags(args);
|
|
256
|
+
const quiet = shouldSuppressOutput(flags);
|
|
257
|
+
const json = isJsonMode(flags);
|
|
258
|
+
|
|
259
|
+
if (flags.help) {
|
|
107
260
|
console.log(`
|
|
108
|
-
${
|
|
261
|
+
${ansi.bold}USAGE${ansi.reset}
|
|
262
|
+
${ansi.cyan}vibecheck whoami${ansi.reset}
|
|
109
263
|
|
|
110
|
-
${
|
|
111
|
-
vibecheck whoami
|
|
264
|
+
${ansi.dim}Aliases: me, user${ansi.reset}
|
|
112
265
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
including plan, limits, and scopes.
|
|
266
|
+
Display information about the currently authenticated user,
|
|
267
|
+
including plan, limits, and available scopes.
|
|
116
268
|
|
|
117
|
-
${
|
|
118
|
-
${
|
|
269
|
+
${ansi.bold}OPTIONS${ansi.reset}
|
|
270
|
+
${ansi.cyan}--json${ansi.reset} Output result as JSON
|
|
271
|
+
${ansi.cyan}--quiet, -q${ansi.reset} Suppress non-essential output
|
|
272
|
+
${ansi.cyan}--help, -h${ansi.reset} Show this help
|
|
119
273
|
|
|
120
|
-
${
|
|
274
|
+
${ansi.bold}EXAMPLES${ansi.reset}
|
|
275
|
+
${ansi.dim}# Check current user${ansi.reset}
|
|
121
276
|
vibecheck whoami
|
|
277
|
+
|
|
278
|
+
${ansi.dim}# Get JSON for scripts${ansi.reset}
|
|
279
|
+
vibecheck whoami --json
|
|
122
280
|
`);
|
|
123
|
-
return
|
|
281
|
+
return EXIT.SUCCESS;
|
|
124
282
|
}
|
|
125
|
-
|
|
126
|
-
console.log("\n 👤 vibecheck WHOAMI\n");
|
|
127
283
|
|
|
128
|
-
|
|
284
|
+
try {
|
|
285
|
+
if (!quiet && !json) {
|
|
286
|
+
renderMinimalHeader("whoami", "free");
|
|
287
|
+
}
|
|
129
288
|
|
|
130
|
-
|
|
131
|
-
console.log(" Not logged in.");
|
|
132
|
-
console.log(' Run "vibecheck login" or set VIBECHECK_API_KEY.');
|
|
133
|
-
return 1;
|
|
134
|
-
}
|
|
289
|
+
const { key, source } = getApiKey();
|
|
135
290
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
291
|
+
if (!key) {
|
|
292
|
+
const result = { authenticated: false, message: "Not logged in" };
|
|
293
|
+
|
|
294
|
+
if (json) {
|
|
295
|
+
console.log(JSON.stringify(result));
|
|
296
|
+
} else {
|
|
297
|
+
renderWarning("Not logged in");
|
|
298
|
+
console.log(` ${ansi.dim}Run "vibecheck login" or set VIBECHECK_API_KEY.${ansi.reset}\n`);
|
|
299
|
+
}
|
|
300
|
+
return EXIT.AUTH_REQUIRED;
|
|
301
|
+
}
|
|
139
302
|
|
|
140
|
-
|
|
141
|
-
if (!entitlements) {
|
|
142
|
-
console.log(" ⚠️ Invalid API Key or server unreachable.");
|
|
143
|
-
return 1;
|
|
144
|
-
}
|
|
303
|
+
const spinner = !quiet && !json ? new Spinner("Fetching user info").start() : null;
|
|
145
304
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
305
|
+
let entitlements;
|
|
306
|
+
try {
|
|
307
|
+
entitlements = await getEntitlements(key);
|
|
308
|
+
} catch (apiError) {
|
|
309
|
+
spinner?.fail(`Failed to fetch: ${apiError.message}`);
|
|
310
|
+
if (json) {
|
|
311
|
+
console.log(JSON.stringify({ authenticated: true, error: apiError.message }));
|
|
312
|
+
}
|
|
313
|
+
return EXIT.NETWORK_ERROR;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!entitlements) {
|
|
317
|
+
spinner?.fail("Invalid API key or server unreachable");
|
|
318
|
+
if (json) {
|
|
319
|
+
console.log(JSON.stringify({ authenticated: false, error: "Invalid API key" }));
|
|
320
|
+
} else {
|
|
321
|
+
console.log(` ${ansi.dim}Run "vibecheck login" to re-authenticate.${ansi.reset}\n`);
|
|
322
|
+
}
|
|
323
|
+
return EXIT.AUTH_FAILED;
|
|
324
|
+
}
|
|
153
325
|
|
|
154
|
-
|
|
326
|
+
spinner?.stop(null, null, null); // Clear spinner without message
|
|
327
|
+
|
|
328
|
+
const result = {
|
|
329
|
+
authenticated: true,
|
|
330
|
+
source: source === "env" ? "environment" : "config",
|
|
331
|
+
user: {
|
|
332
|
+
name: entitlements.user?.name,
|
|
333
|
+
id: entitlements.user?.id,
|
|
334
|
+
},
|
|
335
|
+
plan: entitlements.plan,
|
|
336
|
+
limits: entitlements.limits,
|
|
337
|
+
scopes: entitlements.scopes,
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
if (json) {
|
|
341
|
+
console.log(JSON.stringify(result, null, 2));
|
|
342
|
+
} else if (!quiet) {
|
|
343
|
+
renderSectionHeader("Account", sym.key);
|
|
344
|
+
|
|
345
|
+
renderKeyValue([
|
|
346
|
+
{ label: "User", value: `${ansi.bold}${result.user.name}${ansi.reset} ${ansi.dim}(${result.user.id})${ansi.reset}` },
|
|
347
|
+
{ label: "Plan", value: getTierBadge(result.plan) },
|
|
348
|
+
{ label: "Source", value: source === "env" ? "Environment Variable" : "Local Config" },
|
|
349
|
+
{ label: "Limits", value: `${result.limits?.runsPerMonth || "unlimited"} runs/month` },
|
|
350
|
+
]);
|
|
351
|
+
|
|
352
|
+
if (result.scopes && result.scopes.length > 0) {
|
|
353
|
+
console.log();
|
|
354
|
+
console.log(` ${ansi.dim}Scopes:${ansi.reset}`);
|
|
355
|
+
result.scopes.forEach(s => console.log(` ${ansi.gray}${sym.bullet}${ansi.reset} ${s}`));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Tier-specific upsell
|
|
359
|
+
if (result.plan === "free") {
|
|
360
|
+
renderFooter({
|
|
361
|
+
nextSteps: [
|
|
362
|
+
{ cmd: "vibecheck scan", desc: "analyze your codebase" },
|
|
363
|
+
],
|
|
364
|
+
showUpsell: true,
|
|
365
|
+
});
|
|
366
|
+
} else if (result.plan === "starter") {
|
|
367
|
+
console.log();
|
|
368
|
+
console.log(` ${ansi.dim}${sym.star}${ansi.reset} ${ansi.magenta}PRO${ansi.reset}${ansi.dim}: proof loops + badge generation + priority support${ansi.reset}`);
|
|
369
|
+
console.log(` ${ansi.dim} Upgrade ${sym.arrow} https://vibecheckai.dev${ansi.reset}\n`);
|
|
370
|
+
} else {
|
|
371
|
+
console.log();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return EXIT.SUCCESS;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
if (json) {
|
|
378
|
+
console.log(JSON.stringify({ authenticated: false, error: error.message }));
|
|
379
|
+
} else {
|
|
380
|
+
renderError(`Whoami failed: ${error.message}`);
|
|
381
|
+
}
|
|
382
|
+
return EXIT.INTERNAL_ERROR;
|
|
383
|
+
}
|
|
155
384
|
}
|
|
156
385
|
|
|
157
386
|
module.exports = { runLogin, runLogout, runWhoami };
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
const fs = require("fs");
|
|
14
14
|
const path = require("path");
|
|
15
15
|
const entitlements = require("./lib/entitlements-v2");
|
|
16
|
-
const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
|
|
16
|
+
const { parseGlobalFlags, shouldShowBanner, shouldSuppressOutput, isJsonMode } = require("./lib/global-flags");
|
|
17
|
+
const { EXIT } = require("./lib/exit-codes");
|
|
17
18
|
|
|
18
19
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
19
20
|
// TERMINAL STYLING
|
|
@@ -284,13 +285,25 @@ ${c.bold}TIER${c.reset}
|
|
|
284
285
|
|
|
285
286
|
async function runCheckpoint(args) {
|
|
286
287
|
const opts = parseArgs(args);
|
|
288
|
+
const quiet = shouldSuppressOutput(opts);
|
|
289
|
+
const json = isJsonMode(opts) || opts.json;
|
|
287
290
|
|
|
288
291
|
if (opts.help) {
|
|
289
292
|
printHelp(shouldShowBanner(opts));
|
|
290
|
-
return
|
|
293
|
+
return EXIT.SUCCESS;
|
|
291
294
|
}
|
|
292
295
|
|
|
293
296
|
const projectPath = path.resolve(opts.path);
|
|
297
|
+
|
|
298
|
+
// Validate project path exists
|
|
299
|
+
if (!fs.existsSync(projectPath)) {
|
|
300
|
+
if (json) {
|
|
301
|
+
console.log(JSON.stringify({ success: false, error: `Project path does not exist: ${projectPath}` }));
|
|
302
|
+
} else {
|
|
303
|
+
console.error(`${c.red}${icons.cross}${c.reset} Project path does not exist: ${projectPath}`);
|
|
304
|
+
}
|
|
305
|
+
return EXIT.NOT_FOUND;
|
|
306
|
+
}
|
|
294
307
|
const vibecheckDir = path.join(projectPath, '.vibecheck');
|
|
295
308
|
const resultsDir = path.join(vibecheckDir, 'results');
|
|
296
309
|
const checkpointsDir = path.join(vibecheckDir, 'checkpoints');
|
|
@@ -316,17 +329,17 @@ async function runCheckpoint(args) {
|
|
|
316
329
|
}
|
|
317
330
|
|
|
318
331
|
if (!baseline) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
332
|
+
if (json) {
|
|
333
|
+
console.log(JSON.stringify({ success: false, error: "No baseline found" }));
|
|
334
|
+
} else if (!quiet) {
|
|
335
|
+
console.log(`\n${c.yellow}${icons.warning}${c.reset} No baseline found.`);
|
|
336
|
+
console.log(`${c.dim}Run 'vibecheck scan' first to create a baseline.${c.reset}`);
|
|
337
|
+
console.log(`${c.dim}Or specify --baseline <file> to use a specific file.${c.reset}\n`);
|
|
324
338
|
console.log(`${c.bold}TIP:${c.reset} Create a baseline with:`);
|
|
325
339
|
console.log(` ${c.cyan}vibecheck scan${c.reset}`);
|
|
326
340
|
console.log(` ${c.cyan}cp .vibecheck/results/latest.json .vibecheck/results/baseline.json${c.reset}\n`);
|
|
327
341
|
}
|
|
328
|
-
|
|
329
|
-
return 1;
|
|
342
|
+
return EXIT.NOT_FOUND;
|
|
330
343
|
}
|
|
331
344
|
|
|
332
345
|
// Load current
|
|
@@ -340,9 +353,13 @@ async function runCheckpoint(args) {
|
|
|
340
353
|
}
|
|
341
354
|
|
|
342
355
|
if (!current) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
356
|
+
if (json) {
|
|
357
|
+
console.log(JSON.stringify({ success: false, error: "No current results found" }));
|
|
358
|
+
} else if (!quiet) {
|
|
359
|
+
console.log(`\n${c.yellow}${icons.warning}${c.reset} No current results found.`);
|
|
360
|
+
console.log(`${c.dim}Run 'vibecheck scan' to generate current results.${c.reset}\n`);
|
|
361
|
+
}
|
|
362
|
+
return EXIT.NOT_FOUND;
|
|
346
363
|
}
|
|
347
364
|
|
|
348
365
|
// Extract findings arrays
|
|
@@ -408,18 +425,17 @@ async function runCheckpoint(args) {
|
|
|
408
425
|
if (comparison.regressions.length > 3) {
|
|
409
426
|
console.log(` ${c.dim}... and ${comparison.regressions.length - 3} more${c.reset}`);
|
|
410
427
|
}
|
|
411
|
-
return
|
|
428
|
+
return EXIT.BLOCKING;
|
|
412
429
|
} else {
|
|
413
430
|
console.log(`${c.green}${icons.check}${c.reset} Checkpoint passed (${checkpoint.summary.fixed} fixed, ${checkpoint.summary.remaining} remaining)`);
|
|
414
|
-
return
|
|
431
|
+
return EXIT.SUCCESS;
|
|
415
432
|
}
|
|
416
433
|
}
|
|
417
434
|
|
|
418
435
|
// JSON output
|
|
419
436
|
if (opts.json) {
|
|
420
437
|
console.log(JSON.stringify(checkpoint, null, 2));
|
|
421
|
-
|
|
422
|
-
return exitCode;
|
|
438
|
+
return opts.gate && checkpoint.summary.regressions > 0 ? EXIT.BLOCKING : EXIT.SUCCESS;
|
|
423
439
|
}
|
|
424
440
|
|
|
425
441
|
// Human-readable output
|
|
@@ -531,14 +547,16 @@ ${c.bold}╔══════════════════════
|
|
|
531
547
|
console.log();
|
|
532
548
|
|
|
533
549
|
// Return code:
|
|
534
|
-
// - With --gate:
|
|
535
|
-
// - Without --gate: always
|
|
550
|
+
// - With --gate: BLOCKING (2) if regressions, SUCCESS otherwise
|
|
551
|
+
// - Without --gate: always SUCCESS (informational only)
|
|
536
552
|
if (opts.gate && comparison.regressions.length > 0) {
|
|
537
|
-
|
|
538
|
-
|
|
553
|
+
if (!quiet) {
|
|
554
|
+
console.log(`${c.yellow}${icons.warning} Gate mode: Exiting with code 2 due to regressions${c.reset}\n`);
|
|
555
|
+
}
|
|
556
|
+
return EXIT.BLOCKING;
|
|
539
557
|
}
|
|
540
558
|
|
|
541
|
-
return
|
|
559
|
+
return EXIT.SUCCESS;
|
|
542
560
|
}
|
|
543
561
|
|
|
544
562
|
module.exports = { runCheckpoint };
|