ai-warden 0.9.2 ā 0.9.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.
- package/package.json +1 -1
- package/src/cli.js +116 -4
- package/src/config.js +98 -0
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
const readline = require('readline');
|
|
10
12
|
const scanner = require('./scanner');
|
|
11
13
|
const fileClassifier = require('./fileClassifier');
|
|
12
14
|
const IgnoreParser = require('./ignoreParser');
|
|
13
15
|
const InteractivePrompt = require('./interactivePrompt');
|
|
14
16
|
const AIWarden = require('./index');
|
|
17
|
+
const config = require('./config');
|
|
15
18
|
|
|
16
19
|
const args = process.argv.slice(2);
|
|
17
20
|
const command = args[0];
|
|
@@ -30,6 +33,9 @@ Usage: aiwarden <command> [options]
|
|
|
30
33
|
Commands:
|
|
31
34
|
scan <path> Scan file or directory (offline mode)
|
|
32
35
|
validate <text> Validate text via API (requires API key)
|
|
36
|
+
login Sign up or log in and save API key
|
|
37
|
+
logout Remove saved API key
|
|
38
|
+
whoami Show current API key status
|
|
33
39
|
version Show version
|
|
34
40
|
help Show this help
|
|
35
41
|
|
|
@@ -271,17 +277,23 @@ async function validateCommand(textOrPath, options = {}) {
|
|
|
271
277
|
}
|
|
272
278
|
}
|
|
273
279
|
|
|
274
|
-
// Get API key from
|
|
275
|
-
|
|
280
|
+
// Get API key from:
|
|
281
|
+
// 1. --api-key flag
|
|
282
|
+
// 2. Environment variable
|
|
283
|
+
// 3. Saved config file
|
|
284
|
+
const apiKey = options.apiKey || process.env.AI_WARDEN_API_KEY || config.getApiKey();
|
|
276
285
|
|
|
277
286
|
if (!apiKey) {
|
|
278
287
|
console.error('ā Error: API key required for validate command');
|
|
279
288
|
console.log('');
|
|
280
289
|
console.log('Options:');
|
|
281
|
-
console.log(' 1.
|
|
290
|
+
console.log(' 1. Log in (saves key for future use):');
|
|
291
|
+
console.log(' aiwarden login');
|
|
292
|
+
console.log('');
|
|
293
|
+
console.log(' 2. Pass --api-key flag:');
|
|
282
294
|
console.log(' aiwarden validate "text" --api-key sk_live_xxx');
|
|
283
295
|
console.log('');
|
|
284
|
-
console.log('
|
|
296
|
+
console.log(' 3. Set environment variable:');
|
|
285
297
|
console.log(' export AI_WARDEN_API_KEY=sk_live_xxx');
|
|
286
298
|
console.log(' aiwarden validate "text"');
|
|
287
299
|
console.log('');
|
|
@@ -383,6 +395,100 @@ function parseArgs() {
|
|
|
383
395
|
return options;
|
|
384
396
|
}
|
|
385
397
|
|
|
398
|
+
// Login command
|
|
399
|
+
async function loginCommand() {
|
|
400
|
+
console.log('š AI-Warden Login\n');
|
|
401
|
+
|
|
402
|
+
console.log('Opening browser to get your API key...');
|
|
403
|
+
console.log('ā https://prompt-shield.se/signup\n');
|
|
404
|
+
|
|
405
|
+
// Open browser
|
|
406
|
+
const url = 'https://prompt-shield.se/signup';
|
|
407
|
+
try {
|
|
408
|
+
const platform = process.platform;
|
|
409
|
+
if (platform === 'darwin') {
|
|
410
|
+
execSync(`open "${url}"`);
|
|
411
|
+
} else if (platform === 'win32') {
|
|
412
|
+
// Windows: start "" "URL" (first empty string is window title)
|
|
413
|
+
execSync(`start "" "${url}"`, { shell: true });
|
|
414
|
+
} else {
|
|
415
|
+
execSync(`xdg-open "${url}"`);
|
|
416
|
+
}
|
|
417
|
+
} catch (error) {
|
|
418
|
+
console.log('ā ļø Could not open browser automatically.');
|
|
419
|
+
console.log(`Please visit: ${url}\n`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
console.log('After signing up:');
|
|
423
|
+
console.log('1. Copy your API key from the dashboard');
|
|
424
|
+
console.log('2. Paste it below\n');
|
|
425
|
+
|
|
426
|
+
// Read API key from stdin
|
|
427
|
+
const rl = readline.createInterface({
|
|
428
|
+
input: process.stdin,
|
|
429
|
+
output: process.stdout
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
rl.question('API Key: ', (apiKey) => {
|
|
433
|
+
rl.close();
|
|
434
|
+
|
|
435
|
+
apiKey = apiKey.trim();
|
|
436
|
+
|
|
437
|
+
if (!apiKey) {
|
|
438
|
+
console.error('ā No API key provided');
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Validate format (sk_live_... or sk_test_...)
|
|
443
|
+
if (!apiKey.startsWith('sk_live_') && !apiKey.startsWith('sk_test_')) {
|
|
444
|
+
console.error('ā Invalid API key format');
|
|
445
|
+
console.error('Expected format: sk_live_... or sk_test_...');
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Save to config
|
|
450
|
+
config.setApiKey(apiKey);
|
|
451
|
+
|
|
452
|
+
const keyType = apiKey.startsWith('sk_live_') ? 'Live' : 'Test';
|
|
453
|
+
console.log(`\nā
${keyType} API key saved successfully!`);
|
|
454
|
+
console.log(`Config: ${config.getConfigPath()}`);
|
|
455
|
+
console.log('\nYou can now use: aiwarden validate "text"');
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Logout command
|
|
460
|
+
function logoutCommand() {
|
|
461
|
+
const currentKey = config.getApiKey();
|
|
462
|
+
|
|
463
|
+
if (!currentKey) {
|
|
464
|
+
console.log('ā¹ļø No API key configured');
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
config.removeApiKey();
|
|
469
|
+
console.log('ā
API key removed');
|
|
470
|
+
console.log(`Config file: ${config.getConfigPath()}`);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Whoami command
|
|
474
|
+
function whoamiCommand() {
|
|
475
|
+
const apiKey = config.getApiKey();
|
|
476
|
+
|
|
477
|
+
if (!apiKey) {
|
|
478
|
+
console.log('ā Not logged in');
|
|
479
|
+
console.log('Run: aiwarden login');
|
|
480
|
+
process.exit(1);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const keyType = apiKey.startsWith('sk_live_') ? 'Live' : 'Test';
|
|
484
|
+
const masked = apiKey.substring(0, 12) + '...' + apiKey.substring(apiKey.length - 4);
|
|
485
|
+
|
|
486
|
+
console.log('ā
Logged in');
|
|
487
|
+
console.log(`Type: ${keyType}`);
|
|
488
|
+
console.log(`Key: ${masked}`);
|
|
489
|
+
console.log(`Config: ${config.getConfigPath()}`);
|
|
490
|
+
}
|
|
491
|
+
|
|
386
492
|
// Main
|
|
387
493
|
(async () => {
|
|
388
494
|
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
@@ -403,6 +509,12 @@ function parseArgs() {
|
|
|
403
509
|
const text = args[1];
|
|
404
510
|
const options = parseArgs();
|
|
405
511
|
await validateCommand(text, options);
|
|
512
|
+
} else if (command === 'login') {
|
|
513
|
+
await loginCommand();
|
|
514
|
+
} else if (command === 'logout') {
|
|
515
|
+
logoutCommand();
|
|
516
|
+
} else if (command === 'whoami') {
|
|
517
|
+
whoamiCommand();
|
|
406
518
|
} else {
|
|
407
519
|
console.error(`ā Unknown command: ${command}`);
|
|
408
520
|
console.log('Run "aiwarden help" for usage information');
|
package/src/config.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-Warden Config Manager
|
|
3
|
+
* Handles API key storage in ~/.config/aiwarden/config.json
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
|
|
10
|
+
const CONFIG_DIR = path.join(os.homedir(), '.config', 'aiwarden');
|
|
11
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Ensure config directory exists
|
|
15
|
+
*/
|
|
16
|
+
function ensureConfigDir() {
|
|
17
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
18
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Load config from file
|
|
24
|
+
* @returns {object} Config object (empty if file doesn't exist)
|
|
25
|
+
*/
|
|
26
|
+
function loadConfig() {
|
|
27
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const data = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
33
|
+
return JSON.parse(data);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error('ā ļø Warning: Could not read config file:', error.message);
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Save config to file
|
|
42
|
+
* @param {object} config - Config object to save
|
|
43
|
+
*/
|
|
44
|
+
function saveConfig(config) {
|
|
45
|
+
ensureConfigDir();
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('ā Error: Could not save config:', error.message);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get stored API key
|
|
57
|
+
* @returns {string|null} API key or null if not set
|
|
58
|
+
*/
|
|
59
|
+
function getApiKey() {
|
|
60
|
+
const config = loadConfig();
|
|
61
|
+
return config.apiKey || null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Set API key
|
|
66
|
+
* @param {string} apiKey - API key to store
|
|
67
|
+
*/
|
|
68
|
+
function setApiKey(apiKey) {
|
|
69
|
+
const config = loadConfig();
|
|
70
|
+
config.apiKey = apiKey;
|
|
71
|
+
saveConfig(config);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Remove API key
|
|
76
|
+
*/
|
|
77
|
+
function removeApiKey() {
|
|
78
|
+
const config = loadConfig();
|
|
79
|
+
delete config.apiKey;
|
|
80
|
+
saveConfig(config);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get config file path
|
|
85
|
+
* @returns {string} Path to config file
|
|
86
|
+
*/
|
|
87
|
+
function getConfigPath() {
|
|
88
|
+
return CONFIG_FILE;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
getApiKey,
|
|
93
|
+
setApiKey,
|
|
94
|
+
removeApiKey,
|
|
95
|
+
getConfigPath,
|
|
96
|
+
loadConfig,
|
|
97
|
+
saveConfig
|
|
98
|
+
};
|