@lockr-dev/cli 1.0.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/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # Lockr CLI
2
+
3
+ A command-line interface for managing secrets with Lockr.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @lockr/cli
9
+ # or
10
+ npx @lockr/cli
11
+ ```
12
+
13
+ ## Authentication
14
+
15
+ First, create an API token in the Lockr dashboard:
16
+ 1. Go to **Integrations** → **API Tokens (Pull)**
17
+ 2. Click **Create API Token**
18
+ 3. Copy your token
19
+
20
+ Then authenticate:
21
+
22
+ ```bash
23
+ lockr auth login --token YOUR_API_TOKEN
24
+ # or set the environment variable
25
+ export LOCKR_API_TOKEN=YOUR_API_TOKEN
26
+ ```
27
+
28
+ ## Commands
29
+
30
+ ### Pull Secrets
31
+
32
+ Pull secrets from Lockr to your local environment:
33
+
34
+ ```bash
35
+ # Pull all secrets for production
36
+ lockr pull --env production
37
+
38
+ # Pull to a specific file
39
+ lockr pull --env production --output .env
40
+
41
+ # Pull specific keys only
42
+ lockr pull --env production --keys API_KEY,DATABASE_URL
43
+
44
+ # Output as JSON
45
+ lockr pull --env production --format json
46
+ ```
47
+
48
+ ### Run with Secrets
49
+
50
+ Run a command with secrets injected as environment variables:
51
+
52
+ ```bash
53
+ # Run your app with production secrets
54
+ lockr run --env production -- npm start
55
+
56
+ # Run with staging secrets
57
+ lockr run --env staging -- docker-compose up
58
+ ```
59
+
60
+ ### List Environments
61
+
62
+ ```bash
63
+ lockr envs list
64
+ ```
65
+
66
+ ### Whoami
67
+
68
+ Check your current authentication:
69
+
70
+ ```bash
71
+ lockr whoami
72
+ ```
73
+
74
+ ## Configuration
75
+
76
+ Create a `.lockrrc` file in your project root:
77
+
78
+ ```json
79
+ {
80
+ "project": "my-project",
81
+ "defaultEnv": "development"
82
+ }
83
+ ```
84
+
85
+ ## CI/CD Usage
86
+
87
+ ### GitHub Actions
88
+
89
+ ```yaml
90
+ steps:
91
+ - name: Pull secrets
92
+ run: npx @lockr/cli pull --env production --output .env
93
+ env:
94
+ LOCKR_API_TOKEN: ${{ secrets.LOCKR_API_TOKEN }}
95
+ ```
96
+
97
+ ### GitLab CI
98
+
99
+ ```yaml
100
+ deploy:
101
+ script:
102
+ - npx @lockr/cli pull --env production --output .env
103
+ - docker build -t myapp .
104
+ variables:
105
+ LOCKR_API_TOKEN: $LOCKR_API_TOKEN
106
+ ```
107
+
108
+ ### CircleCI
109
+
110
+ ```yaml
111
+ jobs:
112
+ build:
113
+ steps:
114
+ - run:
115
+ name: Pull secrets
116
+ command: npx @lockr/cli pull --env production --output .env
117
+ ```
118
+
119
+ ## Environment Variables
120
+
121
+ | Variable | Description |
122
+ |----------|-------------|
123
+ | `LOCKR_API_TOKEN` | Your API token for authentication |
124
+ | `LOCKR_API_URL` | Custom API URL (default: production) |
125
+ | `LOCKR_PROJECT` | Default project to use |
126
+
127
+ ## License
128
+
129
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ interface PullOptions {
2
+ environment?: string;
3
+ keys?: string[];
4
+ format?: 'json' | 'env' | 'dotenv';
5
+ }
6
+ export declare function fetchSecrets(options: PullOptions): Promise<Record<string, string>>;
7
+ export declare function formatAsEnv(secrets: Record<string, string>): string;
8
+ export declare function formatAsJson(secrets: Record<string, string>): string;
9
+ export {};
package/dist/api.js ADDED
@@ -0,0 +1,54 @@
1
+ import { getApiToken, getApiUrl } from './config.js';
2
+ export async function fetchSecrets(options) {
3
+ const token = getApiToken();
4
+ if (!token) {
5
+ throw new Error('Not authenticated. Run `lockr auth login --token YOUR_TOKEN` or set LOCKR_API_TOKEN environment variable.');
6
+ }
7
+ const apiUrl = getApiUrl();
8
+ const url = new URL(`${apiUrl}/pull-secrets`);
9
+ if (options.environment) {
10
+ url.searchParams.set('environment', options.environment);
11
+ }
12
+ if (options.format) {
13
+ url.searchParams.set('format', options.format);
14
+ }
15
+ if (options.keys && options.keys.length > 0) {
16
+ url.searchParams.set('keys', options.keys.join(','));
17
+ }
18
+ const response = await fetch(url.toString(), {
19
+ method: 'GET',
20
+ headers: {
21
+ 'X-API-Key': token,
22
+ 'Content-Type': 'application/json',
23
+ },
24
+ });
25
+ if (!response.ok) {
26
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
27
+ throw new Error(error.error || error.message || `HTTP ${response.status}`);
28
+ }
29
+ // Handle different response formats
30
+ const contentType = response.headers.get('content-type');
31
+ if (contentType?.includes('text/plain')) {
32
+ // .env format - parse it
33
+ const text = await response.text();
34
+ const secrets = {};
35
+ for (const line of text.split('\n')) {
36
+ const match = line.match(/^([^=]+)="(.*)"/);
37
+ if (match) {
38
+ secrets[match[1]] = match[2].replace(/\\"/g, '"');
39
+ }
40
+ }
41
+ return secrets;
42
+ }
43
+ // JSON format
44
+ const data = await response.json();
45
+ return data.secrets;
46
+ }
47
+ export function formatAsEnv(secrets) {
48
+ return Object.entries(secrets)
49
+ .map(([key, value]) => `${key}="${value.replace(/"/g, '\\"')}"`)
50
+ .join('\n');
51
+ }
52
+ export function formatAsJson(secrets) {
53
+ return JSON.stringify(secrets, null, 2);
54
+ }
@@ -0,0 +1,10 @@
1
+ interface LoginOptions {
2
+ token?: string;
3
+ }
4
+ declare function login(options: LoginOptions): Promise<void>;
5
+ declare function logout(): Promise<void>;
6
+ export declare const authCommand: {
7
+ login: typeof login;
8
+ logout: typeof logout;
9
+ };
10
+ export {};
@@ -0,0 +1,50 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { setApiToken, clearApiToken, getApiToken, getApiUrl } from '../config.js';
4
+ async function login(options) {
5
+ const token = options.token || process.env.LOCKR_API_TOKEN;
6
+ if (!token) {
7
+ console.error(chalk.red('No token provided.'));
8
+ console.log('\nUsage:');
9
+ console.log(' lockr auth login --token YOUR_API_TOKEN');
10
+ console.log(' # or');
11
+ console.log(' export LOCKR_API_TOKEN=YOUR_API_TOKEN && lockr auth login');
12
+ process.exit(1);
13
+ }
14
+ const spinner = ora('Validating token...').start();
15
+ try {
16
+ // Validate the token by making a request
17
+ const response = await fetch(`${getApiUrl()}/pull-secrets`, {
18
+ method: 'GET',
19
+ headers: {
20
+ 'X-API-Key': token,
21
+ },
22
+ });
23
+ // 404 is OK (no environment specified), 401/403 means bad token
24
+ if (response.status === 401 || response.status === 403) {
25
+ throw new Error('Invalid API token');
26
+ }
27
+ // Store the token
28
+ setApiToken(token);
29
+ spinner.succeed(chalk.green('Successfully authenticated!'));
30
+ console.log(chalk.dim('\nYour token has been saved. You can now use lockr commands.'));
31
+ }
32
+ catch (error) {
33
+ spinner.fail('Authentication failed');
34
+ console.error(chalk.red(error.message));
35
+ process.exit(1);
36
+ }
37
+ }
38
+ async function logout() {
39
+ const token = getApiToken();
40
+ if (!token) {
41
+ console.log(chalk.yellow('Not currently authenticated.'));
42
+ return;
43
+ }
44
+ clearApiToken();
45
+ console.log(chalk.green('Successfully logged out.'));
46
+ }
47
+ export const authCommand = {
48
+ login,
49
+ logout,
50
+ };
@@ -0,0 +1 @@
1
+ export declare function envsCommand(): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import chalk from 'chalk';
2
+ export async function envsCommand() {
3
+ console.log(chalk.yellow('This command requires project context.'));
4
+ console.log(chalk.dim('\nEnvironments are fetched from your Lockr project.'));
5
+ console.log(chalk.dim('Common environments: development, staging, production'));
6
+ console.log('\nUsage:');
7
+ console.log(' lockr pull --env development');
8
+ console.log(' lockr pull --env staging');
9
+ console.log(' lockr pull --env production');
10
+ }
@@ -0,0 +1,8 @@
1
+ interface PullCommandOptions {
2
+ env: string;
3
+ output?: string;
4
+ format: 'env' | 'json' | 'dotenv';
5
+ keys?: string;
6
+ }
7
+ export declare function pullCommand(options: PullCommandOptions): Promise<void>;
8
+ export {};
@@ -0,0 +1,37 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import fs from 'fs';
4
+ import { fetchSecrets, formatAsEnv, formatAsJson } from '../api.js';
5
+ export async function pullCommand(options) {
6
+ const spinner = ora(`Pulling secrets from ${chalk.cyan(options.env)}...`).start();
7
+ try {
8
+ const keys = options.keys?.split(',').map(k => k.trim()).filter(Boolean);
9
+ const secrets = await fetchSecrets({
10
+ environment: options.env,
11
+ keys,
12
+ format: options.format === 'json' ? 'json' : 'env',
13
+ });
14
+ spinner.succeed(`Pulled ${chalk.green(Object.keys(secrets).length)} secrets`);
15
+ // Format output
16
+ let output;
17
+ if (options.format === 'json') {
18
+ output = formatAsJson(secrets);
19
+ }
20
+ else {
21
+ output = formatAsEnv(secrets);
22
+ }
23
+ // Write to file or stdout
24
+ if (options.output) {
25
+ fs.writeFileSync(options.output, output + '\n');
26
+ console.log(chalk.dim(`Written to ${options.output}`));
27
+ }
28
+ else {
29
+ console.log('\n' + output);
30
+ }
31
+ }
32
+ catch (error) {
33
+ spinner.fail('Failed to pull secrets');
34
+ console.error(chalk.red(error.message));
35
+ process.exit(1);
36
+ }
37
+ }
@@ -0,0 +1,5 @@
1
+ interface RunCommandOptions {
2
+ env: string;
3
+ }
4
+ export declare function runCommand(command: string[], options: RunCommandOptions): Promise<void>;
5
+ export {};
@@ -0,0 +1,41 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { spawn } from 'child_process';
4
+ import { fetchSecrets } from '../api.js';
5
+ export async function runCommand(command, options) {
6
+ const spinner = ora(`Loading secrets from ${chalk.cyan(options.env)}...`).start();
7
+ try {
8
+ const secrets = await fetchSecrets({
9
+ environment: options.env,
10
+ });
11
+ spinner.succeed(`Loaded ${chalk.green(Object.keys(secrets).length)} secrets`);
12
+ // Get the command and args
13
+ const [cmd, ...args] = command;
14
+ if (!cmd) {
15
+ console.error(chalk.red('No command specified'));
16
+ process.exit(1);
17
+ }
18
+ console.log(chalk.dim(`Running: ${cmd} ${args.join(' ')}\n`));
19
+ // Spawn the process with secrets as environment variables
20
+ const child = spawn(cmd, args, {
21
+ env: {
22
+ ...process.env,
23
+ ...secrets,
24
+ },
25
+ stdio: 'inherit',
26
+ shell: true,
27
+ });
28
+ child.on('error', (error) => {
29
+ console.error(chalk.red(`Failed to start process: ${error.message}`));
30
+ process.exit(1);
31
+ });
32
+ child.on('exit', (code) => {
33
+ process.exit(code ?? 0);
34
+ });
35
+ }
36
+ catch (error) {
37
+ spinner.fail('Failed to load secrets');
38
+ console.error(chalk.red(error.message));
39
+ process.exit(1);
40
+ }
41
+ }
@@ -0,0 +1,9 @@
1
+ interface SyncOptions {
2
+ env?: string;
3
+ integration?: string;
4
+ all?: boolean;
5
+ dryRun?: boolean;
6
+ }
7
+ export declare function syncCommand(options: SyncOptions): Promise<void>;
8
+ export declare function listIntegrationsCommand(): Promise<void>;
9
+ export {};
@@ -0,0 +1,164 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { getApiToken, getApiUrl } from '../config.js';
4
+ async function fetchIntegrations() {
5
+ const token = getApiToken();
6
+ const apiUrl = getApiUrl();
7
+ const response = await fetch(`${apiUrl}/integrations`, {
8
+ method: 'GET',
9
+ headers: {
10
+ 'X-API-Key': token,
11
+ 'Content-Type': 'application/json',
12
+ },
13
+ });
14
+ if (!response.ok) {
15
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
16
+ throw new Error(error.error || `HTTP ${response.status}`);
17
+ }
18
+ return response.json();
19
+ }
20
+ async function syncIntegration(integrationId, environment) {
21
+ const token = getApiToken();
22
+ const apiUrl = getApiUrl();
23
+ const url = new URL(`${apiUrl}/sync-integration`);
24
+ url.searchParams.set('integration_id', integrationId);
25
+ if (environment) {
26
+ url.searchParams.set('environment', environment);
27
+ }
28
+ const response = await fetch(url.toString(), {
29
+ method: 'POST',
30
+ headers: {
31
+ 'X-API-Key': token,
32
+ 'Content-Type': 'application/json',
33
+ },
34
+ });
35
+ if (!response.ok) {
36
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
37
+ return {
38
+ integration_id: integrationId,
39
+ integration_name: 'Unknown',
40
+ status: 'error',
41
+ error: error.error || `HTTP ${response.status}`,
42
+ };
43
+ }
44
+ return response.json();
45
+ }
46
+ export async function syncCommand(options) {
47
+ const token = getApiToken();
48
+ if (!token) {
49
+ console.error(chalk.red('✗ Not authenticated.'));
50
+ console.error(chalk.dim('Run `lockr auth login --token YOUR_TOKEN` or set LOCKR_API_TOKEN'));
51
+ process.exit(1);
52
+ }
53
+ const spinner = ora('Fetching integrations...').start();
54
+ try {
55
+ const integrations = await fetchIntegrations();
56
+ if (integrations.length === 0) {
57
+ spinner.fail('No integrations found');
58
+ console.log(chalk.dim('\nConnect integrations at https://lockrdev.com/integrations'));
59
+ process.exit(1);
60
+ }
61
+ // Filter integrations if specific one requested
62
+ let targetIntegrations = integrations.filter(i => i.status === 'connected');
63
+ if (options.integration) {
64
+ targetIntegrations = targetIntegrations.filter(i => i.name.toLowerCase().includes(options.integration.toLowerCase()) ||
65
+ i.provider.toLowerCase() === options.integration.toLowerCase());
66
+ if (targetIntegrations.length === 0) {
67
+ spinner.fail(`No matching integration found: ${options.integration}`);
68
+ console.log(chalk.dim('\nAvailable integrations:'));
69
+ integrations.forEach(i => {
70
+ console.log(chalk.dim(` - ${i.name} (${i.provider})`));
71
+ });
72
+ process.exit(1);
73
+ }
74
+ }
75
+ if (!options.all && targetIntegrations.length > 1 && !options.integration) {
76
+ spinner.stop();
77
+ console.log(chalk.yellow('⚠ Multiple integrations found. Use --all to sync all, or --integration to specify one.\n'));
78
+ console.log('Available integrations:');
79
+ targetIntegrations.forEach(i => {
80
+ console.log(` ${chalk.cyan(i.name)} ${chalk.dim(`(${i.provider})`)}`);
81
+ });
82
+ process.exit(1);
83
+ }
84
+ if (options.dryRun) {
85
+ spinner.stop();
86
+ console.log(chalk.blue('ℹ Dry run mode - no changes will be made\n'));
87
+ console.log('Would sync to:');
88
+ targetIntegrations.forEach(i => {
89
+ console.log(` ${chalk.cyan(i.name)} ${chalk.dim(`(${i.provider})`)}`);
90
+ });
91
+ if (options.env) {
92
+ console.log(chalk.dim(`\nEnvironment: ${options.env}`));
93
+ }
94
+ return;
95
+ }
96
+ spinner.text = `Syncing secrets to ${targetIntegrations.length} integration(s)...`;
97
+ const results = [];
98
+ for (const integration of targetIntegrations) {
99
+ spinner.text = `Syncing to ${integration.name}...`;
100
+ const result = await syncIntegration(integration.id, options.env);
101
+ result.integration_name = integration.name;
102
+ results.push(result);
103
+ }
104
+ spinner.stop();
105
+ // Print results
106
+ console.log(chalk.bold('\nSync Results:\n'));
107
+ let successCount = 0;
108
+ let errorCount = 0;
109
+ for (const result of results) {
110
+ if (result.status === 'success') {
111
+ successCount++;
112
+ console.log(chalk.green('✓'), chalk.bold(result.integration_name), chalk.dim(`- ${result.secrets_synced || 0} secrets synced`));
113
+ }
114
+ else {
115
+ errorCount++;
116
+ console.log(chalk.red('✗'), chalk.bold(result.integration_name), chalk.red(`- ${result.error}`));
117
+ }
118
+ }
119
+ console.log('');
120
+ if (errorCount > 0) {
121
+ console.log(chalk.yellow(`⚠ ${successCount} succeeded, ${errorCount} failed`));
122
+ process.exit(1);
123
+ }
124
+ else {
125
+ console.log(chalk.green(`✓ Successfully synced to ${successCount} integration(s)`));
126
+ }
127
+ }
128
+ catch (error) {
129
+ spinner.fail('Sync failed');
130
+ console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
131
+ process.exit(1);
132
+ }
133
+ }
134
+ // List available integrations
135
+ export async function listIntegrationsCommand() {
136
+ const token = getApiToken();
137
+ if (!token) {
138
+ console.error(chalk.red('✗ Not authenticated.'));
139
+ process.exit(1);
140
+ }
141
+ const spinner = ora('Fetching integrations...').start();
142
+ try {
143
+ const integrations = await fetchIntegrations();
144
+ spinner.stop();
145
+ if (integrations.length === 0) {
146
+ console.log(chalk.yellow('No integrations configured'));
147
+ console.log(chalk.dim('\nConnect integrations at https://lockrdev.com/integrations'));
148
+ return;
149
+ }
150
+ console.log(chalk.bold('\nConfigured Integrations:\n'));
151
+ for (const integration of integrations) {
152
+ const statusIcon = integration.status === 'connected'
153
+ ? chalk.green('●')
154
+ : chalk.yellow('○');
155
+ console.log(` ${statusIcon} ${chalk.bold(integration.name)}`, chalk.dim(`(${integration.provider})`), chalk.dim(`- ${integration.status}`));
156
+ }
157
+ console.log('');
158
+ }
159
+ catch (error) {
160
+ spinner.fail('Failed to fetch integrations');
161
+ console.error(chalk.red(error instanceof Error ? error.message : 'Unknown error'));
162
+ process.exit(1);
163
+ }
164
+ }
@@ -0,0 +1 @@
1
+ export declare function whoamiCommand(): Promise<void>;
@@ -0,0 +1,13 @@
1
+ import chalk from 'chalk';
2
+ import { getApiToken, getApiUrl } from '../config.js';
3
+ export async function whoamiCommand() {
4
+ const token = getApiToken();
5
+ if (!token) {
6
+ console.log(chalk.yellow('Not authenticated.'));
7
+ console.log(chalk.dim('\nRun `lockr auth login --token YOUR_TOKEN` to authenticate.'));
8
+ return;
9
+ }
10
+ console.log(chalk.green('✓ Authenticated'));
11
+ console.log(chalk.dim(`Token: ${token.substring(0, 8)}...`));
12
+ console.log(chalk.dim(`API URL: ${getApiUrl()}`));
13
+ }
@@ -0,0 +1,13 @@
1
+ import Conf from 'conf';
2
+ interface Config {
3
+ apiToken?: string;
4
+ apiUrl: string;
5
+ project?: string;
6
+ }
7
+ declare const config: Conf<Config>;
8
+ export declare function getApiToken(): string | undefined;
9
+ export declare function setApiToken(token: string): void;
10
+ export declare function clearApiToken(): void;
11
+ export declare function getApiUrl(): string;
12
+ export declare function getProject(): string | undefined;
13
+ export { config };
package/dist/config.js ADDED
@@ -0,0 +1,23 @@
1
+ import Conf from 'conf';
2
+ const config = new Conf({
3
+ projectName: 'lockr-cli',
4
+ defaults: {
5
+ apiUrl: 'https://cqtzvcifscaqxuieqhsn.supabase.co/functions/v1',
6
+ },
7
+ });
8
+ export function getApiToken() {
9
+ return process.env.LOCKR_API_TOKEN || config.get('apiToken');
10
+ }
11
+ export function setApiToken(token) {
12
+ config.set('apiToken', token);
13
+ }
14
+ export function clearApiToken() {
15
+ config.delete('apiToken');
16
+ }
17
+ export function getApiUrl() {
18
+ return process.env.LOCKR_API_URL || config.get('apiUrl');
19
+ }
20
+ export function getProject() {
21
+ return process.env.LOCKR_PROJECT || config.get('project');
22
+ }
23
+ export { config };
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { pullCommand } from './commands/pull.js';
4
+ import { runCommand } from './commands/run.js';
5
+ import { authCommand } from './commands/auth.js';
6
+ import { envsCommand } from './commands/envs.js';
7
+ import { whoamiCommand } from './commands/whoami.js';
8
+ import { syncCommand, listIntegrationsCommand } from './commands/sync.js';
9
+ const program = new Command();
10
+ program
11
+ .name('lockr')
12
+ .description('CLI for managing secrets with Lockr')
13
+ .version('1.0.0');
14
+ // Pull secrets command
15
+ program
16
+ .command('pull')
17
+ .description('Pull secrets from Lockr')
18
+ .option('-e, --env <environment>', 'Environment to pull from', 'development')
19
+ .option('-o, --output <file>', 'Output file path (default: stdout)')
20
+ .option('-f, --format <format>', 'Output format: env, json, dotenv', 'env')
21
+ .option('-k, --keys <keys>', 'Comma-separated list of specific keys to pull')
22
+ .action(pullCommand);
23
+ // Run with secrets command
24
+ program
25
+ .command('run')
26
+ .description('Run a command with secrets injected as environment variables')
27
+ .option('-e, --env <environment>', 'Environment to use', 'development')
28
+ .argument('<command...>', 'Command to run')
29
+ .action(runCommand);
30
+ // Auth commands
31
+ const auth = program
32
+ .command('auth')
33
+ .description('Authentication commands');
34
+ auth
35
+ .command('login')
36
+ .description('Authenticate with Lockr')
37
+ .option('-t, --token <token>', 'API token')
38
+ .action(authCommand.login);
39
+ auth
40
+ .command('logout')
41
+ .description('Remove stored credentials')
42
+ .action(authCommand.logout);
43
+ // Environments command
44
+ program
45
+ .command('envs')
46
+ .description('List available environments')
47
+ .action(envsCommand);
48
+ // Whoami command
49
+ program
50
+ .command('whoami')
51
+ .description('Show current authentication status')
52
+ .action(whoamiCommand);
53
+ // Sync command
54
+ program
55
+ .command('sync')
56
+ .description('Sync secrets to connected integrations (for CI/CD)')
57
+ .option('-e, --env <environment>', 'Environment to sync from', 'production')
58
+ .option('-i, --integration <name>', 'Specific integration to sync to')
59
+ .option('-a, --all', 'Sync to all connected integrations')
60
+ .option('--dry-run', 'Show what would be synced without making changes')
61
+ .action(syncCommand);
62
+ // Integrations command
63
+ program
64
+ .command('integrations')
65
+ .description('List configured integrations')
66
+ .action(listIntegrationsCommand);
67
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@lockr-dev/cli",
3
+ "version": "1.0.0",
4
+ "description": "Command-line interface for Lockr secrets management - securely pull, sync, and inject environment variables",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "lockr": "./dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "dev": "ts-node src/index.ts",
18
+ "prepublishOnly": "npm run build",
19
+ "test": "echo \"No tests yet\" && exit 0"
20
+ },
21
+ "keywords": [
22
+ "secrets",
23
+ "environment",
24
+ "cli",
25
+ "lockr",
26
+ "env",
27
+ "configuration",
28
+ "dotenv",
29
+ "secrets-management",
30
+ "environment-variables",
31
+ "devops",
32
+ "ci-cd"
33
+ ],
34
+ "author": "LockrDev <hello@lockrdev.com>",
35
+ "license": "MIT",
36
+ "homepage": "https://lockrdev.com",
37
+ "bugs": {
38
+ "url": "https://github.com/lockrdev/cli/issues"
39
+ },
40
+ "dependencies": {
41
+ "commander": "^11.1.0",
42
+ "chalk": "^5.3.0",
43
+ "ora": "^8.0.1",
44
+ "conf": "^12.0.0",
45
+ "dotenv": "^16.3.1"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^20.10.0",
49
+ "typescript": "^5.3.0",
50
+ "ts-node": "^10.9.2"
51
+ },
52
+ "engines": {
53
+ "node": ">=18.0.0"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/lockrdev/cli.git"
58
+ }
59
+ }