lsh-framework 1.1.0 ā 1.2.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 +30 -1
- package/dist/services/secrets/secrets.js +100 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,6 +104,34 @@ lsh sync # Stored as: app1_dev
|
|
|
104
104
|
|
|
105
105
|
cd ~/repos/app2
|
|
106
106
|
lsh sync # Stored as: app2_dev (separate!)
|
|
107
|
+
|
|
108
|
+
# See what's tracked in the current directory
|
|
109
|
+
lsh info
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Example `lsh info` output:**
|
|
113
|
+
```
|
|
114
|
+
š Current Directory Context
|
|
115
|
+
|
|
116
|
+
š Git Repository:
|
|
117
|
+
Name: myapp
|
|
118
|
+
Branch: main
|
|
119
|
+
|
|
120
|
+
š Environment Tracking:
|
|
121
|
+
Base environment: dev
|
|
122
|
+
Cloud storage name: myapp_dev
|
|
123
|
+
Namespace: myapp
|
|
124
|
+
ā¹ļø Repo-based isolation enabled
|
|
125
|
+
|
|
126
|
+
š Local .env File:
|
|
127
|
+
Keys: 12
|
|
128
|
+
Has encryption key: ā
|
|
129
|
+
|
|
130
|
+
āļø Cloud Storage:
|
|
131
|
+
Environment: myapp_dev
|
|
132
|
+
Keys stored: 12
|
|
133
|
+
Last updated: 11/6/2025, 10:15:23 PM
|
|
134
|
+
Key matches: ā
|
|
107
135
|
```
|
|
108
136
|
|
|
109
137
|
No more conflicts between projects using the same environment names!
|
|
@@ -223,7 +251,8 @@ lsh set DATABASE_URL postgres://localhost/db
|
|
|
223
251
|
| `lsh create` | Create new .env file |
|
|
224
252
|
| `lsh delete` | Delete .env file (with confirmation) |
|
|
225
253
|
| `lsh sync` | Smart sync (auto-setup and sync) |
|
|
226
|
-
| `lsh status` | Get detailed secrets status |
|
|
254
|
+
| `lsh status` | Get detailed secrets status (JSON) |
|
|
255
|
+
| `lsh info` | Show current context and tracked environment |
|
|
227
256
|
| `lsh get <key>` | Get a specific secret value |
|
|
228
257
|
| `lsh set <key> <value>` | Set a single secret value |
|
|
229
258
|
| `printenv \| lsh set` | Batch upsert from stdin (pipe) |
|
|
@@ -6,6 +6,7 @@ import SecretsManager from '../../lib/secrets-manager.js';
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import * as readline from 'readline';
|
|
9
|
+
import { getGitRepoInfo } from '../../lib/git-utils.js';
|
|
9
10
|
export async function init_secrets(program) {
|
|
10
11
|
// Push secrets to cloud
|
|
11
12
|
program
|
|
@@ -272,6 +273,105 @@ API_KEY=
|
|
|
272
273
|
process.exit(1);
|
|
273
274
|
}
|
|
274
275
|
});
|
|
276
|
+
// Info command - show relevant context information
|
|
277
|
+
program
|
|
278
|
+
.command('info')
|
|
279
|
+
.description('Show current directory context and tracked environment')
|
|
280
|
+
.option('-f, --file <path>', 'Path to .env file', '.env')
|
|
281
|
+
.option('-e, --env <name>', 'Environment name', 'dev')
|
|
282
|
+
.action(async (options) => {
|
|
283
|
+
try {
|
|
284
|
+
const gitInfo = getGitRepoInfo();
|
|
285
|
+
const manager = new SecretsManager();
|
|
286
|
+
const envPath = path.resolve(options.file);
|
|
287
|
+
console.log('\nš Current Directory Context\n');
|
|
288
|
+
// Git Repository Info
|
|
289
|
+
if (gitInfo.isGitRepo) {
|
|
290
|
+
console.log('š Git Repository:');
|
|
291
|
+
console.log(` Root: ${gitInfo.rootPath || 'unknown'}`);
|
|
292
|
+
console.log(` Name: ${gitInfo.repoName || 'unknown'}`);
|
|
293
|
+
if (gitInfo.currentBranch) {
|
|
294
|
+
console.log(` Branch: ${gitInfo.currentBranch}`);
|
|
295
|
+
}
|
|
296
|
+
if (gitInfo.remoteUrl) {
|
|
297
|
+
console.log(` Remote: ${gitInfo.remoteUrl}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
console.log('š Not in a git repository');
|
|
302
|
+
}
|
|
303
|
+
console.log('');
|
|
304
|
+
// Environment Tracking
|
|
305
|
+
console.log('š Environment Tracking:');
|
|
306
|
+
// Show the effective environment name used for cloud storage
|
|
307
|
+
const effectiveEnv = gitInfo.repoName
|
|
308
|
+
? `${gitInfo.repoName}_${options.env}`
|
|
309
|
+
: options.env;
|
|
310
|
+
console.log(` Base environment: ${options.env}`);
|
|
311
|
+
console.log(` Cloud storage name: ${effectiveEnv}`);
|
|
312
|
+
if (gitInfo.repoName) {
|
|
313
|
+
console.log(` Namespace: ${gitInfo.repoName}`);
|
|
314
|
+
console.log(' ā¹ļø Repo-based isolation enabled');
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
console.log(' Namespace: (none - not in git repo)');
|
|
318
|
+
console.log(' ā ļø No isolation - shared environment name');
|
|
319
|
+
}
|
|
320
|
+
console.log('');
|
|
321
|
+
// Local File Status
|
|
322
|
+
console.log('š Local .env File:');
|
|
323
|
+
if (fs.existsSync(envPath)) {
|
|
324
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
325
|
+
const lines = content.split('\n').filter(line => {
|
|
326
|
+
const trimmed = line.trim();
|
|
327
|
+
return trimmed && !trimmed.startsWith('#') && trimmed.includes('=');
|
|
328
|
+
});
|
|
329
|
+
console.log(` Path: ${envPath}`);
|
|
330
|
+
console.log(` Keys: ${lines.length}`);
|
|
331
|
+
console.log(` Size: ${Math.round(content.length / 1024 * 10) / 10} KB`);
|
|
332
|
+
// Check for encryption key
|
|
333
|
+
const hasKey = content.includes('LSH_SECRETS_KEY=');
|
|
334
|
+
console.log(` Has encryption key: ${hasKey ? 'ā
' : 'ā'}`);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
console.log(` Path: ${envPath}`);
|
|
338
|
+
console.log(' Status: ā Not found');
|
|
339
|
+
}
|
|
340
|
+
console.log('');
|
|
341
|
+
// Cloud Status
|
|
342
|
+
console.log('āļø Cloud Storage:');
|
|
343
|
+
try {
|
|
344
|
+
const status = await manager.status(options.file, options.env);
|
|
345
|
+
if (status.cloudExists) {
|
|
346
|
+
console.log(` Environment: ${effectiveEnv}`);
|
|
347
|
+
console.log(` Keys stored: ${status.cloudKeys}`);
|
|
348
|
+
console.log(` Last updated: ${status.cloudModified ? new Date(status.cloudModified).toLocaleString() : 'unknown'}`);
|
|
349
|
+
if (status.keyMatches !== undefined) {
|
|
350
|
+
console.log(` Key matches: ${status.keyMatches ? 'ā
' : 'ā MISMATCH'}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
console.log(` Environment: ${effectiveEnv}`);
|
|
355
|
+
console.log(' Status: ā Not synced yet');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
catch (_error) {
|
|
359
|
+
console.log(' Status: ā ļø Unable to check (Supabase not configured)');
|
|
360
|
+
}
|
|
361
|
+
console.log('');
|
|
362
|
+
// Quick Actions
|
|
363
|
+
console.log('š” Quick Actions:');
|
|
364
|
+
console.log(` Push: lsh push --env ${options.env}`);
|
|
365
|
+
console.log(` Pull: lsh pull --env ${options.env}`);
|
|
366
|
+
console.log(` Sync: lsh sync --env ${options.env}`);
|
|
367
|
+
console.log('');
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
const err = error;
|
|
371
|
+
console.error('ā Failed to get info:', err.message);
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
275
375
|
// Get a specific secret value
|
|
276
376
|
program
|
|
277
377
|
.command('get [key]')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Encrypted secrets manager with automatic rotation, team sync, and multi-environment support. Built on a powerful shell with daemon scheduling and CI/CD integration.",
|
|
5
5
|
"main": "dist/app.js",
|
|
6
6
|
"bin": {
|