vibecheck-ai 1.0.7 → 1.0.8

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/dist/index.js CHANGED
@@ -5,6 +5,8 @@ import * as path18 from 'path';
5
5
  import path18__default, { resolve, join, basename, dirname, isAbsolute, extname, sep } from 'path';
6
6
  import * as fs102 from 'fs/promises';
7
7
  import fs102__default, { readFile, copyFile, unlink, stat, mkdir, readdir, writeFile, access, constants } from 'fs/promises';
8
+ import * as os5 from 'os';
9
+ import os5__default from 'os';
8
10
  import * as crypto52 from 'crypto';
9
11
  import { randomUUID, createHash, createHmac } from 'crypto';
10
12
  import { glob } from 'glob';
@@ -12,8 +14,6 @@ import fg from 'fast-glob';
12
14
  import * as fs15 from 'fs';
13
15
  import fs15__default, { existsSync, promises, realpathSync } from 'fs';
14
16
  import { spawn, execSync, exec, execFileSync } from 'child_process';
15
- import * as os5 from 'os';
16
- import os5__default from 'os';
17
17
  import { promisify } from 'util';
18
18
  import { gzip, gunzip } from 'zlib';
19
19
  import * as net from 'net';
@@ -34,7 +34,7 @@ import 'ink';
34
34
  import 'react/jsx-runtime';
35
35
  import 'ink-spinner';
36
36
  import 'react';
37
- import * as p2 from '@clack/prompts';
37
+ import * as p4 from '@clack/prompts';
38
38
  import { createConsola } from 'consola';
39
39
  import { Listr } from 'listr2';
40
40
  import ora from 'ora';
@@ -1080,6 +1080,457 @@ var init_config = __esm({
1080
1080
  }
1081
1081
  });
1082
1082
 
1083
+ // src/lib/credentials.ts
1084
+ var credentials_exports = {};
1085
+ __export(credentials_exports, {
1086
+ clearCredentials: () => clearCredentials,
1087
+ getApiUrl: () => getApiUrl,
1088
+ getAuthToken: () => getAuthToken,
1089
+ getCredentialsPath: () => getCredentialsPath,
1090
+ getCurrentUser: () => getCurrentUser,
1091
+ getWebUrl: () => getWebUrl,
1092
+ hasCredentials: () => hasCredentials,
1093
+ isLoggedIn: () => isLoggedIn,
1094
+ loadCredentials: () => loadCredentials,
1095
+ loginWithApiKey: () => loginWithApiKey,
1096
+ loginWithEmailPassword: () => loginWithEmailPassword,
1097
+ loginWithOAuth: () => loginWithOAuth,
1098
+ loginWithOAuthToken: () => loginWithOAuthToken,
1099
+ requestMagicLink: () => requestMagicLink,
1100
+ saveCredentials: () => saveCredentials,
1101
+ verifyMagicLink: () => verifyMagicLink
1102
+ });
1103
+ function obfuscate(data) {
1104
+ const key = crypto52.createHash("sha256").update(OBFUSCATION_KEY).digest();
1105
+ const iv = crypto52.randomBytes(16);
1106
+ const cipher = crypto52.createCipheriv("aes-256-cbc", key, iv);
1107
+ let encrypted = cipher.update(data, "utf8", "base64");
1108
+ encrypted += cipher.final("base64");
1109
+ return iv.toString("base64") + ":" + encrypted;
1110
+ }
1111
+ function deobfuscate(data) {
1112
+ try {
1113
+ const [ivBase64, encrypted] = data.split(":");
1114
+ if (!ivBase64 || !encrypted) return data;
1115
+ const key = crypto52.createHash("sha256").update(OBFUSCATION_KEY).digest();
1116
+ const iv = Buffer.from(ivBase64, "base64");
1117
+ const decipher = crypto52.createDecipheriv("aes-256-cbc", key, iv);
1118
+ let decrypted = decipher.update(encrypted, "base64", "utf8");
1119
+ decrypted += decipher.final("utf8");
1120
+ return decrypted;
1121
+ } catch {
1122
+ return data;
1123
+ }
1124
+ }
1125
+ async function ensureConfigDir() {
1126
+ await fs102.mkdir(CONFIG_DIR, { recursive: true });
1127
+ }
1128
+ async function saveCredentials(credentials) {
1129
+ await ensureConfigDir();
1130
+ const toSave = {
1131
+ ...credentials,
1132
+ authToken: credentials.authToken ? obfuscate(credentials.authToken) : void 0,
1133
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1134
+ };
1135
+ await fs102.writeFile(
1136
+ CREDENTIALS_PATH,
1137
+ JSON.stringify(toSave, null, 2),
1138
+ { mode: 384 }
1139
+ // Owner read/write only
1140
+ );
1141
+ }
1142
+ async function loadCredentials() {
1143
+ try {
1144
+ const content = await fs102.readFile(CREDENTIALS_PATH, "utf-8");
1145
+ const stored = JSON.parse(content);
1146
+ if (stored.expiresAt && new Date(stored.expiresAt) < /* @__PURE__ */ new Date()) {
1147
+ return {
1148
+ valid: false,
1149
+ error: "Token has expired. Please run `vibecheck login` to re-authenticate."
1150
+ };
1151
+ }
1152
+ const credentials = {
1153
+ ...stored,
1154
+ authToken: stored.authToken ? deobfuscate(stored.authToken) : void 0
1155
+ };
1156
+ return {
1157
+ valid: Boolean(credentials.authToken),
1158
+ credentials
1159
+ };
1160
+ } catch (error) {
1161
+ if (error.code === "ENOENT") {
1162
+ return {
1163
+ valid: false,
1164
+ error: "Not logged in. Run `vibecheck login` to authenticate."
1165
+ };
1166
+ }
1167
+ return {
1168
+ valid: false,
1169
+ error: `Failed to load credentials: ${error instanceof Error ? error.message : String(error)}`
1170
+ };
1171
+ }
1172
+ }
1173
+ async function clearCredentials() {
1174
+ try {
1175
+ await fs102.unlink(CREDENTIALS_PATH);
1176
+ } catch {
1177
+ }
1178
+ }
1179
+ async function hasCredentials() {
1180
+ try {
1181
+ await fs102.access(CREDENTIALS_PATH);
1182
+ return true;
1183
+ } catch {
1184
+ return false;
1185
+ }
1186
+ }
1187
+ async function getAuthToken() {
1188
+ if (process.env.VIBECHECK_AUTH_TOKEN) {
1189
+ return process.env.VIBECHECK_AUTH_TOKEN;
1190
+ }
1191
+ const result = await loadCredentials();
1192
+ return result.credentials?.authToken;
1193
+ }
1194
+ async function getApiUrl() {
1195
+ if (process.env.VIBECHECK_API_URL) {
1196
+ return process.env.VIBECHECK_API_URL;
1197
+ }
1198
+ if (process.env.API_URL) {
1199
+ return process.env.API_URL;
1200
+ }
1201
+ const result = await loadCredentials();
1202
+ return result.credentials?.apiUrl ?? DEFAULT_API_URL;
1203
+ }
1204
+ async function getWebUrl() {
1205
+ if (process.env.VIBECHECK_WEB_URL) {
1206
+ return process.env.VIBECHECK_WEB_URL;
1207
+ }
1208
+ if (process.env.WEB_URL) {
1209
+ return process.env.WEB_URL;
1210
+ }
1211
+ const result = await loadCredentials();
1212
+ return result.credentials?.webUrl ?? DEFAULT_WEB_URL;
1213
+ }
1214
+ async function getCurrentUser() {
1215
+ const result = await loadCredentials();
1216
+ if (!result.valid || !result.credentials) {
1217
+ return null;
1218
+ }
1219
+ return {
1220
+ userId: result.credentials.userId,
1221
+ email: result.credentials.email,
1222
+ name: result.credentials.name,
1223
+ tier: result.credentials.tier
1224
+ };
1225
+ }
1226
+ async function isLoggedIn() {
1227
+ const token = await getAuthToken();
1228
+ return Boolean(token);
1229
+ }
1230
+ async function requestMagicLink(email, options = {}) {
1231
+ const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
1232
+ try {
1233
+ const response = await fetch(`${apiUrl}/api/v1/auth/magic-link/request`, {
1234
+ method: "POST",
1235
+ headers: {
1236
+ "Content-Type": "application/json"
1237
+ },
1238
+ body: JSON.stringify({ email })
1239
+ });
1240
+ const data = await response.json();
1241
+ if (!response.ok || !data.success) {
1242
+ return {
1243
+ success: false,
1244
+ error: data.error?.message ?? "Failed to send magic link"
1245
+ };
1246
+ }
1247
+ return { success: true };
1248
+ } catch (error) {
1249
+ const message = error instanceof Error ? error.message : String(error);
1250
+ if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
1251
+ return { success: false, error: `Cannot connect to API at ${apiUrl}` };
1252
+ }
1253
+ return { success: false, error: message };
1254
+ }
1255
+ }
1256
+ async function verifyMagicLink(token, options = {}) {
1257
+ const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
1258
+ const webUrl = options.webUrl ?? DEFAULT_WEB_URL;
1259
+ try {
1260
+ const response = await fetch(`${apiUrl}/api/v1/auth/magic-link/verify`, {
1261
+ method: "POST",
1262
+ headers: {
1263
+ "Content-Type": "application/json"
1264
+ },
1265
+ body: JSON.stringify({ token })
1266
+ });
1267
+ const data = await response.json();
1268
+ if (!response.ok || !data.success) {
1269
+ return {
1270
+ success: false,
1271
+ error: data.error?.message ?? "Invalid or expired magic link"
1272
+ };
1273
+ }
1274
+ const { accessToken, expiresIn, user } = data.data;
1275
+ const credentials = {
1276
+ authToken: accessToken,
1277
+ apiUrl,
1278
+ webUrl,
1279
+ userId: user.id,
1280
+ email: user.email,
1281
+ name: user.name,
1282
+ tier: user.tier,
1283
+ expiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString()
1284
+ };
1285
+ await saveCredentials(credentials);
1286
+ return { success: true, user: credentials };
1287
+ } catch (error) {
1288
+ const message = error instanceof Error ? error.message : String(error);
1289
+ if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
1290
+ return { success: false, error: `Cannot connect to API at ${apiUrl}` };
1291
+ }
1292
+ return { success: false, error: message };
1293
+ }
1294
+ }
1295
+ async function loginWithEmailPassword(email, password2, options = {}) {
1296
+ const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
1297
+ const webUrl = options.webUrl ?? DEFAULT_WEB_URL;
1298
+ try {
1299
+ const response = await fetch(`${apiUrl}/api/v1/auth/login`, {
1300
+ method: "POST",
1301
+ headers: {
1302
+ "Content-Type": "application/json"
1303
+ },
1304
+ body: JSON.stringify({ email, password: password2 })
1305
+ });
1306
+ const data = await response.json();
1307
+ if (!response.ok || !data.success) {
1308
+ return {
1309
+ success: false,
1310
+ error: data.error?.message ?? "Invalid email or password"
1311
+ };
1312
+ }
1313
+ const { accessToken, expiresIn, user } = data.data;
1314
+ const credentials = {
1315
+ authToken: accessToken,
1316
+ apiUrl,
1317
+ webUrl,
1318
+ userId: user.id,
1319
+ email: user.email,
1320
+ name: user.name,
1321
+ tier: user.tier,
1322
+ expiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString()
1323
+ };
1324
+ await saveCredentials(credentials);
1325
+ return { success: true, user: credentials };
1326
+ } catch (error) {
1327
+ const message = error instanceof Error ? error.message : String(error);
1328
+ if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
1329
+ return { success: false, error: `Cannot connect to API at ${apiUrl}` };
1330
+ }
1331
+ return { success: false, error: message };
1332
+ }
1333
+ }
1334
+ async function loginWithApiKey(apiKey, options = {}) {
1335
+ const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
1336
+ const webUrl = options.webUrl ?? DEFAULT_WEB_URL;
1337
+ try {
1338
+ const response = await fetch(`${apiUrl}/api/v1/auth/me`, {
1339
+ headers: {
1340
+ "Authorization": `Bearer ${apiKey}`
1341
+ }
1342
+ });
1343
+ if (!response.ok) {
1344
+ if (response.status === 401) {
1345
+ return { success: false, error: "Invalid API key. Please check and try again." };
1346
+ }
1347
+ return { success: false, error: `Authentication failed: ${response.status}` };
1348
+ }
1349
+ const userData = await response.json();
1350
+ const credentials = {
1351
+ authToken: apiKey,
1352
+ apiUrl,
1353
+ webUrl,
1354
+ userId: userData.id,
1355
+ email: userData.email,
1356
+ name: userData.name,
1357
+ tier: userData.tier,
1358
+ // API keys don't expire unless revoked
1359
+ expiresAt: void 0
1360
+ };
1361
+ await saveCredentials(credentials);
1362
+ return { success: true, user: credentials };
1363
+ } catch (error) {
1364
+ const message = error instanceof Error ? error.message : String(error);
1365
+ if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
1366
+ return { success: false, error: `Cannot connect to API at ${apiUrl}` };
1367
+ }
1368
+ return { success: false, error: message };
1369
+ }
1370
+ }
1371
+ async function loginWithOAuth(provider, options = {}) {
1372
+ const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
1373
+ const webUrl = options.webUrl ?? DEFAULT_WEB_URL;
1374
+ const http2 = await import('http');
1375
+ const { URL: URL2 } = await import('url');
1376
+ return new Promise((resolve6) => {
1377
+ const server = http2.createServer(async (req, res) => {
1378
+ const url = new URL2(req.url ?? "/", `http://localhost`);
1379
+ if (url.pathname === "/callback") {
1380
+ const code = url.searchParams.get("code");
1381
+ const error = url.searchParams.get("error");
1382
+ if (error) {
1383
+ res.writeHead(200, { "Content-Type": "text/html" });
1384
+ res.end(`
1385
+ <html>
1386
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
1387
+ <h1>\u274C Authentication Failed</h1>
1388
+ <p>Error: ${error}</p>
1389
+ <p>You can close this window and try again.</p>
1390
+ </body>
1391
+ </html>
1392
+ `);
1393
+ server.close();
1394
+ resolve6({ success: false, error: `OAuth error: ${error}` });
1395
+ return;
1396
+ }
1397
+ if (!code) {
1398
+ res.writeHead(200, { "Content-Type": "text/html" });
1399
+ res.end(`
1400
+ <html>
1401
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
1402
+ <h1>\u274C Missing Authorization Code</h1>
1403
+ <p>You can close this window and try again.</p>
1404
+ </body>
1405
+ </html>
1406
+ `);
1407
+ server.close();
1408
+ resolve6({ success: false, error: "Missing authorization code" });
1409
+ return;
1410
+ }
1411
+ try {
1412
+ const exchangeResponse = await fetch(`${apiUrl}/api/v1/auth/${provider}/exchange`, {
1413
+ method: "POST",
1414
+ headers: { "Content-Type": "application/json" },
1415
+ body: JSON.stringify({ code, redirect_uri: "http://localhost:9876/callback" })
1416
+ });
1417
+ const data = await exchangeResponse.json();
1418
+ if (!exchangeResponse.ok || !data.success) {
1419
+ res.writeHead(200, { "Content-Type": "text/html" });
1420
+ res.end(`
1421
+ <html>
1422
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
1423
+ <h1>\u274C Authentication Failed</h1>
1424
+ <p>${data.error?.message ?? "Unknown error"}</p>
1425
+ <p>You can close this window and try again.</p>
1426
+ </body>
1427
+ </html>
1428
+ `);
1429
+ server.close();
1430
+ resolve6({ success: false, error: data.error?.message ?? "Token exchange failed" });
1431
+ return;
1432
+ }
1433
+ const { accessToken, expiresIn, user } = data.data;
1434
+ const credentials = {
1435
+ authToken: accessToken,
1436
+ apiUrl,
1437
+ webUrl,
1438
+ userId: user.id,
1439
+ email: user.email,
1440
+ name: user.name,
1441
+ tier: user.tier,
1442
+ expiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString()
1443
+ };
1444
+ await saveCredentials(credentials);
1445
+ res.writeHead(200, { "Content-Type": "text/html" });
1446
+ res.end(`
1447
+ <html>
1448
+ <body style="font-family: system-ui; padding: 40px; text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; min-height: 100vh; margin: 0;">
1449
+ <h1>\u2705 Authentication Successful!</h1>
1450
+ <p>Welcome, ${user.name ?? user.email}!</p>
1451
+ <p>You can close this window and return to the CLI.</p>
1452
+ </body>
1453
+ </html>
1454
+ `);
1455
+ server.close();
1456
+ resolve6({ success: true, user: credentials });
1457
+ } catch (err) {
1458
+ res.writeHead(200, { "Content-Type": "text/html" });
1459
+ res.end(`
1460
+ <html>
1461
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
1462
+ <h1>\u274C Authentication Failed</h1>
1463
+ <p>${err instanceof Error ? err.message : "Unknown error"}</p>
1464
+ <p>You can close this window and try again.</p>
1465
+ </body>
1466
+ </html>
1467
+ `);
1468
+ server.close();
1469
+ resolve6({ success: false, error: err instanceof Error ? err.message : "Unknown error" });
1470
+ }
1471
+ } else {
1472
+ res.writeHead(404);
1473
+ res.end("Not found");
1474
+ }
1475
+ });
1476
+ server.listen(9876, "127.0.0.1", async () => {
1477
+ const redirectUri = "http://localhost:9876/callback";
1478
+ let authUrl;
1479
+ if (provider === "github") {
1480
+ const params = new URLSearchParams({
1481
+ client_id: process.env.GITHUB_CLIENT_ID ?? "",
1482
+ redirect_uri: `${apiUrl}/api/v1/auth/github/callback?cli_redirect=${encodeURIComponent(redirectUri)}`,
1483
+ scope: "user:email read:user"
1484
+ });
1485
+ authUrl = `https://github.com/login/oauth/authorize?${params}`;
1486
+ } else {
1487
+ const params = new URLSearchParams({
1488
+ client_id: process.env.GOOGLE_CLIENT_ID ?? "",
1489
+ redirect_uri: `${apiUrl}/api/v1/auth/google/callback?cli_redirect=${encodeURIComponent(redirectUri)}`,
1490
+ response_type: "code",
1491
+ scope: "openid email profile",
1492
+ access_type: "offline",
1493
+ prompt: "consent"
1494
+ });
1495
+ authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
1496
+ }
1497
+ const open = (await import('open')).default;
1498
+ await open(authUrl);
1499
+ });
1500
+ setTimeout(() => {
1501
+ server.close();
1502
+ resolve6({ success: false, error: "Authentication timed out. Please try again." });
1503
+ }, 5 * 60 * 1e3);
1504
+ });
1505
+ }
1506
+ async function loginWithOAuthToken(accessToken, refreshToken, expiresIn, user, options = {}) {
1507
+ const credentials = {
1508
+ authToken: accessToken,
1509
+ apiUrl: options.apiUrl ?? DEFAULT_API_URL,
1510
+ webUrl: options.webUrl ?? DEFAULT_WEB_URL,
1511
+ userId: user.id,
1512
+ email: user.email,
1513
+ name: user.name,
1514
+ tier: user.tier,
1515
+ expiresAt: new Date(Date.now() + expiresIn * 1e3).toISOString()
1516
+ };
1517
+ await saveCredentials(credentials);
1518
+ }
1519
+ function getCredentialsPath() {
1520
+ return CREDENTIALS_PATH;
1521
+ }
1522
+ var CONFIG_DIR, CREDENTIALS_FILE, CREDENTIALS_PATH, OBFUSCATION_KEY, DEFAULT_API_URL, DEFAULT_WEB_URL;
1523
+ var init_credentials = __esm({
1524
+ "src/lib/credentials.ts"() {
1525
+ CONFIG_DIR = path18.join(os5.homedir(), ".config", "vibecheck");
1526
+ CREDENTIALS_FILE = "credentials.json";
1527
+ CREDENTIALS_PATH = path18.join(CONFIG_DIR, CREDENTIALS_FILE);
1528
+ OBFUSCATION_KEY = "vibecheck-cli-v1";
1529
+ DEFAULT_API_URL = "https://api.vibecheckai.dev";
1530
+ DEFAULT_WEB_URL = "https://app.vibecheckai.dev";
1531
+ }
1532
+ });
1533
+
1083
1534
  // ../../packages/shared-types/dist/index.js
1084
1535
  function tierMeetsRequirement(userTier, requiredTier) {
1085
1536
  const userIndex = TIER_ORDER.indexOf(userTier);
@@ -70142,8 +70593,8 @@ async function runInitWizard() {
70142
70593
  configContent: generateConfigTemplate("standard")
70143
70594
  };
70144
70595
  }
70145
- p2.intro(chalk8.cyan("vibecheck init"));
70146
- const template = await p2.select({
70596
+ p4.intro(chalk8.cyan("vibecheck init"));
70597
+ const template = await p4.select({
70147
70598
  message: "Choose a configuration template:",
70148
70599
  options: [
70149
70600
  {
@@ -70164,11 +70615,11 @@ async function runInitWizard() {
70164
70615
  ],
70165
70616
  initialValue: "standard"
70166
70617
  });
70167
- if (p2.isCancel(template)) {
70168
- p2.cancel("Setup cancelled.");
70618
+ if (p4.isCancel(template)) {
70619
+ p4.cancel("Setup cancelled.");
70169
70620
  return null;
70170
70621
  }
70171
- const rules = await p2.multiselect({
70622
+ const rules = await p4.multiselect({
70172
70623
  message: "Select scanners to enable:",
70173
70624
  options: [
70174
70625
  { value: "routes", label: "Routes", hint: "API routes and endpoints" },
@@ -70180,20 +70631,20 @@ async function runInitWizard() {
70180
70631
  initialValues: template === "minimal" ? ["routes", "env"] : ["routes", "env", "auth", "contracts"],
70181
70632
  required: true
70182
70633
  });
70183
- if (p2.isCancel(rules)) {
70184
- p2.cancel("Setup cancelled.");
70634
+ if (p4.isCancel(rules)) {
70635
+ p4.cancel("Setup cancelled.");
70185
70636
  return null;
70186
70637
  }
70187
- const strict = await p2.confirm({
70638
+ const strict = await p4.confirm({
70188
70639
  message: "Enable strict mode?",
70189
70640
  initialValue: template === "strict"
70190
70641
  });
70191
- if (p2.isCancel(strict)) {
70192
- p2.cancel("Setup cancelled.");
70642
+ if (p4.isCancel(strict)) {
70643
+ p4.cancel("Setup cancelled.");
70193
70644
  return null;
70194
70645
  }
70195
70646
  const configContent = generateConfigTemplate(template);
70196
- p2.outro(chalk8.green("Configuration ready!"));
70647
+ p4.outro(chalk8.green("Configuration ready!"));
70197
70648
  return {
70198
70649
  template,
70199
70650
  rules,
@@ -70205,11 +70656,11 @@ async function confirmOverwrite(path28) {
70205
70656
  if (!shouldPrompt()) {
70206
70657
  return false;
70207
70658
  }
70208
- const confirmed = await p2.confirm({
70659
+ const confirmed = await p4.confirm({
70209
70660
  message: `Config file already exists at ${chalk8.cyan(path28)}. Overwrite?`,
70210
70661
  initialValue: false
70211
70662
  });
70212
- if (p2.isCancel(confirmed)) {
70663
+ if (p4.isCancel(confirmed)) {
70213
70664
  return false;
70214
70665
  }
70215
70666
  return confirmed;
@@ -70224,13 +70675,13 @@ async function runConfigWizard(currentConfig) {
70224
70675
  if (!shouldPrompt()) {
70225
70676
  return null;
70226
70677
  }
70227
- p2.intro(chalk8.cyan("vibecheck config"));
70228
- const section = await p2.select({
70678
+ p4.intro(chalk8.cyan("vibecheck config"));
70679
+ const section = await p4.select({
70229
70680
  message: "What would you like to configure?",
70230
70681
  options: [...CONFIG_SECTIONS]
70231
70682
  });
70232
- if (p2.isCancel(section)) {
70233
- p2.cancel("Configuration cancelled.");
70683
+ if (p4.isCancel(section)) {
70684
+ p4.cancel("Configuration cancelled.");
70234
70685
  return null;
70235
70686
  }
70236
70687
  switch (section) {
@@ -70255,37 +70706,37 @@ var SCANNER_OPTIONS = [
70255
70706
  { value: "ui", label: "UI Graph", hint: "Component relationships" }
70256
70707
  ];
70257
70708
  async function configureRules(currentConfig) {
70258
- const rules = await p2.multiselect({
70709
+ const rules = await p4.multiselect({
70259
70710
  message: "Select scanners to enable:",
70260
70711
  options: [...SCANNER_OPTIONS],
70261
70712
  initialValues: currentConfig.rules,
70262
70713
  required: true
70263
70714
  });
70264
- if (p2.isCancel(rules)) {
70265
- p2.cancel("Scanner configuration cancelled.");
70715
+ if (p4.isCancel(rules)) {
70716
+ p4.cancel("Scanner configuration cancelled.");
70266
70717
  return null;
70267
70718
  }
70268
- p2.outro(chalk8.green("Rules updated!"));
70719
+ p4.outro(chalk8.green("Rules updated!"));
70269
70720
  return { rules };
70270
70721
  }
70271
70722
  async function configureValidation(currentConfig) {
70272
- const strict = await p2.confirm({
70723
+ const strict = await p4.confirm({
70273
70724
  message: "Enable strict mode?",
70274
70725
  initialValue: currentConfig.strict
70275
70726
  });
70276
- if (p2.isCancel(strict)) {
70277
- p2.cancel("Validation configuration cancelled.");
70727
+ if (p4.isCancel(strict)) {
70728
+ p4.cancel("Validation configuration cancelled.");
70278
70729
  return null;
70279
70730
  }
70280
- const failFast = await p2.confirm({
70731
+ const failFast = await p4.confirm({
70281
70732
  message: "Stop on first error (fail-fast)?",
70282
70733
  initialValue: currentConfig.validation.failFast
70283
70734
  });
70284
- if (p2.isCancel(failFast)) {
70285
- p2.cancel("Validation configuration cancelled.");
70735
+ if (p4.isCancel(failFast)) {
70736
+ p4.cancel("Validation configuration cancelled.");
70286
70737
  return null;
70287
70738
  }
70288
- const maxErrorsStr = await p2.text({
70739
+ const maxErrorsStr = await p4.text({
70289
70740
  message: "Maximum errors to report:",
70290
70741
  initialValue: String(currentConfig.validation.maxErrors),
70291
70742
  validate: (value) => {
@@ -70299,11 +70750,11 @@ async function configureValidation(currentConfig) {
70299
70750
  return void 0;
70300
70751
  }
70301
70752
  });
70302
- if (p2.isCancel(maxErrorsStr)) {
70303
- p2.cancel("Validation configuration cancelled.");
70753
+ if (p4.isCancel(maxErrorsStr)) {
70754
+ p4.cancel("Validation configuration cancelled.");
70304
70755
  return null;
70305
70756
  }
70306
- p2.outro(chalk8.green("Validation settings updated!"));
70757
+ p4.outro(chalk8.green("Validation settings updated!"));
70307
70758
  return {
70308
70759
  strict,
70309
70760
  validation: {
@@ -70314,7 +70765,7 @@ async function configureValidation(currentConfig) {
70314
70765
  };
70315
70766
  }
70316
70767
  async function configureWatch(currentConfig) {
70317
- const includeStr = await p2.text({
70768
+ const includeStr = await p4.text({
70318
70769
  message: "Include patterns (comma-separated):",
70319
70770
  initialValue: currentConfig.watch.include.join(", "),
70320
70771
  placeholder: "src/**/*.ts, src/**/*.tsx",
@@ -70325,20 +70776,20 @@ async function configureWatch(currentConfig) {
70325
70776
  return void 0;
70326
70777
  }
70327
70778
  });
70328
- if (p2.isCancel(includeStr)) {
70329
- p2.cancel("Watch configuration cancelled.");
70779
+ if (p4.isCancel(includeStr)) {
70780
+ p4.cancel("Watch configuration cancelled.");
70330
70781
  return null;
70331
70782
  }
70332
- const excludeStr = await p2.text({
70783
+ const excludeStr = await p4.text({
70333
70784
  message: "Exclude patterns (comma-separated):",
70334
70785
  initialValue: currentConfig.watch.exclude.join(", "),
70335
70786
  placeholder: "node_modules, dist, build"
70336
70787
  });
70337
- if (p2.isCancel(excludeStr)) {
70338
- p2.cancel("Watch configuration cancelled.");
70788
+ if (p4.isCancel(excludeStr)) {
70789
+ p4.cancel("Watch configuration cancelled.");
70339
70790
  return null;
70340
70791
  }
70341
- const debounceStr = await p2.text({
70792
+ const debounceStr = await p4.text({
70342
70793
  message: "Debounce delay (ms):",
70343
70794
  initialValue: String(currentConfig.watch.debounce),
70344
70795
  validate: (value) => {
@@ -70355,11 +70806,11 @@ async function configureWatch(currentConfig) {
70355
70806
  return void 0;
70356
70807
  }
70357
70808
  });
70358
- if (p2.isCancel(debounceStr)) {
70359
- p2.cancel("Watch configuration cancelled.");
70809
+ if (p4.isCancel(debounceStr)) {
70810
+ p4.cancel("Watch configuration cancelled.");
70360
70811
  return null;
70361
70812
  }
70362
- p2.outro(chalk8.green("Watch settings updated!"));
70813
+ p4.outro(chalk8.green("Watch settings updated!"));
70363
70814
  const includePatterns = includeStr.split(",").map((s) => s.trim()).filter(Boolean);
70364
70815
  const excludePatterns = excludeStr.split(",").map((s) => s.trim()).filter(Boolean);
70365
70816
  return {
@@ -70375,16 +70826,16 @@ var OUTPUT_FORMAT_OPTIONS = [
70375
70826
  { value: "json", label: "JSON", hint: "Machine-readable JSON" }
70376
70827
  ];
70377
70828
  async function configureOutput(currentConfig) {
70378
- const output = await p2.select({
70829
+ const output = await p4.select({
70379
70830
  message: "Default output format:",
70380
70831
  options: [...OUTPUT_FORMAT_OPTIONS],
70381
70832
  initialValue: currentConfig.output
70382
70833
  });
70383
- if (p2.isCancel(output)) {
70384
- p2.cancel("Output configuration cancelled.");
70834
+ if (p4.isCancel(output)) {
70835
+ p4.cancel("Output configuration cancelled.");
70385
70836
  return null;
70386
70837
  }
70387
- const truthpackPath = await p2.text({
70838
+ const truthpackPath = await p4.text({
70388
70839
  message: "Truthpack storage path:",
70389
70840
  initialValue: currentConfig.truthpackPath,
70390
70841
  placeholder: ".vibecheck/truthpack",
@@ -70396,16 +70847,22 @@ async function configureOutput(currentConfig) {
70396
70847
  return void 0;
70397
70848
  }
70398
70849
  });
70399
- if (p2.isCancel(truthpackPath)) {
70400
- p2.cancel("Output configuration cancelled.");
70850
+ if (p4.isCancel(truthpackPath)) {
70851
+ p4.cancel("Output configuration cancelled.");
70401
70852
  return null;
70402
70853
  }
70403
- p2.outro(chalk8.green("Output settings updated!"));
70854
+ p4.outro(chalk8.green("Output settings updated!"));
70404
70855
  return {
70405
70856
  output,
70406
70857
  truthpackPath: truthpackPath.trim()
70407
70858
  };
70408
70859
  }
70860
+
70861
+ // src/lib/version.ts
70862
+ var CLI_VERSION = "1.0.8" ;
70863
+ var CLI_NAME = "vibecheck-ai" ;
70864
+
70865
+ // src/ui/command-header.tsx
70409
70866
  var VIBECHECK_BANNER = [
70410
70867
  "\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
70411
70868
  "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D",
@@ -70561,7 +71018,7 @@ function getCommandAscii(command) {
70561
71018
  return COMMAND_ASCII[key] || [`[ ${key} ]`];
70562
71019
  }
70563
71020
  function renderCommandHeader(options) {
70564
- const { command, version = "1.0.0", target, sessionId, elapsedTime = 0 } = options;
71021
+ const { command, version = CLI_VERSION, target, sessionId, elapsedTime = 0 } = options;
70565
71022
  const session = sessionId || `${Math.random().toString(36).substring(2, 4).toUpperCase()}-${Math.floor(Math.random() * 1e3)}`;
70566
71023
  const commandAscii = getCommandAscii(command);
70567
71024
  const integrityStatus = options.vitals && options.vitals.length > 0 ? options.vitals[0].status.toUpperCase() : "READY";
@@ -71120,7 +71577,7 @@ function getStatusIndicator() {
71120
71577
  }
71121
71578
  async function showInteractiveMenu() {
71122
71579
  await printWelcome();
71123
- const selection = await p2.select({
71580
+ const selection = await p4.select({
71124
71581
  message: chalk8.cyan.bold("What would you like to do?"),
71125
71582
  options: MAIN_MENU_ITEMS.filter((item) => !item.value.startsWith("divider")).map((item) => ({
71126
71583
  value: item.value,
@@ -71128,7 +71585,7 @@ async function showInteractiveMenu() {
71128
71585
  hint: chalk8.dim(item.hint)
71129
71586
  }))
71130
71587
  });
71131
- if (p2.isCancel(selection)) {
71588
+ if (p4.isCancel(selection)) {
71132
71589
  console.log("");
71133
71590
  console.log(chalk8.dim(" \u{1F44B} See you next time, Vibecoder!"));
71134
71591
  console.log("");
@@ -71146,152 +71603,14 @@ function printError(message) {
71146
71603
  console.log(chalk8.red.bold(" \u2717 ") + chalk8.white(message));
71147
71604
  console.log("");
71148
71605
  }
71149
- var CONFIG_DIR = path18.join(os5.homedir(), ".config", "vibecheck");
71150
- var CREDENTIALS_FILE = "credentials.json";
71151
- var CREDENTIALS_PATH = path18.join(CONFIG_DIR, CREDENTIALS_FILE);
71152
- var OBFUSCATION_KEY = "vibecheck-cli-v1";
71153
- var DEFAULT_API_URL = "https://api.vibecheckai.dev";
71154
- var DEFAULT_WEB_URL = "https://app.vibecheckai.dev";
71155
- function obfuscate(data) {
71156
- const key = crypto52.createHash("sha256").update(OBFUSCATION_KEY).digest();
71157
- const iv = crypto52.randomBytes(16);
71158
- const cipher = crypto52.createCipheriv("aes-256-cbc", key, iv);
71159
- let encrypted = cipher.update(data, "utf8", "base64");
71160
- encrypted += cipher.final("base64");
71161
- return iv.toString("base64") + ":" + encrypted;
71162
- }
71163
- function deobfuscate(data) {
71164
- try {
71165
- const [ivBase64, encrypted] = data.split(":");
71166
- if (!ivBase64 || !encrypted) return data;
71167
- const key = crypto52.createHash("sha256").update(OBFUSCATION_KEY).digest();
71168
- const iv = Buffer.from(ivBase64, "base64");
71169
- const decipher = crypto52.createDecipheriv("aes-256-cbc", key, iv);
71170
- let decrypted = decipher.update(encrypted, "base64", "utf8");
71171
- decrypted += decipher.final("utf8");
71172
- return decrypted;
71173
- } catch {
71174
- return data;
71175
- }
71176
- }
71177
- async function ensureConfigDir() {
71178
- await fs102.mkdir(CONFIG_DIR, { recursive: true });
71179
- }
71180
- async function saveCredentials(credentials) {
71181
- await ensureConfigDir();
71182
- const toSave = {
71183
- ...credentials,
71184
- authToken: credentials.authToken ? obfuscate(credentials.authToken) : void 0,
71185
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
71186
- };
71187
- await fs102.writeFile(
71188
- CREDENTIALS_PATH,
71189
- JSON.stringify(toSave, null, 2),
71190
- { mode: 384 }
71191
- // Owner read/write only
71192
- );
71193
- }
71194
- async function loadCredentials() {
71195
- try {
71196
- const content = await fs102.readFile(CREDENTIALS_PATH, "utf-8");
71197
- const stored = JSON.parse(content);
71198
- if (stored.expiresAt && new Date(stored.expiresAt) < /* @__PURE__ */ new Date()) {
71199
- return {
71200
- valid: false,
71201
- error: "Token has expired. Please run `vibecheck login` to re-authenticate."
71202
- };
71203
- }
71204
- const credentials = {
71205
- ...stored,
71206
- authToken: stored.authToken ? deobfuscate(stored.authToken) : void 0
71207
- };
71208
- return {
71209
- valid: Boolean(credentials.authToken),
71210
- credentials
71211
- };
71212
- } catch (error) {
71213
- if (error.code === "ENOENT") {
71214
- return {
71215
- valid: false,
71216
- error: "Not logged in. Run `vibecheck login` to authenticate."
71217
- };
71218
- }
71219
- return {
71220
- valid: false,
71221
- error: `Failed to load credentials: ${error instanceof Error ? error.message : String(error)}`
71222
- };
71223
- }
71224
- }
71225
- async function getAuthToken() {
71226
- if (process.env.VIBECHECK_AUTH_TOKEN) {
71227
- return process.env.VIBECHECK_AUTH_TOKEN;
71228
- }
71229
- const result = await loadCredentials();
71230
- return result.credentials?.authToken;
71231
- }
71232
- async function getApiUrl() {
71233
- if (process.env.VIBECHECK_API_URL) {
71234
- return process.env.VIBECHECK_API_URL;
71235
- }
71236
- if (process.env.API_URL) {
71237
- return process.env.API_URL;
71238
- }
71239
- const result = await loadCredentials();
71240
- return result.credentials?.apiUrl ?? DEFAULT_API_URL;
71241
- }
71242
- async function getWebUrl() {
71243
- if (process.env.VIBECHECK_WEB_URL) {
71244
- return process.env.VIBECHECK_WEB_URL;
71245
- }
71246
- if (process.env.WEB_URL) {
71247
- return process.env.WEB_URL;
71248
- }
71249
- const result = await loadCredentials();
71250
- return result.credentials?.webUrl ?? DEFAULT_WEB_URL;
71251
- }
71252
- async function isLoggedIn() {
71253
- const token = await getAuthToken();
71254
- return Boolean(token);
71255
- }
71256
- async function loginWithApiKey(apiKey, options = {}) {
71257
- const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
71258
- const webUrl = options.webUrl ?? DEFAULT_WEB_URL;
71259
- try {
71260
- const response = await fetch(`${apiUrl}/api/v1/auth/me`, {
71261
- headers: {
71262
- "Authorization": `Bearer ${apiKey}`
71263
- }
71264
- });
71265
- if (!response.ok) {
71266
- if (response.status === 401) {
71267
- return { success: false, error: "Invalid API key. Please check and try again." };
71268
- }
71269
- return { success: false, error: `Authentication failed: ${response.status}` };
71270
- }
71271
- const userData = await response.json();
71272
- const credentials = {
71273
- authToken: apiKey,
71274
- apiUrl,
71275
- webUrl,
71276
- userId: userData.id,
71277
- email: userData.email,
71278
- name: userData.name,
71279
- tier: userData.tier,
71280
- // API keys don't expire unless revoked
71281
- expiresAt: void 0
71282
- };
71283
- await saveCredentials(credentials);
71284
- return { success: true, user: credentials };
71285
- } catch (error) {
71286
- const message = error instanceof Error ? error.message : String(error);
71287
- if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
71288
- return { success: false, error: `Cannot connect to API at ${apiUrl}` };
71289
- }
71290
- return { success: false, error: message };
71291
- }
71606
+ function printWarning(message) {
71607
+ console.log("");
71608
+ console.log(chalk8.yellow.bold(" \u26A0 ") + chalk8.white(message));
71609
+ console.log("");
71292
71610
  }
71293
71611
 
71294
71612
  // src/ui/login.ts
71613
+ init_credentials();
71295
71614
  var loginGradient = gradient(["#667eea", "#764ba2", "#f093fb"]);
71296
71615
  var successGradient = gradient(["#00ff88", "#00d9ff", "#a855f7"]);
71297
71616
  gradient(["#ff416c", "#ff4b2b"]);
@@ -71359,7 +71678,7 @@ async function showLoginScreen() {
71359
71678
  console.log("");
71360
71679
  console.log(chalk8.dim(" \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
71361
71680
  console.log("");
71362
- const authMethod = await p2.select({
71681
+ const authMethod = await p4.select({
71363
71682
  message: chalk8.cyan("How would you like to authenticate?"),
71364
71683
  options: [
71365
71684
  {
@@ -71399,7 +71718,7 @@ async function showLoginScreen() {
71399
71718
  }
71400
71719
  ]
71401
71720
  });
71402
- if (p2.isCancel(authMethod) || authMethod === "cancel") {
71721
+ if (p4.isCancel(authMethod) || authMethod === "cancel") {
71403
71722
  return null;
71404
71723
  }
71405
71724
  switch (authMethod) {
@@ -71426,7 +71745,7 @@ async function apiKeyLogin() {
71426
71745
  console.log(" " + chalk8.cyan("Get your API key from:"));
71427
71746
  console.log(" " + chalk8.white("https://app.vibecheckai.dev/api-keys"));
71428
71747
  console.log("");
71429
- const apiKey = await p2.password({
71748
+ const apiKey = await p4.password({
71430
71749
  message: chalk8.cyan("\u{1F511} Paste your API key"),
71431
71750
  validate: (value) => {
71432
71751
  if (!value) return "API key is required";
@@ -71434,18 +71753,18 @@ async function apiKeyLogin() {
71434
71753
  return void 0;
71435
71754
  }
71436
71755
  });
71437
- if (p2.isCancel(apiKey)) return null;
71438
- const s = p2.spinner();
71756
+ if (p4.isCancel(apiKey)) return null;
71757
+ const s = p4.spinner();
71439
71758
  s.start(chalk8.cyan("Validating API key..."));
71440
71759
  const result = await loginWithApiKey(apiKey);
71441
71760
  if (!result.success) {
71442
71761
  s.stop(chalk8.red(`\u2717 ${result.error}`));
71443
71762
  console.log("");
71444
- const retry = await p2.confirm({
71763
+ const retry = await p4.confirm({
71445
71764
  message: chalk8.cyan("Would you like to try again?"),
71446
71765
  initialValue: true
71447
71766
  });
71448
- if (p2.isCancel(retry) || !retry) return null;
71767
+ if (p4.isCancel(retry) || !retry) return null;
71449
71768
  return apiKeyLogin();
71450
71769
  }
71451
71770
  s.stop(chalk8.green("\u2713 API key validated!"));
@@ -71462,7 +71781,7 @@ async function emailLogin() {
71462
71781
  console.log("");
71463
71782
  console.log(chalk8.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
71464
71783
  console.log("");
71465
- const email = await p2.text({
71784
+ const email = await p4.text({
71466
71785
  message: chalk8.cyan("\u{1F4E7} Email address"),
71467
71786
  placeholder: "you@example.com",
71468
71787
  validate: (value) => {
@@ -71471,8 +71790,8 @@ async function emailLogin() {
71471
71790
  return void 0;
71472
71791
  }
71473
71792
  });
71474
- if (p2.isCancel(email)) return null;
71475
- const password2 = await p2.password({
71793
+ if (p4.isCancel(email)) return null;
71794
+ const password2 = await p4.password({
71476
71795
  message: chalk8.cyan("\u{1F511} Password"),
71477
71796
  validate: (value) => {
71478
71797
  if (!value) return "Password is required";
@@ -71480,49 +71799,103 @@ async function emailLogin() {
71480
71799
  return void 0;
71481
71800
  }
71482
71801
  });
71483
- if (p2.isCancel(password2)) return null;
71802
+ if (p4.isCancel(password2)) return null;
71803
+ const s = p4.spinner();
71804
+ s.start(chalk8.cyan("Authenticating..."));
71805
+ const result = await loginWithEmailPassword(email, password2);
71806
+ if (!result.success) {
71807
+ s.stop(chalk8.red(`\u2717 ${result.error}`));
71808
+ console.log("");
71809
+ const retry = await p4.confirm({
71810
+ message: chalk8.cyan("Would you like to try again?"),
71811
+ initialValue: true
71812
+ });
71813
+ if (p4.isCancel(retry) || !retry) return null;
71814
+ return emailLogin();
71815
+ }
71816
+ s.stop(chalk8.green("\u2713 Authentication successful!"));
71484
71817
  console.log("");
71485
71818
  await showSecurityAnimation();
71819
+ const user = result.user;
71486
71820
  return showLoginSuccess({
71487
- email,
71488
- name: email.split("@")[0],
71489
- tier: "pro"
71821
+ email: user.email ?? email,
71822
+ name: user.name ?? email.split("@")[0],
71823
+ tier: user.tier ?? "free"
71490
71824
  });
71491
71825
  }
71492
71826
  async function oauthLogin(provider) {
71493
71827
  console.log("");
71494
71828
  console.log(chalk8.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
71495
71829
  console.log("");
71496
- const email = await p2.text({
71497
- message: chalk8.cyan(`\u{1F4E7} Enter your email to link with ${provider}`),
71498
- placeholder: "you@example.com",
71830
+ console.log(chalk8.cyan(` ${provider} OAuth for CLI:`));
71831
+ console.log("");
71832
+ console.log(chalk8.white(" 1. We'll open your browser to sign in with " + provider));
71833
+ console.log(chalk8.white(" 2. After signing in, go to Settings \u2192 API Keys"));
71834
+ console.log(chalk8.white(" 3. Create an API key and paste it here"));
71835
+ console.log("");
71836
+ const proceed = await p4.confirm({
71837
+ message: chalk8.cyan(`Open browser to sign in with ${provider}?`),
71838
+ initialValue: true
71839
+ });
71840
+ if (p4.isCancel(proceed) || !proceed) return null;
71841
+ const s = p4.spinner();
71842
+ s.start(chalk8.cyan(`Opening ${provider} login page...`));
71843
+ try {
71844
+ const open = (await import('open')).default;
71845
+ const webUrl = process.env.VIBECHECK_WEB_URL ?? "https://app.vibecheckai.dev";
71846
+ const providerLower = provider.toLowerCase();
71847
+ await open(`${webUrl}/auth/login?provider=${providerLower}`);
71848
+ s.stop(chalk8.green(`\u2713 Browser opened!`));
71849
+ } catch {
71850
+ s.stop(chalk8.yellow("\u26A0 Could not open browser automatically"));
71851
+ console.log("");
71852
+ console.log(chalk8.white(" Please visit: https://app.vibecheckai.dev/auth/login"));
71853
+ }
71854
+ console.log("");
71855
+ console.log(chalk8.dim(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
71856
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" Complete sign-in in your browser, then: ") + chalk8.dim("\u2502"));
71857
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" 1. Go to Settings \u2192 API Keys ") + chalk8.dim("\u2502"));
71858
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" 2. Create a new API key ") + chalk8.dim("\u2502"));
71859
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" 3. Copy and paste it below ") + chalk8.dim("\u2502"));
71860
+ console.log(chalk8.dim(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
71861
+ console.log("");
71862
+ const apiKey = await p4.password({
71863
+ message: chalk8.cyan("\u{1F511} Paste your API key"),
71499
71864
  validate: (value) => {
71500
- if (!value) return "Email is required";
71501
- if (!value.includes("@")) return "Please enter a valid email";
71865
+ if (!value) return "API key is required";
71866
+ if (value.length < 20) return "Invalid API key format";
71502
71867
  return void 0;
71503
71868
  }
71504
71869
  });
71505
- if (p2.isCancel(email)) return null;
71506
- const s = p2.spinner();
71507
- s.start(chalk8.cyan(`Opening ${provider} authorization page...`));
71508
- await new Promise((resolve6) => setTimeout(resolve6, 1500));
71509
- s.message(chalk8.cyan(`Waiting for ${provider} authorization...`));
71510
- await new Promise((resolve6) => setTimeout(resolve6, 2e3));
71511
- s.stop(chalk8.green(`\u2713 ${provider} authorization successful!`));
71870
+ if (p4.isCancel(apiKey)) return null;
71871
+ const s2 = p4.spinner();
71872
+ s2.start(chalk8.cyan("Validating API key..."));
71873
+ const result = await loginWithApiKey(apiKey);
71874
+ if (!result.success) {
71875
+ s2.stop(chalk8.red(`\u2717 ${result.error}`));
71876
+ console.log("");
71877
+ const retry = await p4.confirm({
71878
+ message: chalk8.cyan("Would you like to try again?"),
71879
+ initialValue: true
71880
+ });
71881
+ if (p4.isCancel(retry) || !retry) return null;
71882
+ return oauthLogin(provider);
71883
+ }
71884
+ s2.stop(chalk8.green("\u2713 API key validated!"));
71512
71885
  console.log("");
71513
71886
  await showSecurityAnimation();
71514
- const userName = email.split("@")[0];
71887
+ const user = result.user;
71515
71888
  return showLoginSuccess({
71516
- email,
71517
- name: userName.charAt(0).toUpperCase() + userName.slice(1),
71518
- tier: "pro"
71889
+ email: user.email ?? "user@vibecheck.dev",
71890
+ name: user.name ?? user.email?.split("@")[0] ?? "User",
71891
+ tier: user.tier ?? "free"
71519
71892
  });
71520
71893
  }
71521
71894
  async function magicLinkLogin() {
71522
71895
  console.log("");
71523
71896
  console.log(chalk8.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
71524
71897
  console.log("");
71525
- const email = await p2.text({
71898
+ const email = await p4.text({
71526
71899
  message: chalk8.cyan("\u{1F4E7} Enter your email for a magic link"),
71527
71900
  placeholder: "you@example.com",
71528
71901
  validate: (value) => {
@@ -71531,27 +71904,60 @@ async function magicLinkLogin() {
71531
71904
  return void 0;
71532
71905
  }
71533
71906
  });
71534
- if (p2.isCancel(email)) return null;
71535
- const s = p2.spinner();
71907
+ if (p4.isCancel(email)) return null;
71908
+ const s = p4.spinner();
71536
71909
  s.start(chalk8.cyan("Sending magic link..."));
71537
- await new Promise((resolve6) => setTimeout(resolve6, 1500));
71910
+ const result = await requestMagicLink(email);
71911
+ if (!result.success) {
71912
+ s.stop(chalk8.red(`\u2717 ${result.error}`));
71913
+ console.log("");
71914
+ const retry = await p4.confirm({
71915
+ message: chalk8.cyan("Would you like to try again?"),
71916
+ initialValue: true
71917
+ });
71918
+ if (p4.isCancel(retry) || !retry) return null;
71919
+ return magicLinkLogin();
71920
+ }
71538
71921
  s.stop(chalk8.green("\u2713 Magic link sent!"));
71539
71922
  console.log("");
71540
71923
  console.log(chalk8.dim(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
71541
71924
  console.log(chalk8.dim(" \u2502") + chalk8.white(" \u{1F4EC} Check your inbox! ") + chalk8.dim("\u2502"));
71542
71925
  console.log(chalk8.dim(" \u2502") + chalk8.dim(` We sent a login link to ${email}`) + " ".repeat(Math.max(0, 26 - email.length)) + chalk8.dim("\u2502"));
71543
- console.log(chalk8.dim(" \u2502") + chalk8.dim(" Click the link to complete login. ") + chalk8.dim("\u2502"));
71926
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" ") + chalk8.dim("\u2502"));
71927
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" Click the link in your email, then paste the ") + chalk8.dim("\u2502"));
71928
+ console.log(chalk8.dim(" \u2502") + chalk8.white(" verification code below. ") + chalk8.dim("\u2502"));
71544
71929
  console.log(chalk8.dim(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
71545
71930
  console.log("");
71546
- const s2 = p2.spinner();
71547
- s2.start(chalk8.cyan("Waiting for magic link confirmation..."));
71548
- await new Promise((resolve6) => setTimeout(resolve6, 3e3));
71549
- s2.stop(chalk8.green("\u2713 Magic link confirmed!"));
71931
+ const token = await p4.text({
71932
+ message: chalk8.cyan("\u{1F511} Paste the verification code from the email"),
71933
+ placeholder: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
71934
+ validate: (value) => {
71935
+ if (!value) return "Verification code is required";
71936
+ if (value.length < 20) return "Invalid verification code";
71937
+ return void 0;
71938
+ }
71939
+ });
71940
+ if (p4.isCancel(token)) return null;
71941
+ const s2 = p4.spinner();
71942
+ s2.start(chalk8.cyan("Verifying..."));
71943
+ const verifyResult = await verifyMagicLink(token);
71944
+ if (!verifyResult.success) {
71945
+ s2.stop(chalk8.red(`\u2717 ${verifyResult.error}`));
71946
+ console.log("");
71947
+ const retry = await p4.confirm({
71948
+ message: chalk8.cyan("Would you like to try again?"),
71949
+ initialValue: true
71950
+ });
71951
+ if (p4.isCancel(retry) || !retry) return null;
71952
+ return magicLinkLogin();
71953
+ }
71954
+ s2.stop(chalk8.green("\u2713 Verification successful!"));
71550
71955
  await showSecurityAnimation();
71956
+ const user = verifyResult.user;
71551
71957
  return showLoginSuccess({
71552
- email,
71553
- name: email.split("@")[0],
71554
- tier: "free"
71958
+ email: user.email ?? email,
71959
+ name: user.name ?? email.split("@")[0],
71960
+ tier: user.tier ?? "free"
71555
71961
  });
71556
71962
  }
71557
71963
  async function signupFlow() {
@@ -71571,7 +71977,7 @@ async function signupFlow() {
71571
71977
  console.log(" " + chalk8.white.bold("Create Your VibeCheck Account"));
71572
71978
  console.log(" " + chalk8.dim("Join thousands of developers preventing AI hallucinations"));
71573
71979
  console.log("");
71574
- const name = await p2.text({
71980
+ const name = await p4.text({
71575
71981
  message: chalk8.cyan("\u{1F464} What should we call you?"),
71576
71982
  placeholder: "Your name",
71577
71983
  validate: (value) => {
@@ -71579,8 +71985,8 @@ async function signupFlow() {
71579
71985
  return void 0;
71580
71986
  }
71581
71987
  });
71582
- if (p2.isCancel(name)) return null;
71583
- const email = await p2.text({
71988
+ if (p4.isCancel(name)) return null;
71989
+ const email = await p4.text({
71584
71990
  message: chalk8.cyan("\u{1F4E7} Email address"),
71585
71991
  placeholder: "you@example.com",
71586
71992
  validate: (value) => {
@@ -71589,8 +71995,8 @@ async function signupFlow() {
71589
71995
  return void 0;
71590
71996
  }
71591
71997
  });
71592
- if (p2.isCancel(email)) return null;
71593
- const password2 = await p2.password({
71998
+ if (p4.isCancel(email)) return null;
71999
+ const password2 = await p4.password({
71594
72000
  message: chalk8.cyan("\u{1F511} Create a password"),
71595
72001
  validate: (value) => {
71596
72002
  if (!value) return "Password is required";
@@ -71600,20 +72006,20 @@ async function signupFlow() {
71600
72006
  return void 0;
71601
72007
  }
71602
72008
  });
71603
- if (p2.isCancel(password2)) return null;
72009
+ if (p4.isCancel(password2)) return null;
71604
72010
  const strength = getPasswordStrength(password2);
71605
72011
  console.log("");
71606
72012
  console.log(" " + chalk8.dim("Password Strength:") + " " + strength.indicator);
71607
- const confirmPassword = await p2.password({
72013
+ const confirmPassword = await p4.password({
71608
72014
  message: chalk8.cyan("\u{1F511} Confirm password"),
71609
72015
  validate: (value) => {
71610
72016
  if (value !== password2) return "Passwords do not match";
71611
72017
  return void 0;
71612
72018
  }
71613
72019
  });
71614
- if (p2.isCancel(confirmPassword)) return null;
72020
+ if (p4.isCancel(confirmPassword)) return null;
71615
72021
  console.log("");
71616
- const tier = await p2.select({
72022
+ const tier = await p4.select({
71617
72023
  message: chalk8.cyan("Choose your plan"),
71618
72024
  options: [
71619
72025
  {
@@ -71633,12 +72039,12 @@ async function signupFlow() {
71633
72039
  }
71634
72040
  ]
71635
72041
  });
71636
- if (p2.isCancel(tier)) return null;
71637
- const terms = await p2.confirm({
72042
+ if (p4.isCancel(tier)) return null;
72043
+ const terms = await p4.confirm({
71638
72044
  message: chalk8.cyan("I agree to the Terms of Service and Privacy Policy"),
71639
72045
  initialValue: false
71640
72046
  });
71641
- if (p2.isCancel(terms) || !terms) {
72047
+ if (p4.isCancel(terms) || !terms) {
71642
72048
  console.log("");
71643
72049
  console.log(chalk8.yellow(" \u26A0 You must accept the terms to create an account."));
71644
72050
  return null;
@@ -71741,6 +72147,7 @@ init_dist();
71741
72147
 
71742
72148
  // src/lib/entitlements.ts
71743
72149
  init_dist();
72150
+ init_credentials();
71744
72151
  var currentSession = {
71745
72152
  tier: "free",
71746
72153
  authenticated: false
@@ -72954,6 +73361,7 @@ async function integrateWithCI(options) {
72954
73361
 
72955
73362
  // src/lib/reality-uploader.ts
72956
73363
  init_dist2();
73364
+ init_credentials();
72957
73365
  async function uploadVideoArtifacts(artifactsDir, projectId, checkId) {
72958
73366
  try {
72959
73367
  const storageService = createVideoStorageService();
@@ -73080,6 +73488,9 @@ async function isApiUploadConfigured() {
73080
73488
  return await isLoggedIn();
73081
73489
  }
73082
73490
 
73491
+ // src/lib/index.ts
73492
+ init_credentials();
73493
+
73083
73494
  // src/commands/scan.ts
73084
73495
  init_truthpack();
73085
73496
  init_utils();
@@ -73354,7 +73765,6 @@ async function scanCommand(options) {
73354
73765
  if (env.isInteractive && !options.json && !options.quiet) {
73355
73766
  renderCommandHeader({
73356
73767
  command: "scan",
73357
- version: "1.0.0",
73358
73768
  target: process.cwd(),
73359
73769
  elapsedTime: results.duration,
73360
73770
  vitals: [
@@ -73421,7 +73831,6 @@ async function scanCommand(options) {
73421
73831
  if (options.json) {
73422
73832
  const commandResult = {
73423
73833
  commandName: "scan",
73424
- version: "1.0.0",
73425
73834
  repoRoot: process.cwd(),
73426
73835
  startedAt: new Date(startTime).toISOString(),
73427
73836
  durationMs: results.duration,
@@ -73605,7 +74014,6 @@ async function validateCommand(files, options) {
73605
74014
  if (env.isInteractive && !options.json && !options.quiet) {
73606
74015
  renderCommandHeader({
73607
74016
  command: "validate",
73608
- version: "1.0.0",
73609
74017
  target: process.cwd(),
73610
74018
  elapsedTime: 0
73611
74019
  });
@@ -73718,7 +74126,6 @@ async function validateCommand(files, options) {
73718
74126
  const warningScore = calculateHealthScore({ ...createEmptySeverityCounts(), medium: summary.warnings });
73719
74127
  renderCommandHeader({
73720
74128
  command: "validate",
73721
- version: "1.0.0",
73722
74129
  target: process.cwd(),
73723
74130
  elapsedTime: summary.duration,
73724
74131
  vitals: [
@@ -73752,7 +74159,6 @@ async function validateCommand(files, options) {
73752
74159
  };
73753
74160
  const commandResult = {
73754
74161
  commandName: "validate",
73755
- version: "1.0.0",
73756
74162
  repoRoot: process.cwd(),
73757
74163
  startedAt: new Date(startTime).toISOString(),
73758
74164
  durationMs: summary.duration,
@@ -73863,7 +74269,6 @@ async function checkCommand(options) {
73863
74269
  if (env.isInteractive && !options.json && !options.quiet) {
73864
74270
  renderCommandHeader({
73865
74271
  command: "check",
73866
- version: "1.0.0",
73867
74272
  target: process.cwd(),
73868
74273
  elapsedTime: 0
73869
74274
  });
@@ -73997,7 +74402,6 @@ async function checkCommand(options) {
73997
74402
  const driftScore = calculateHealthScore({ ...createEmptySeverityCounts(), medium: driftCount });
73998
74403
  renderCommandHeader({
73999
74404
  command: "check",
74000
- version: "1.0.0",
74001
74405
  target: process.cwd(),
74002
74406
  elapsedTime: result.duration,
74003
74407
  vitals: [
@@ -74049,7 +74453,6 @@ async function checkCommand(options) {
74049
74453
  };
74050
74454
  const commandResult = {
74051
74455
  commandName: "check",
74052
- version: "1.0.0",
74053
74456
  repoRoot: process.cwd(),
74054
74457
  startedAt: new Date(startTime).toISOString(),
74055
74458
  durationMs: result.duration,
@@ -74210,20 +74613,38 @@ function renderScoreBar2(score, maxScore = 20, width = 10) {
74210
74613
  function renderShipScoreBox(score, options = {}) {
74211
74614
  const env2 = getEnvironment();
74212
74615
  const width = options.width ?? Math.min(60, getSafeTerminalWidth(80));
74213
- const verdictColor = VERDICT_COLORS3[score.verdict];
74214
- const verdictIcon = env2.terminal.unicode ? VERDICT_ICONS2[score.verdict] : "";
74616
+ const verdict = score?.verdict ?? "WARN";
74617
+ const verdictColor = VERDICT_COLORS3[verdict] ?? chalk8.yellow;
74618
+ const verdictIcon = env2.terminal.unicode ? VERDICT_ICONS2[verdict] ?? "" : "";
74215
74619
  const lines = [];
74216
- const scoreText = `Ship Score: ${score.total}/100`;
74217
- const verdictText = `${verdictIcon} ${score.verdict}`;
74620
+ const totalScore = score?.total ?? 0;
74621
+ const scoreText = `Ship Score: ${totalScore}/100`;
74622
+ const verdictText = `${verdictIcon} ${verdict}`;
74218
74623
  lines.push(` ${chalk8.bold(scoreText)} ${verdictColor(verdictText)}`);
74219
74624
  lines.push("");
74220
- const dimensions = score.dimensions;
74625
+ const dimensions = score?.dimensions ?? {};
74221
74626
  const dimEntries = Object.entries(dimensions);
74222
- for (const [key, value] of dimEntries) {
74223
- const label = DIMENSION_LABELS[key].padEnd(16);
74224
- const scoreStr = `${value}/20`.padStart(5);
74225
- const bar = renderScoreBar2(value, 20, 10);
74226
- lines.push(` ${chalk8.dim(label)} ${scoreStr} ${bar}`);
74627
+ if (dimEntries.length === 0) {
74628
+ const defaultDimensions = [
74629
+ ["ghostRisk", 0],
74630
+ ["authCoverage", 0],
74631
+ ["envIntegrity", 0],
74632
+ ["runtimeProof", 0],
74633
+ ["contractsAlignment", 0]
74634
+ ];
74635
+ for (const [key, value] of defaultDimensions) {
74636
+ const label = (DIMENSION_LABELS[key] ?? key).padEnd(16);
74637
+ const scoreStr = `${value}/20`.padStart(5);
74638
+ const bar = renderScoreBar2(value, 20, 10);
74639
+ lines.push(` ${chalk8.dim(label)} ${scoreStr} ${bar}`);
74640
+ }
74641
+ } else {
74642
+ for (const [key, value] of dimEntries) {
74643
+ const label = (DIMENSION_LABELS[key] ?? key).padEnd(16);
74644
+ const scoreStr = `${value ?? 0}/20`.padStart(5);
74645
+ const bar = renderScoreBar2(value ?? 0, 20, 10);
74646
+ lines.push(` ${chalk8.dim(label)} ${scoreStr} ${bar}`);
74647
+ }
74227
74648
  }
74228
74649
  const boxContent = lines.join("\n");
74229
74650
  if (env2.terminal.unicode) {
@@ -74333,7 +74754,7 @@ async function initCommand(options) {
74333
74754
  if (env.isInteractive && !options.json) {
74334
74755
  renderCommandHeader({
74335
74756
  command: "init",
74336
- version: "1.0.0",
74757
+ version: CLI_VERSION,
74337
74758
  target: process.cwd(),
74338
74759
  elapsedTime: 0
74339
74760
  });
@@ -74528,7 +74949,7 @@ async function initCommand(options) {
74528
74949
  if (env.isInteractive && !options.json) {
74529
74950
  renderCommandHeader({
74530
74951
  command: "init",
74531
- version: "1.0.0",
74952
+ version: CLI_VERSION,
74532
74953
  target: process.cwd(),
74533
74954
  elapsedTime: duration,
74534
74955
  vitals: [
@@ -74793,8 +75214,9 @@ async function configCommand(options) {
74793
75214
  }
74794
75215
  const changes = await runConfigWizard(config);
74795
75216
  if (changes) {
74796
- logger2.info("Configuration changes would be applied.");
74797
- logger2.dim("Note: Writing config changes is not yet implemented.");
75217
+ logger2.info("Configuration changes detected.");
75218
+ logger2.dim("Use --set to apply changes: vibecheck config --set key=value");
75219
+ logger2.dim("Example: vibecheck config --set strict=true");
74798
75220
  }
74799
75221
  }
74800
75222
  } catch (error) {
@@ -74984,7 +75406,6 @@ async function watchCommand(options) {
74984
75406
  if (env.isInteractive && !options.json && !options.quiet) {
74985
75407
  renderCommandHeader({
74986
75408
  command: "watch",
74987
- version: "1.0.0",
74988
75409
  target: process.cwd(),
74989
75410
  elapsedTime: 0,
74990
75411
  vitals: [
@@ -75499,7 +75920,7 @@ ${fix.description}`));
75499
75920
  console.log(chalk8.yellow("Diff:"));
75500
75921
  console.log(patchGenerator.formatAsUnifiedDiff(fix.patch));
75501
75922
  console.log();
75502
- const action = await p2.select({
75923
+ const action = await p4.select({
75503
75924
  message: "What would you like to do?",
75504
75925
  options: [
75505
75926
  { value: "approve", label: "Approve and apply this fix" },
@@ -75507,7 +75928,7 @@ ${fix.description}`));
75507
75928
  { value: "skip", label: "Skip for now" }
75508
75929
  ]
75509
75930
  });
75510
- if (p2.isCancel(action)) {
75931
+ if (p4.isCancel(action)) {
75511
75932
  logger2.warn("Review cancelled");
75512
75933
  break;
75513
75934
  }
@@ -75576,10 +75997,10 @@ async function handleRollback(transactionId, logger2, options) {
75576
75997
  return;
75577
75998
  }
75578
75999
  if (env.isInteractive && !options.json && !options.quiet) {
75579
- const confirm6 = await p2.confirm({
76000
+ const confirm6 = await p4.confirm({
75580
76001
  message: `Rollback ${transaction.fixes.length} file(s)?`
75581
76002
  });
75582
- if (p2.isCancel(confirm6) || !confirm6) {
76003
+ if (p4.isCancel(confirm6) || !confirm6) {
75583
76004
  logger2.warn("Rollback cancelled");
75584
76005
  return;
75585
76006
  }
@@ -75723,7 +76144,6 @@ async function shipCommand(options) {
75723
76144
  if (env.isInteractive && !options.json && !options.quiet) {
75724
76145
  renderCommandHeader({
75725
76146
  command: "ship",
75726
- version: "1.0.0",
75727
76147
  target: projectRoot,
75728
76148
  elapsedTime: 0,
75729
76149
  vitals: [
@@ -76830,7 +77250,6 @@ function printResults2(result, logger2, isForced) {
76830
77250
  } : void 0;
76831
77251
  renderCommandHeader({
76832
77252
  command: result.ready || isForced ? "ship" : "no ship",
76833
- version: "1.0.0",
76834
77253
  target: process.cwd(),
76835
77254
  elapsedTime: result.duration,
76836
77255
  vitals,
@@ -76995,7 +77414,6 @@ async function doctorCommand(options) {
76995
77414
  if (!options.json) {
76996
77415
  renderCommandHeader({
76997
77416
  command: "doctor",
76998
- version: "1.0.0",
76999
77417
  target: process.cwd(),
77000
77418
  elapsedTime: 0
77001
77419
  });
@@ -77061,7 +77479,6 @@ async function doctorCommand(options) {
77061
77479
  } : void 0;
77062
77480
  renderCommandHeader({
77063
77481
  command: "doctor",
77064
- version: "1.0.0",
77065
77482
  target: process.cwd(),
77066
77483
  elapsedTime: duration,
77067
77484
  vitals: [
@@ -77144,7 +77561,6 @@ async function doctorCommand(options) {
77144
77561
  } : void 0;
77145
77562
  renderCommandHeader({
77146
77563
  command: "doctor",
77147
- version: "1.0.0",
77148
77564
  target: process.cwd(),
77149
77565
  elapsedTime: duration,
77150
77566
  vitals: [
@@ -77248,7 +77664,6 @@ async function reportCommand(options) {
77248
77664
  if (env.isInteractive && !options.json && !options.quiet) {
77249
77665
  renderCommandHeader({
77250
77666
  command: "report",
77251
- version: "1.0.0",
77252
77667
  target: projectRoot,
77253
77668
  elapsedTime: 0,
77254
77669
  vitals: [
@@ -77284,8 +77699,7 @@ async function reportCommand(options) {
77284
77699
  title: "Transforming data for report",
77285
77700
  task: async (ctx2) => {
77286
77701
  ctx2.reportData = transformToEnterpriseData(ctx2.scanInput, {
77287
- reportType,
77288
- version: "1.0.0"
77702
+ reportType
77289
77703
  });
77290
77704
  }
77291
77705
  },
@@ -77370,8 +77784,7 @@ async function reportCommand(options) {
77370
77784
  scanInput = await collectScanData(projectRoot, config);
77371
77785
  logger2.step("Transforming data...");
77372
77786
  const reportData = transformToEnterpriseData(scanInput, {
77373
- reportType,
77374
- version: "1.0.0"
77787
+ reportType
77375
77788
  });
77376
77789
  logger2.step(`Generating ${format.toUpperCase()} report...`);
77377
77790
  const reportConfig = {
@@ -77458,7 +77871,6 @@ async function reportCommand(options) {
77458
77871
  if (env.isInteractive && !options.quiet) {
77459
77872
  renderCommandHeader({
77460
77873
  command: "report",
77461
- version: "1.0.0",
77462
77874
  target: projectRoot,
77463
77875
  elapsedTime: result.duration,
77464
77876
  vitals: [
@@ -77614,8 +78026,8 @@ function buildCommandString(options) {
77614
78026
  init_config();
77615
78027
  init_errors();
77616
78028
  var pkg = {
77617
- name: "@vibecheck/cli",
77618
- version: "1.0.0"
78029
+ name: CLI_NAME,
78030
+ version: CLI_VERSION
77619
78031
  };
77620
78032
  var isShuttingDown = false;
77621
78033
  var cleanupCallbacks = [];
@@ -77875,6 +78287,13 @@ program2.command("login").description("Login to VibeCheck Cloud").action(async (
77875
78287
  }
77876
78288
  });
77877
78289
  program2.command("logout").description("Logout from VibeCheck Cloud").action(async () => {
78290
+ const { clearCredentials: clearCredentials2, hasCredentials: hasCredentials2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
78291
+ const wasLoggedIn = await hasCredentials2();
78292
+ if (!wasLoggedIn) {
78293
+ printWarning("You are not currently logged in.");
78294
+ return;
78295
+ }
78296
+ await clearCredentials2();
77878
78297
  printSuccess("Logged out successfully. See you next time!");
77879
78298
  });
77880
78299
  program2.helpOption("-h, --help", "Display gorgeous help");