vanguard-cli 3.1.14 → 3.1.16

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/README.md CHANGED
@@ -64,6 +64,18 @@ npm install -g vanguard-cli
64
64
 
65
65
  ## šŸš€ Quick Start
66
66
 
67
+ ### šŸ›”ļø Enable Invisible Protection
68
+ Integrate Vanguard with your shell (Bash, Zsh, Fish, PowerShell) to automatically scan every `git clone`.
69
+ ```bash
70
+ vanguard integrate
71
+ ```
72
+
73
+ ### šŸ“Š Check Status
74
+ Verify if the firewall is active or if you are in a protected session.
75
+ ```bash
76
+ vanguard status
77
+ ```
78
+
67
79
  ### āš™ļø Configuration
68
80
  Setup your Gemini API key or local Ollama endpoint:
69
81
  ```bash
package/bin/vanguard.js CHANGED
@@ -9,6 +9,10 @@ import { handlePull, handleClone } from '../lib/commands/scan.js';
9
9
  import { showBanner, showFooter } from '../lib/utils/ui.js';
10
10
  import config from '../lib/utils/config.js';
11
11
 
12
+ import { createRequire } from 'module';
13
+ const require = createRequire(import.meta.url);
14
+ const pkg = require('../package.json');
15
+
12
16
  const program = new Command();
13
17
 
14
18
  async function handleAction(actionName, logicFn) {
@@ -17,7 +21,7 @@ async function handleAction(actionName, logicFn) {
17
21
  (config.get('AI_PROVIDER') === 'ollama');
18
22
 
19
23
  if (!isConfigured) {
20
- showBanner();
24
+ // showBanner();
21
25
  console.log(chalk.yellow(`šŸ›”ļø Vanguard V3 is not fully configured. Starting setup...\n`));
22
26
  await runConfigWizard();
23
27
  // After wizard, check again
@@ -27,7 +31,7 @@ async function handleAction(actionName, logicFn) {
27
31
  }
28
32
  }
29
33
 
30
- showBanner();
34
+ // showBanner();
31
35
  const options = program.opts();
32
36
  config.set('VERBOSE', !!options.verbose);
33
37
 
@@ -52,7 +56,7 @@ async function handleAction(actionName, logicFn) {
52
56
  program
53
57
  .name('vanguard')
54
58
  .description('Enterprise-Grade AI Supply Chain Firewall')
55
- .version('3.0.0-enterprise')
59
+ .version(pkg.version)
56
60
  .option('-m, --model <name>', 'Override AI model')
57
61
  .option('-v, --verbose', 'Show verbose connection logs')
58
62
  .option('--clear-cache', 'Flush local audit cache');
@@ -64,7 +68,7 @@ program
64
68
  .command('status')
65
69
  .description('Check firewall protection status')
66
70
  .action(() => {
67
- showBanner();
71
+ // showBanner();
68
72
  const isInternal = process.env.VANGUARD_INTERNAL === '1';
69
73
  console.log(chalk.bold('šŸ”„ Firewall Status:'));
70
74
  if (isInternal) {
@@ -94,6 +98,7 @@ program
94
98
  await handleAction('CLONE', () => handleClone(url, directory, program.opts()));
95
99
  });
96
100
 
101
+ showBanner(pkg.version);
97
102
  program.parse(process.argv);
98
103
 
99
104
  // Default action: if no command provided, check config
@@ -103,7 +108,7 @@ if (!process.argv.slice(2).length) {
103
108
  (config.get('AI_PROVIDER') === 'ollama');
104
109
 
105
110
  if (!isConfigured) {
106
- showBanner();
111
+ // showBanner();
107
112
  console.log(chalk.yellow(`šŸ›”ļø Vanguard V3 is not fully configured. Starting setup...\n`));
108
113
  await runConfigWizard();
109
114
  } else {
@@ -5,7 +5,7 @@ import { createSpinner } from '../utils/spinner.js';
5
5
  import { showBanner } from '../utils/ui.js';
6
6
 
7
7
  export async function runConfigWizard() {
8
- showBanner();
8
+ // showBanner();
9
9
  console.log('šŸ›°ļø Vanguard Configuration Wizard');
10
10
  console.log(chalk.dim(`šŸ“‚ Config Path: ${config.path}\n`));
11
11
 
@@ -41,7 +41,13 @@ export async function handlePull(cmdOptions, programOptions) {
41
41
  try {
42
42
  analysis = await scanner.scan('git_diff', diff, spinner);
43
43
  } catch (err) {
44
- spinner.fail(`AI Audit Failed: ${err.message}`);
44
+ let msg = err.message;
45
+ if (msg.includes('[GoogleGenerativeAI Error]')) {
46
+ msg = msg.split('[')[0].trim();
47
+ if (msg.includes('400')) msg = 'Invalid API Request (400). Check configuration.';
48
+ else if (msg.length > 100) msg = 'AI Service Error (Check connection/quota)';
49
+ }
50
+ spinner.fail(`AI Audit Failed: ${msg}`);
45
51
  console.log(chalk.yellow('\nšŸ’” Tip: You might be rate-limited. Try again in 60s or run "vanguard config" to switch to local Ollama.'));
46
52
  return;
47
53
  }
@@ -125,7 +131,15 @@ export async function handleClone(url, directory, programOptions) {
125
131
  CacheManager.save(file, content, 'SAFE');
126
132
  }
127
133
  } catch (err) {
128
- scanSpinner.fail(`Audit Interrupted: ${err.message}`);
134
+ let msg = err.message;
135
+ // Clean up Google's noisy JSON error if it slipped through
136
+ if (msg.includes('[GoogleGenerativeAI Error]')) {
137
+ msg = msg.split('[')[0].trim(); // Take the first part or default to simple text
138
+ if (msg.includes('400')) msg = 'Invalid API Request (400). Check configuration.';
139
+ else if (msg.length > 100) msg = 'AI Service Error (Check connection/quota)';
140
+ }
141
+
142
+ scanSpinner.fail(`Audit Interrupted: ${msg}`);
129
143
  console.log(chalk.yellow('\nāš ļø Service Error. Part of the codebase remains unverified.'));
130
144
  await cleanupSandbox(tempPath);
131
145
  return;
@@ -89,12 +89,14 @@ RESPONSE FORMAT (JSON ONLY):
89
89
  if (spinner) {
90
90
  const originalText = spinner.text;
91
91
  for (let i = waitTime; i > 0; i--) {
92
- spinner.text = `ā„ļø Quota hit. Cooling down API (${i}s remaining)...`;
92
+ // Only update once per second to prevent terminal flickering
93
+ if (spinner.text.includes(`${i}s`)) continue;
94
+ spinner.text = `ā„ļø Quota hit (${i}s). Waiting... (Tip: Ctrl+C -> 'vanguard config' to switch AI)`;
93
95
  await sleep(1000);
94
96
  }
95
97
  spinner.text = originalText;
96
98
  } else {
97
- console.log(chalk.yellow(`\nāš ļø Rate limit hit. Cooling down for ${waitTime}s (Attempt ${attempt}/${maxAttempts})...`));
99
+ console.log(chalk.yellow(`\nāš ļø Rate limit hit. Cooling down for ${waitTime}s... (Tip: 'vanguard config' to switch AI)`));
98
100
  await sleep(waitTime * 1000);
99
101
  }
100
102
  return this.scanWithRetry(filePath, content, spinner, attempt + 1);
@@ -110,6 +112,19 @@ RESPONSE FORMAT (JSON ONLY):
110
112
  console.log(chalk.cyan(' vanguard config -> Select "Google Gemini"'));
111
113
  }
112
114
 
115
+ const isAuthError =
116
+ error.message.includes('API key') ||
117
+ error.message.includes('400') ||
118
+ error.message.includes('PERMISSION_DENIED');
119
+
120
+ if (isAuthError) {
121
+ if (spinner) spinner.fail('Authentication Failed');
122
+ console.log(chalk.red('\nāŒ Critical: Gemini API Key is invalid, expired, or missing permissions.'));
123
+ console.log(chalk.yellow('šŸ‘‰ Run "vanguard config" to update your credentials.'));
124
+ // We fail closed - do not allow the scan to proceed or return 'safe'
125
+ process.exit(1);
126
+ }
127
+
113
128
  if (isServerErr && attempt === 1) {
114
129
  if (spinner) spinner.text = 'šŸ”„ AI Server hiccup. Retrying immediately...';
115
130
  return this.scanWithRetry(filePath, content, spinner, attempt + 1);
@@ -123,6 +138,9 @@ RESPONSE FORMAT (JSON ONLY):
123
138
  const apiKey = config.get('GEMINI_KEY');
124
139
  if (!apiKey) throw new Error('Gemini API Key missing. Run "vanguard config"');
125
140
 
141
+ if (!apiKey || apiKey.trim() === '') {
142
+ throw new Error('API key is missing.');
143
+ }
126
144
  const genAI = new GoogleGenerativeAI(apiKey.trim());
127
145
  // Use the latest stable pro flash model for the best performance/quota ratio
128
146
  const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
package/lib/utils/ui.js CHANGED
@@ -3,9 +3,10 @@ import chalk from 'chalk';
3
3
  import boxen from 'boxen';
4
4
  import ora from 'ora';
5
5
 
6
- export function showBanner() {
7
- console.log(chalk.cyan(figlet.textSync('VANGUARD', { horizontalLayout: 'full' })));
8
- console.log(chalk.dim('šŸ›”ļø Software Supply Chain Firewall | AI-Powered Security šŸ›”ļø\n'));
6
+ export function showBanner(version) {
7
+ console.log(chalk.cyan(figlet.textSync('VANGUARD', { font: 'Standard', horizontalLayout: 'full' })));
8
+ const versionStr = version ? ` v${version}` : '';
9
+ console.log(chalk.dim(`šŸ›”ļø Enterprise AI Supply Chain Firewall${versionStr}\n`));
9
10
  }
10
11
 
11
12
  export function showAlert(analysis) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vanguard-cli",
3
- "version": "3.1.14",
3
+ "version": "3.1.16",
4
4
  "description": "AI-Powered Supply Chain Firewall for Git",
5
5
  "type": "module",
6
6
  "bin": {