vaulter-cli 0.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/postinstall.js +1 -0
- package/src/commands/help.js +1 -0
- package/src/commands/init.js +119 -0
- package/src/index.js +11 -1
- package/src/lib/project.js +56 -0
package/package.json
CHANGED
package/postinstall.js
CHANGED
|
@@ -17,6 +17,7 @@ console.log(purple4 + ' Your keys. Your vault.' + reset);
|
|
|
17
17
|
console.log('');
|
|
18
18
|
console.log(purple + ' COMMANDS' + reset);
|
|
19
19
|
console.log('');
|
|
20
|
+
console.log(' ' + bold + white + 'vaulter init ' + reset + dim + 'Initialize current directory as a Vaulter project' + reset);
|
|
20
21
|
console.log(' ' + bold + white + 'vaulter sign-in ' + reset + dim + 'Authenticate with Vaulter via browser' + reset);
|
|
21
22
|
console.log(' ' + bold + white + 'vaulter sign-out ' + reset + dim + 'Sign out and clear saved credentials' + reset);
|
|
22
23
|
console.log(' ' + bold + white + 'vaulter ls ' + reset + dim + 'List all API keys in your vault' + reset);
|
package/src/commands/help.js
CHANGED
|
@@ -16,6 +16,7 @@ export async function showHelp() {
|
|
|
16
16
|
console.log('');
|
|
17
17
|
|
|
18
18
|
const commands = [
|
|
19
|
+
{ name: 'init', desc: 'Initialize current directory as a Vaulter project' },
|
|
19
20
|
{ name: 'sign-in', desc: 'Authenticate with Vaulter via browser' },
|
|
20
21
|
{ name: 'sign-out', desc: 'Sign out and clear saved credentials' },
|
|
21
22
|
{ name: 'ls', desc: 'List all API keys in your vault' },
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import {
|
|
5
|
+
isInitialized,
|
|
6
|
+
getProjectConfig,
|
|
7
|
+
createDefaultConfig,
|
|
8
|
+
writeProjectConfig,
|
|
9
|
+
getProjectDirPath,
|
|
10
|
+
} from '../lib/project.js';
|
|
11
|
+
import { isAuthenticated } from '../lib/auth.js';
|
|
12
|
+
import { success, error, warn, tip, dim, purple, bold, white } from '../lib/ui.js';
|
|
13
|
+
|
|
14
|
+
export async function initProject(options = {}) {
|
|
15
|
+
const root = process.cwd();
|
|
16
|
+
const dirName = path.basename(root);
|
|
17
|
+
const yes = options.yes || false;
|
|
18
|
+
|
|
19
|
+
console.log('');
|
|
20
|
+
|
|
21
|
+
// Check if already initialized
|
|
22
|
+
if (isInitialized(root)) {
|
|
23
|
+
const existing = getProjectConfig(root);
|
|
24
|
+
|
|
25
|
+
if (existing) {
|
|
26
|
+
console.log(dim(` Existing project: ${bold(existing.project?.name || 'unknown')}`));
|
|
27
|
+
console.log(dim(` Created: ${existing.project?.createdAt || 'unknown'}`));
|
|
28
|
+
console.log('');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!yes) {
|
|
32
|
+
const { reinit } = await inquirer.prompt([
|
|
33
|
+
{
|
|
34
|
+
type: 'confirm',
|
|
35
|
+
name: 'reinit',
|
|
36
|
+
message: purple('.vaulter/ already exists. Re-initialize?'),
|
|
37
|
+
default: false,
|
|
38
|
+
},
|
|
39
|
+
]);
|
|
40
|
+
if (!reinit) {
|
|
41
|
+
warn('Cancelled.');
|
|
42
|
+
console.log('');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Prompt for project name
|
|
49
|
+
let projectName = options.name || null;
|
|
50
|
+
|
|
51
|
+
if (!projectName && !yes) {
|
|
52
|
+
const { name } = await inquirer.prompt([
|
|
53
|
+
{
|
|
54
|
+
type: 'input',
|
|
55
|
+
name: 'name',
|
|
56
|
+
message: purple('Project name:'),
|
|
57
|
+
default: dirName,
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
projectName = name;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!projectName) {
|
|
64
|
+
projectName = dirName;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create config
|
|
68
|
+
const config = createDefaultConfig(projectName);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
writeProjectConfig(root, config);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
error(`Failed to create .vaulter/config.json: ${err.message}`);
|
|
74
|
+
console.log('');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
success(`Initialized Vaulter project "${projectName}"`);
|
|
79
|
+
|
|
80
|
+
// Append .vaulter/ to .gitignore if it exists and doesn't already contain it
|
|
81
|
+
const gitignorePath = path.join(root, '.gitignore');
|
|
82
|
+
if (fs.existsSync(gitignorePath)) {
|
|
83
|
+
try {
|
|
84
|
+
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
85
|
+
if (!content.includes('.vaulter/')) {
|
|
86
|
+
fs.appendFileSync(gitignorePath, '\n.vaulter/\n');
|
|
87
|
+
success('Added .vaulter/ to .gitignore');
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
warn('Could not update .gitignore (non-fatal)');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// .env tips based on state
|
|
95
|
+
const envPath = path.join(root, '.env');
|
|
96
|
+
const envExists = fs.existsSync(envPath);
|
|
97
|
+
|
|
98
|
+
if (envExists) {
|
|
99
|
+
tip('Run `vaulter save` to upload your .env to the vault, or `vaulter make` to regenerate it.');
|
|
100
|
+
} else if (isAuthenticated()) {
|
|
101
|
+
console.log('');
|
|
102
|
+
const { generate } = await inquirer.prompt([
|
|
103
|
+
{
|
|
104
|
+
type: 'confirm',
|
|
105
|
+
name: 'generate',
|
|
106
|
+
message: purple('No .env found. Generate one from your vault?'),
|
|
107
|
+
default: true,
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
if (generate) {
|
|
111
|
+
const { makeEnv } = await import('./make.js');
|
|
112
|
+
await makeEnv(undefined, {});
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
tip('Run `vaulter sign-in` to connect your vault, then `vaulter make` to generate a .env.');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log('');
|
|
119
|
+
}
|
package/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { addKey } from './commands/add.js';
|
|
|
8
8
|
import { removeKey } from './commands/remove.js';
|
|
9
9
|
import { makeEnv } from './commands/make.js';
|
|
10
10
|
import { saveEnv } from './commands/save.js';
|
|
11
|
+
import { initProject } from './commands/init.js';
|
|
11
12
|
import { openWebApp } from './commands/web-app.js';
|
|
12
13
|
import { showHelp } from './commands/help.js';
|
|
13
14
|
import { printLogo } from './assets/logo.js';
|
|
@@ -19,7 +20,7 @@ const program = new Command();
|
|
|
19
20
|
program
|
|
20
21
|
.name('vaulter')
|
|
21
22
|
.description('Vaulter CLI - Secure API Key Manager')
|
|
22
|
-
.version('
|
|
23
|
+
.version('2.3.0')
|
|
23
24
|
.action(async () => {
|
|
24
25
|
await showHelp();
|
|
25
26
|
});
|
|
@@ -90,6 +91,15 @@ program
|
|
|
90
91
|
await saveEnv(filename);
|
|
91
92
|
});
|
|
92
93
|
|
|
94
|
+
program
|
|
95
|
+
.command('init')
|
|
96
|
+
.description('Initialize current directory as a Vaulter project')
|
|
97
|
+
.option('-n, --name <name>', 'Project name')
|
|
98
|
+
.option('-y, --yes', 'Non-interactive, use all defaults')
|
|
99
|
+
.action(async (options) => {
|
|
100
|
+
await initProject(options);
|
|
101
|
+
});
|
|
102
|
+
|
|
93
103
|
program
|
|
94
104
|
.command('web-app')
|
|
95
105
|
.description('Open the Vaulter web app in your browser')
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const VAULTER_PROJECT_DIR = '.vaulter';
|
|
5
|
+
const CONFIG_FILE = 'config.json';
|
|
6
|
+
|
|
7
|
+
export function getProjectDirPath(root = process.cwd()) {
|
|
8
|
+
return path.join(root, VAULTER_PROJECT_DIR);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getConfigFilePath(root = process.cwd()) {
|
|
12
|
+
return path.join(root, VAULTER_PROJECT_DIR, CONFIG_FILE);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isInitialized(root = process.cwd()) {
|
|
16
|
+
return fs.existsSync(getConfigFilePath(root));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getProjectConfig(root = process.cwd()) {
|
|
20
|
+
try {
|
|
21
|
+
const data = JSON.parse(fs.readFileSync(getConfigFilePath(root), 'utf-8'));
|
|
22
|
+
return data;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ensureProjectDir(root = process.cwd()) {
|
|
29
|
+
const dirPath = getProjectDirPath(root);
|
|
30
|
+
if (!fs.existsSync(dirPath)) {
|
|
31
|
+
fs.mkdirSync(dirPath, { mode: 0o700 });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function createDefaultConfig(name) {
|
|
36
|
+
const now = new Date().toISOString();
|
|
37
|
+
return {
|
|
38
|
+
version: 1,
|
|
39
|
+
project: {
|
|
40
|
+
name,
|
|
41
|
+
createdAt: now,
|
|
42
|
+
updatedAt: now,
|
|
43
|
+
},
|
|
44
|
+
sync: { enabled: false, remote: null },
|
|
45
|
+
env: { autoGenerate: false, filename: '.env', selectedKeys: [] },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function writeProjectConfig(root, config) {
|
|
50
|
+
ensureProjectDir(root);
|
|
51
|
+
fs.writeFileSync(
|
|
52
|
+
getConfigFilePath(root),
|
|
53
|
+
JSON.stringify(config, null, 2) + '\n',
|
|
54
|
+
{ mode: 0o600 }
|
|
55
|
+
);
|
|
56
|
+
}
|