@veestack-tools/cli 3.0.3 → 3.0.4

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.
Files changed (2) hide show
  1. package/dist/index.js +148 -35
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,11 +5,75 @@ import { Command } from "commander";
5
5
 
6
6
  // src/commands/scan.ts
7
7
  import { glob } from "glob";
8
- import { readFileSync, statSync } from "fs";
9
- import { join, resolve } from "path";
8
+ import { readFileSync as readFileSync2, statSync } from "fs";
9
+ import { join as join2, resolve } from "path";
10
10
  import crypto from "crypto";
11
11
  import ora from "ora";
12
+ import chalk2 from "chalk";
13
+
14
+ // src/utils/auth.ts
15
+ import { readFileSync, existsSync } from "fs";
16
+ import { join } from "path";
17
+ import { homedir } from "os";
18
+ import chalk from "chalk";
19
+ var CONFIG_DIR = join(homedir(), ".veestack");
20
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
21
+ function getAuthConfig() {
22
+ try {
23
+ if (!existsSync(CONFIG_FILE)) {
24
+ return null;
25
+ }
26
+ const config = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
27
+ return config;
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function isAuthenticated() {
33
+ const config = getAuthConfig();
34
+ return config !== null && config.apiKey !== void 0 && config.apiKey.length > 0;
35
+ }
36
+ function getSubscriptionTier() {
37
+ const config = getAuthConfig();
38
+ if (!config || !config.subscription) {
39
+ return "free";
40
+ }
41
+ return config.subscription.tier;
42
+ }
43
+ function isSubscriptionActive() {
44
+ const config = getAuthConfig();
45
+ if (!config || !config.subscription) {
46
+ return true;
47
+ }
48
+ if (config.subscription.tier === "free") {
49
+ return true;
50
+ }
51
+ if (config.subscription.expiresAt) {
52
+ const expiresAt = new Date(config.subscription.expiresAt);
53
+ const now = /* @__PURE__ */ new Date();
54
+ return expiresAt > now && config.subscription.isActive;
55
+ }
56
+ return config.subscription.isActive;
57
+ }
58
+ function requireAuth() {
59
+ const config = getAuthConfig();
60
+ if (!config || !config.apiKey) {
61
+ console.log(chalk.red("\u274C Authentication required"));
62
+ console.log(chalk.yellow("\nPlease login first:"));
63
+ console.log(chalk.cyan(" veestack login"));
64
+ console.log(chalk.gray("\nOr get an API key from: https://veestack.tools/dashboard"));
65
+ process.exit(1);
66
+ }
67
+ return config;
68
+ }
69
+
70
+ // src/commands/scan.ts
12
71
  async function scanCommand(options) {
72
+ const authConfig = requireAuth();
73
+ const tier = getSubscriptionTier();
74
+ console.log(chalk2.blue("\n\u{1F510} Authentication verified"));
75
+ console.log(chalk2.gray(`Subscription tier: ${tier === "pro" ? "Pro" : "Free"}`));
76
+ console.log(chalk2.gray("\u2500".repeat(40) + "\n"));
13
77
  const spinner = ora({
14
78
  text: "Scanning project...",
15
79
  spinner: "dots",
@@ -69,7 +133,7 @@ async function scanFiles(projectPath) {
69
133
  absolute: false
70
134
  });
71
135
  for (const filePath of filePaths) {
72
- const fullPath = join(projectPath, filePath);
136
+ const fullPath = join2(projectPath, filePath);
73
137
  const stats = statSync(fullPath);
74
138
  if (stats.isFile()) {
75
139
  const fileNode = {
@@ -92,8 +156,8 @@ async function scanFiles(projectPath) {
92
156
  async function scanDependencies(projectPath) {
93
157
  const dependencies = [];
94
158
  try {
95
- const packageJsonPath = join(projectPath, "package.json");
96
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
159
+ const packageJsonPath = join2(projectPath, "package.json");
160
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
97
161
  const processDeps = (deps, category) => {
98
162
  for (const [name, version] of Object.entries(deps)) {
99
163
  const versionMatch = version.match(/^(\d+)\.(\d+)/);
@@ -189,7 +253,7 @@ function hashString(str) {
189
253
 
190
254
  // src/commands/upload.ts
191
255
  import ora2 from "ora";
192
- import chalk from "chalk";
256
+ import chalk3 from "chalk";
193
257
  import readline from "readline";
194
258
  var supabaseUrl = process.env.SUPABASE_URL || "https://qhonrrojtqklvlkvfswb.supabase.co";
195
259
  var supabaseAnonKey = process.env.SUPABASE_ANON_KEY || "";
@@ -245,17 +309,17 @@ function askQuestion(question) {
245
309
  });
246
310
  }
247
311
  async function selectOrCreateProject() {
248
- console.log(chalk.blue("\n\u{1F4C1} Loading projects...\n"));
312
+ console.log(chalk3.blue("\n\u{1F4C1} Loading projects...\n"));
249
313
  const projects = await fetchProjects();
250
314
  if (projects.length === 0) {
251
- console.log(chalk.yellow("No projects found.\n"));
315
+ console.log(chalk3.yellow("No projects found.\n"));
252
316
  const answer2 = await askQuestion("Do you want to create a new project? (y/n): ");
253
317
  if (answer2.toLowerCase() === "y") {
254
318
  const name = await askQuestion("Enter project name: ");
255
319
  if (name.trim()) {
256
320
  const projectId = await createProject(name.trim());
257
321
  if (projectId) {
258
- console.log(chalk.green(`
322
+ console.log(chalk3.green(`
259
323
  \u2705 Project "${name}" created successfully!`));
260
324
  return projectId;
261
325
  }
@@ -263,12 +327,12 @@ async function selectOrCreateProject() {
263
327
  }
264
328
  return null;
265
329
  }
266
- console.log(chalk.white("Select a project:\n"));
267
- console.log(chalk.gray("0. [+] Create new project\n"));
330
+ console.log(chalk3.white("Select a project:\n"));
331
+ console.log(chalk3.gray("0. [+] Create new project\n"));
268
332
  projects.forEach((p, i) => {
269
- console.log(chalk.white(`${i + 1}. ${p.name}`));
270
- console.log(chalk.gray(` ID: ${p.id}`));
271
- console.log(chalk.gray(` Created: ${new Date(p.created_at).toLocaleDateString()}
333
+ console.log(chalk3.white(`${i + 1}. ${p.name}`));
334
+ console.log(chalk3.gray(` ID: ${p.id}`));
335
+ console.log(chalk3.gray(` Created: ${new Date(p.created_at).toLocaleDateString()}
272
336
  `));
273
337
  });
274
338
  const answer = await askQuestion("Enter number (0-" + projects.length + "): ");
@@ -278,7 +342,7 @@ async function selectOrCreateProject() {
278
342
  if (name.trim()) {
279
343
  const projectId = await createProject(name.trim());
280
344
  if (projectId) {
281
- console.log(chalk.green(`
345
+ console.log(chalk3.green(`
282
346
  \u2705 Project "${name}" created successfully!`));
283
347
  return projectId;
284
348
  }
@@ -286,15 +350,20 @@ async function selectOrCreateProject() {
286
350
  return null;
287
351
  } else if (choice > 0 && choice <= projects.length) {
288
352
  const selected = projects[choice - 1];
289
- console.log(chalk.green(`
353
+ console.log(chalk3.green(`
290
354
  \u2705 Selected project: "${selected.name}"`));
291
355
  return selected.id;
292
356
  } else {
293
- console.log(chalk.red("\n\u274C Invalid selection"));
357
+ console.log(chalk3.red("\n\u274C Invalid selection"));
294
358
  return null;
295
359
  }
296
360
  }
297
361
  async function uploadCommand(options) {
362
+ const authConfig = requireAuth();
363
+ const tier = getSubscriptionTier();
364
+ console.log(chalk3.blue("\n\u{1F510} Authentication verified"));
365
+ console.log(chalk3.gray(`Subscription tier: ${tier === "pro" ? "Pro" : "Free"}`));
366
+ console.log(chalk3.gray("\u2500".repeat(40) + "\n"));
298
367
  const spinner = ora2("Preparing upload...").start();
299
368
  try {
300
369
  const fs = await import("fs/promises");
@@ -305,7 +374,7 @@ async function uploadCommand(options) {
305
374
  spinner.stop();
306
375
  const selectedProjectId = await selectOrCreateProject();
307
376
  if (!selectedProjectId) {
308
- console.log(chalk.red("\n\u274C No project selected. Exiting."));
377
+ console.log(chalk3.red("\n\u274C No project selected. Exiting."));
309
378
  process.exit(1);
310
379
  }
311
380
  projectId = selectedProjectId;
@@ -330,7 +399,7 @@ async function uploadCommand(options) {
330
399
  if (!snapshotRes.ok) {
331
400
  const error = await snapshotRes.json();
332
401
  spinner.fail("Failed to create snapshot");
333
- console.error(chalk.red(`Error: ${error.message || error.details || "Unknown error"}`));
402
+ console.error(chalk3.red(`Error: ${error.message || error.details || "Unknown error"}`));
334
403
  process.exit(1);
335
404
  }
336
405
  const snapshotData2 = await snapshotRes.json();
@@ -343,7 +412,7 @@ async function uploadCommand(options) {
343
412
  const result = await engine.analyze(snapshot);
344
413
  if (!result.success) {
345
414
  spinner.fail("Analysis failed");
346
- console.error(chalk.red("Error:", result.error));
415
+ console.error(chalk3.red("Error:", result.error));
347
416
  process.exit(1);
348
417
  }
349
418
  spinner.text = "Creating report...";
@@ -370,21 +439,21 @@ async function uploadCommand(options) {
370
439
  if (!reportRes.ok) {
371
440
  const error = await reportRes.json();
372
441
  spinner.fail("Failed to create report");
373
- console.error(chalk.red(`Error: ${error.message || error.details || "Unknown error"}`));
442
+ console.error(chalk3.red(`Error: ${error.message || error.details || "Unknown error"}`));
374
443
  process.exit(1);
375
444
  }
376
445
  const reportData = await reportRes.json();
377
446
  const reportId = reportData[0]?.id || reportData[0]?.id;
378
447
  spinner.succeed("Analysis complete");
379
- console.log(chalk.green("\n\u2705 Report generated and saved to VeeStack"));
380
- console.log(chalk.gray("Project ID:"), projectId);
381
- console.log(chalk.gray("Snapshot ID:"), snapshotId);
382
- console.log(chalk.gray("Report ID:"), reportId);
383
- console.log(chalk.bold("\n\u{1F4CA} Score:"), result.report.total_score);
384
- console.log(chalk.gray("Severity:"), result.report.severity_band);
385
- console.log(chalk.gray("Findings:"), result.report.summary.total_findings);
386
- console.log(chalk.blue("\n\u{1F517} View your report at:"));
387
- console.log(chalk.underline(`http://localhost:3001/reports/${reportId}?project=${projectId}`));
448
+ console.log(chalk3.green("\n\u2705 Report generated and saved to VeeStack"));
449
+ console.log(chalk3.gray("Project ID:"), projectId);
450
+ console.log(chalk3.gray("Snapshot ID:"), snapshotId);
451
+ console.log(chalk3.gray("Report ID:"), reportId);
452
+ console.log(chalk3.bold("\n\u{1F4CA} Score:"), result.report.total_score);
453
+ console.log(chalk3.gray("Severity:"), result.report.severity_band);
454
+ console.log(chalk3.gray("Findings:"), result.report.summary.total_findings);
455
+ console.log(chalk3.blue("\n\u{1F517} View your report at:"));
456
+ console.log(chalk3.underline(`http://localhost:3001/reports/${reportId}?project=${projectId}`));
388
457
  } catch (error) {
389
458
  spinner.fail("Upload failed");
390
459
  console.error(error);
@@ -394,8 +463,8 @@ async function uploadCommand(options) {
394
463
 
395
464
  // src/commands/login.ts
396
465
  import { writeFileSync } from "fs";
397
- import { join as join2 } from "path";
398
- import { homedir } from "os";
466
+ import { join as join3 } from "path";
467
+ import { homedir as homedir2 } from "os";
399
468
  import ora3 from "ora";
400
469
  import prompts from "prompts";
401
470
  async function loginCommand(options) {
@@ -421,8 +490,8 @@ async function loginCommand(options) {
421
490
  }
422
491
  spinner.start("Validating API key...");
423
492
  await new Promise((resolve2) => setTimeout(resolve2, 1e3));
424
- const configDir = join2(homedir(), ".veestack");
425
- const configFile = join2(configDir, "config.json");
493
+ const configDir = join3(homedir2(), ".veestack");
494
+ const configFile = join3(configDir, "config.json");
426
495
  try {
427
496
  const fs = await import("fs/promises");
428
497
  await fs.mkdir(configDir, { recursive: true });
@@ -441,10 +510,54 @@ async function loginCommand(options) {
441
510
  }
442
511
  }
443
512
 
513
+ // src/commands/status.ts
514
+ import chalk4 from "chalk";
515
+ async function statusCommand() {
516
+ console.log(chalk4.blue("\n\u{1F4CA} VeeStack CLI Status\n"));
517
+ console.log(chalk4.gray("\u2500".repeat(40)));
518
+ const authenticated = isAuthenticated();
519
+ const tier = getSubscriptionTier();
520
+ const active = isSubscriptionActive();
521
+ if (!authenticated) {
522
+ console.log(chalk4.red("\n\u274C Not authenticated"));
523
+ console.log(chalk4.yellow("\nTo use VeeStack CLI, you need to login:"));
524
+ console.log(chalk4.cyan(" veestack login"));
525
+ console.log(chalk4.gray("\nGet your API key from: https://veestack.tools/dashboard"));
526
+ console.log(chalk4.gray("\u2500".repeat(40) + "\n"));
527
+ process.exit(1);
528
+ }
529
+ console.log(chalk4.green("\n\u2705 Authenticated"));
530
+ if (tier === "pro") {
531
+ console.log(chalk4.cyan("\u{1F48E} Subscription: Pro"));
532
+ if (!active) {
533
+ console.log(chalk4.red("\u26A0\uFE0F Status: Expired"));
534
+ console.log(chalk4.yellow("\nPlease renew your subscription:"));
535
+ console.log(chalk4.cyan(" https://veestack.tools/pricing"));
536
+ } else {
537
+ console.log(chalk4.green("\u2713 Status: Active"));
538
+ }
539
+ } else {
540
+ console.log(chalk4.blue("\u{1F4E6} Subscription: Free"));
541
+ console.log(chalk4.green("\u2713 Status: Active"));
542
+ console.log(chalk4.gray("\nUpgrade to Pro for advanced features:"));
543
+ console.log(chalk4.cyan(" https://veestack.tools/pricing"));
544
+ }
545
+ console.log(chalk4.gray("\u2500".repeat(40) + "\n"));
546
+ console.log(chalk4.white("Available commands:"));
547
+ console.log(chalk4.cyan(" veestack scan ") + chalk4.gray(" - Scan project (Free)"));
548
+ console.log(chalk4.cyan(" veestack upload ") + chalk4.gray(" - Upload to cloud (Free)"));
549
+ console.log(chalk4.cyan(" veestack status ") + chalk4.gray(" - Check status (Free)"));
550
+ if (tier === "pro") {
551
+ console.log(chalk4.cyan(" veestack analyze ") + chalk4.gray(" - Advanced analysis (Pro)"));
552
+ }
553
+ console.log(chalk4.gray("\n\u2500".repeat(40) + "\n"));
554
+ }
555
+
444
556
  // src/index.ts
445
557
  var program = new Command();
446
- program.name("veestack").description("VeeStack CLI - Technical Stack Visibility Tool").version("3.0.1");
558
+ program.name("veestack").description("VeeStack CLI - Technical Stack Visibility Tool").version("3.0.3");
447
559
  program.command("scan").description("Scan a project directory and generate analysis").option("-p, --path <path>", "Path to project directory", ".").option("-o, --output <path>", "Output file path", "snapshot.json").option("--ci", "CI mode (no interactive prompts)").action(scanCommand);
448
560
  program.command("upload").description("Upload a snapshot to VeeStack server").option("-f, --file <path>", "Snapshot file path", "snapshot.json").option("-p, --project-id <id>", "Project ID").action(uploadCommand);
449
561
  program.command("login").description("Authenticate with VeeStack server").option("-k, --key <apiKey>", "API key").action(loginCommand);
562
+ program.command("status").description("Check authentication and subscription status").action(statusCommand);
450
563
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veestack-tools/cli",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/**/*",