lsh-framework 0.9.1 → 0.9.3
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/dist/cicd/webhook-receiver.js +9 -3
- package/dist/cli.js +1 -0
- package/dist/commands/api.js +6 -3
- package/dist/commands/self.js +1 -0
- package/dist/commands/theme.js +6 -3
- package/dist/daemon/api-server.js +2 -1
- package/dist/lib/cron-job-manager.js +1 -0
- package/dist/lib/daemon-client-helper.js +6 -5
- package/dist/lib/git-utils.js +4 -2
- package/dist/lib/job-builtins.js +2 -0
- package/dist/lib/job-manager.js +4 -1
- package/dist/lib/lshrc-init.js +9 -4
- package/dist/lib/supabase-client.js +1 -0
- package/dist/lib/zsh-compatibility.js +2 -0
- package/dist/pipeline/pipeline-service.js +3 -0
- package/dist/services/daemon/daemon-registrar.js +10 -5
- package/dist/services/secrets/secrets.js +43 -2
- package/package.json +1 -1
|
@@ -63,6 +63,7 @@ function verifyGitHubSignature(payload, signature) {
|
|
|
63
63
|
const checksum = `sha256=${digest}`;
|
|
64
64
|
return crypto.timingSafeEqual(Buffer.from(signature, 'utf8'), Buffer.from(checksum, 'utf8'));
|
|
65
65
|
}
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
67
|
function parseGitHubWorkflowEvent(body) {
|
|
67
68
|
const { workflow_run, workflow_job, action } = body;
|
|
68
69
|
if (!workflow_run && !workflow_job)
|
|
@@ -127,6 +128,7 @@ function verifyGitLabSignature(payload, signature) {
|
|
|
127
128
|
const digest = hmac.update(payload, 'utf8').digest('hex');
|
|
128
129
|
return crypto.timingSafeEqual(Buffer.from(signature, 'utf8'), Buffer.from(digest, 'utf8'));
|
|
129
130
|
}
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
132
|
function parseGitLabPipelineEvent(body) {
|
|
131
133
|
const { object_kind, object_attributes, project, user } = body;
|
|
132
134
|
if (object_kind !== 'pipeline' && object_kind !== 'job')
|
|
@@ -192,6 +194,7 @@ function mapGitLabConclusion(status) {
|
|
|
192
194
|
default: return 'failure';
|
|
193
195
|
}
|
|
194
196
|
}
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
195
198
|
function parseJenkinsEvent(body) {
|
|
196
199
|
const { name, url, build, timestamp } = body;
|
|
197
200
|
if (!build)
|
|
@@ -574,7 +577,8 @@ app.post('/auth/register', async (req, res) => {
|
|
|
574
577
|
res.json({ user, token });
|
|
575
578
|
}
|
|
576
579
|
catch (error) {
|
|
577
|
-
|
|
580
|
+
const err = error;
|
|
581
|
+
res.status(400).json({ error: err.message });
|
|
578
582
|
}
|
|
579
583
|
});
|
|
580
584
|
app.post('/auth/login', async (req, res) => {
|
|
@@ -584,7 +588,8 @@ app.post('/auth/login', async (req, res) => {
|
|
|
584
588
|
res.json(result);
|
|
585
589
|
}
|
|
586
590
|
catch (error) {
|
|
587
|
-
|
|
591
|
+
const err = error;
|
|
592
|
+
res.status(401).json({ error: err.message });
|
|
588
593
|
}
|
|
589
594
|
});
|
|
590
595
|
app.post('/auth/api-key', authenticate(authService), authorize('admin', 'developer'), async (req, res) => {
|
|
@@ -594,7 +599,8 @@ app.post('/auth/api-key', authenticate(authService), authorize('admin', 'develop
|
|
|
594
599
|
res.json({ apiKey });
|
|
595
600
|
}
|
|
596
601
|
catch (error) {
|
|
597
|
-
|
|
602
|
+
const err = error;
|
|
603
|
+
res.status(400).json({ error: err.message });
|
|
598
604
|
}
|
|
599
605
|
});
|
|
600
606
|
// Protected admin endpoints
|
package/dist/cli.js
CHANGED
|
@@ -482,6 +482,7 @@ async function validateConfig(rcFile) {
|
|
|
482
482
|
/**
|
|
483
483
|
* Load rc file
|
|
484
484
|
*/
|
|
485
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
485
486
|
async function loadRcFile(executor, rcFile) {
|
|
486
487
|
if (!fs.existsSync(rcFile)) {
|
|
487
488
|
console.error(`Configuration file not found: ${rcFile}`);
|
package/dist/commands/api.js
CHANGED
|
@@ -42,7 +42,8 @@ export function registerApiCommands(program) {
|
|
|
42
42
|
console.log(chalk.gray(` curl -H "X-API-Key: ${apiKey}" http://localhost:${options.port}/api/status`));
|
|
43
43
|
}
|
|
44
44
|
catch (error) {
|
|
45
|
-
|
|
45
|
+
const err = error;
|
|
46
|
+
console.error(chalk.red(`❌ Failed to start API server: ${err.message}`));
|
|
46
47
|
process.exit(1);
|
|
47
48
|
}
|
|
48
49
|
});
|
|
@@ -85,7 +86,8 @@ export function registerApiCommands(program) {
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
catch (error) {
|
|
88
|
-
|
|
89
|
+
const err = error;
|
|
90
|
+
console.error(chalk.red(`❌ Failed to connect to API server: ${err.message}`));
|
|
89
91
|
console.log(chalk.yellow('Make sure the daemon is running with API enabled:'));
|
|
90
92
|
console.log(chalk.gray(' lsh api start'));
|
|
91
93
|
}
|
|
@@ -148,7 +150,8 @@ export function registerApiCommands(program) {
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
catch (error) {
|
|
151
|
-
|
|
153
|
+
const err = error;
|
|
154
|
+
console.error(chalk.red(`❌ Failed: ${err.message}`));
|
|
152
155
|
}
|
|
153
156
|
});
|
|
154
157
|
// Example client code generator
|
package/dist/commands/self.js
CHANGED
|
@@ -127,6 +127,7 @@ async function checkCIStatus(_version) {
|
|
|
127
127
|
const ghData = JSON.parse(data);
|
|
128
128
|
const runs = ghData.workflow_runs || [];
|
|
129
129
|
// Find the most recent workflow run for main branch
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
131
|
const mainRuns = runs.filter((run) => run.head_branch === 'main' && run.status === 'completed');
|
|
131
132
|
if (mainRuns.length > 0) {
|
|
132
133
|
const latestRun = mainRuns[0];
|
package/dist/commands/theme.js
CHANGED
|
@@ -83,7 +83,8 @@ export function registerThemeCommands(program) {
|
|
|
83
83
|
process.exit(0);
|
|
84
84
|
}
|
|
85
85
|
catch (error) {
|
|
86
|
-
|
|
86
|
+
const err = error;
|
|
87
|
+
console.error(chalk.red(`✗ Failed to import theme: ${err.message}`));
|
|
87
88
|
process.exit(1);
|
|
88
89
|
}
|
|
89
90
|
});
|
|
@@ -164,7 +165,8 @@ ${commands}
|
|
|
164
165
|
process.exit(0);
|
|
165
166
|
}
|
|
166
167
|
catch (error) {
|
|
167
|
-
|
|
168
|
+
const err = error;
|
|
169
|
+
console.error(chalk.red(`✗ Failed to apply theme: ${err.message}`));
|
|
168
170
|
process.exit(1);
|
|
169
171
|
}
|
|
170
172
|
});
|
|
@@ -251,7 +253,8 @@ ${commands}
|
|
|
251
253
|
process.exit(0);
|
|
252
254
|
}
|
|
253
255
|
catch (error) {
|
|
254
|
-
|
|
256
|
+
const err = error;
|
|
257
|
+
console.error(chalk.red(`✗ Failed to import theme: ${err.message}`));
|
|
255
258
|
process.exit(1);
|
|
256
259
|
}
|
|
257
260
|
});
|
|
@@ -155,7 +155,8 @@ export class LSHApiServer extends BaseAPIServer {
|
|
|
155
155
|
results.push({ success: true, job });
|
|
156
156
|
}
|
|
157
157
|
catch (error) {
|
|
158
|
-
|
|
158
|
+
const err = error;
|
|
159
|
+
results.push({ success: false, error: err.message, jobSpec });
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
res.json({ results });
|
|
@@ -160,6 +160,7 @@ export class CronJobManager extends BaseJobManager {
|
|
|
160
160
|
*/
|
|
161
161
|
async getJobReport(jobId) {
|
|
162
162
|
// Try to get historical data from database if available, otherwise use current job info
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
164
|
let jobs = [];
|
|
164
165
|
try {
|
|
165
166
|
jobs = await this.daemonClient.getJobHistory(jobId, 1000);
|
|
@@ -58,11 +58,12 @@ export async function withDaemonClient(operation, config = {}) {
|
|
|
58
58
|
return result;
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
|
61
|
+
const err = error;
|
|
61
62
|
// Always disconnect on error
|
|
62
63
|
client.disconnect();
|
|
63
64
|
// Handle errors with helpful messages
|
|
64
|
-
if (
|
|
65
|
-
const enhancedError = new Error(`❌ ${
|
|
65
|
+
if (err.message.includes('Permission denied')) {
|
|
66
|
+
const enhancedError = new Error(`❌ ${err.message}\n` +
|
|
66
67
|
`The daemon socket may be owned by another user.\n` +
|
|
67
68
|
`Try starting your own daemon with: lsh daemon start`);
|
|
68
69
|
if (exitOnError) {
|
|
@@ -71,7 +72,7 @@ export async function withDaemonClient(operation, config = {}) {
|
|
|
71
72
|
}
|
|
72
73
|
throw enhancedError;
|
|
73
74
|
}
|
|
74
|
-
else if (
|
|
75
|
+
else if (err.message.includes('not found') || err.message.includes('ENOENT')) {
|
|
75
76
|
const enhancedError = new Error(`❌ Daemon socket not found.\n` +
|
|
76
77
|
`Start the daemon with: lsh daemon start`);
|
|
77
78
|
if (exitOnError) {
|
|
@@ -80,7 +81,7 @@ export async function withDaemonClient(operation, config = {}) {
|
|
|
80
81
|
}
|
|
81
82
|
throw enhancedError;
|
|
82
83
|
}
|
|
83
|
-
else if (
|
|
84
|
+
else if (err.message.includes('ECONNREFUSED')) {
|
|
84
85
|
const enhancedError = new Error(`❌ Daemon is not responding.\n` +
|
|
85
86
|
`The daemon may have crashed. Try restarting with: lsh daemon restart`);
|
|
86
87
|
if (exitOnError) {
|
|
@@ -91,7 +92,7 @@ export async function withDaemonClient(operation, config = {}) {
|
|
|
91
92
|
}
|
|
92
93
|
else {
|
|
93
94
|
if (exitOnError) {
|
|
94
|
-
console.error('❌ Error:',
|
|
95
|
+
console.error('❌ Error:', err.message);
|
|
95
96
|
process.exit(1);
|
|
96
97
|
}
|
|
97
98
|
throw error;
|
package/dist/lib/git-utils.js
CHANGED
|
@@ -144,7 +144,8 @@ export function isEnvIgnored(dir = process.cwd()) {
|
|
|
144
144
|
return false;
|
|
145
145
|
}
|
|
146
146
|
catch (error) {
|
|
147
|
-
|
|
147
|
+
const err = error;
|
|
148
|
+
logger.warn(`Failed to read .gitignore: ${err.message}`);
|
|
148
149
|
return false;
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -170,7 +171,8 @@ export function ensureEnvInGitignore(dir = process.cwd()) {
|
|
|
170
171
|
logger.info('✅ Added .env to .gitignore');
|
|
171
172
|
}
|
|
172
173
|
catch (error) {
|
|
173
|
-
|
|
174
|
+
const err = error;
|
|
175
|
+
logger.warn(`Failed to update .gitignore: ${err.message}`);
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
export default {
|
package/dist/lib/job-builtins.js
CHANGED
|
@@ -438,7 +438,9 @@ export class JobBuiltins {
|
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
// Helper methods for parsing options and formatting output
|
|
441
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
441
442
|
parseCreateOptions(args) {
|
|
443
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
442
444
|
const options = { tags: [] };
|
|
443
445
|
for (let i = 0; i < args.length; i++) {
|
|
444
446
|
const arg = args[i];
|
package/dist/lib/job-manager.js
CHANGED
|
@@ -136,9 +136,10 @@ export class JobManager extends BaseJobManager {
|
|
|
136
136
|
return updatedJob;
|
|
137
137
|
}
|
|
138
138
|
catch (error) {
|
|
139
|
+
const err = error;
|
|
139
140
|
await this.updateJobStatus(job.id, 'failed', {
|
|
140
141
|
completedAt: new Date(),
|
|
141
|
-
stderr:
|
|
142
|
+
stderr: err.message,
|
|
142
143
|
});
|
|
143
144
|
this.emit('jobFailed', job, error);
|
|
144
145
|
throw error;
|
|
@@ -169,6 +170,7 @@ export class JobManager extends BaseJobManager {
|
|
|
169
170
|
job.process.kill(signal);
|
|
170
171
|
}
|
|
171
172
|
catch (error) {
|
|
173
|
+
const err = error;
|
|
172
174
|
this.logger.error(`Failed to kill job ${jobId}`, error);
|
|
173
175
|
}
|
|
174
176
|
// Update status
|
|
@@ -291,6 +293,7 @@ export class JobManager extends BaseJobManager {
|
|
|
291
293
|
/**
|
|
292
294
|
* Get job statistics
|
|
293
295
|
*/
|
|
296
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
294
297
|
getJobStats() {
|
|
295
298
|
const jobs = Array.from(this.jobs.values());
|
|
296
299
|
const stats = {
|
package/dist/lib/lshrc-init.js
CHANGED
|
@@ -46,7 +46,8 @@ export class LshrcManager {
|
|
|
46
46
|
return true;
|
|
47
47
|
}
|
|
48
48
|
catch (error) {
|
|
49
|
-
|
|
49
|
+
const err = error;
|
|
50
|
+
console.error(`Failed to initialize .lshrc: ${err.message}`);
|
|
50
51
|
return false;
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -75,6 +76,7 @@ zsh-source${options.importOptions ? ' ' + options.importOptions.join(' ') : ''}
|
|
|
75
76
|
/**
|
|
76
77
|
* Source .lshrc commands
|
|
77
78
|
*/
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
80
|
async source(_executor) {
|
|
79
81
|
if (!this.exists()) {
|
|
80
82
|
return [];
|
|
@@ -93,7 +95,8 @@ zsh-source${options.importOptions ? ' ' + options.importOptions.join(' ') : ''}
|
|
|
93
95
|
return commands;
|
|
94
96
|
}
|
|
95
97
|
catch (error) {
|
|
96
|
-
|
|
98
|
+
const err = error;
|
|
99
|
+
console.error(`Failed to source .lshrc: ${err.message}`);
|
|
97
100
|
return [];
|
|
98
101
|
}
|
|
99
102
|
}
|
|
@@ -130,7 +133,8 @@ zsh-source${options.length > 0 ? ' ' + options.join(' ') : ''}
|
|
|
130
133
|
return true;
|
|
131
134
|
}
|
|
132
135
|
catch (error) {
|
|
133
|
-
|
|
136
|
+
const err = error;
|
|
137
|
+
console.error(`Failed to enable auto-import: ${err.message}`);
|
|
134
138
|
return false;
|
|
135
139
|
}
|
|
136
140
|
}
|
|
@@ -152,7 +156,8 @@ zsh-source${options.length > 0 ? ' ' + options.join(' ') : ''}
|
|
|
152
156
|
return true;
|
|
153
157
|
}
|
|
154
158
|
catch (error) {
|
|
155
|
-
|
|
159
|
+
const err = error;
|
|
160
|
+
console.error(`Failed to disable auto-import: ${err.message}`);
|
|
156
161
|
return false;
|
|
157
162
|
}
|
|
158
163
|
}
|
|
@@ -9,6 +9,7 @@ const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBh
|
|
|
9
9
|
// Database connection string (for direct PostgreSQL access if needed)
|
|
10
10
|
const DATABASE_URL = 'postgresql://postgres:[YOUR-PASSWORD]@db.uljsqvwkomdrlnofmlad.supabase.co:5432/postgres';
|
|
11
11
|
export class SupabaseClient {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
13
|
client;
|
|
13
14
|
config;
|
|
14
15
|
constructor(config) {
|
|
@@ -168,6 +168,7 @@ export class ZshCompatibility {
|
|
|
168
168
|
/**
|
|
169
169
|
* Apply parsed ZSH configuration to LSH
|
|
170
170
|
*/
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
171
172
|
async applyZshConfig(config) {
|
|
172
173
|
// Apply aliases
|
|
173
174
|
for (const alias of config.aliases) {
|
|
@@ -329,6 +330,7 @@ export class ZshCompatibility {
|
|
|
329
330
|
/**
|
|
330
331
|
* Generate completions based on patterns
|
|
331
332
|
*/
|
|
333
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
332
334
|
async generateCompletions(context, patterns) {
|
|
333
335
|
const completions = [];
|
|
334
336
|
for (const pattern of patterns) {
|
|
@@ -25,6 +25,7 @@ function getCurrentDirname() {
|
|
|
25
25
|
const currentDir = getCurrentDirname();
|
|
26
26
|
export class PipelineService {
|
|
27
27
|
app;
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
29
|
server;
|
|
29
30
|
io;
|
|
30
31
|
pool;
|
|
@@ -34,7 +35,9 @@ export class PipelineService {
|
|
|
34
35
|
config;
|
|
35
36
|
isDemoMode = false;
|
|
36
37
|
streamlitProcess = null;
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
39
|
getSystemJobs() {
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
41
|
const jobs = [];
|
|
39
42
|
const monitoringJobs = [
|
|
40
43
|
{ script: 'db-health-monitor', name: 'Database Health Monitor', type: 'monitoring', owner: 'ops-team', schedule: '*/5 * * * *' },
|
|
@@ -208,7 +208,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
catch (error) {
|
|
211
|
-
|
|
211
|
+
const err = error;
|
|
212
|
+
this.logError(` ${job.name} failed: ${err.message || err}`);
|
|
212
213
|
}
|
|
213
214
|
}
|
|
214
215
|
}, { forUser: true });
|
|
@@ -423,7 +424,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
|
|
|
423
424
|
syncCount++;
|
|
424
425
|
}
|
|
425
426
|
catch (error) {
|
|
426
|
-
|
|
427
|
+
const err = error;
|
|
428
|
+
this.logError(` Failed to sync ${job.name}: ${err.message}`);
|
|
427
429
|
}
|
|
428
430
|
}
|
|
429
431
|
return { syncCount, totalJobs: jobs.length };
|
|
@@ -494,7 +496,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
|
|
|
494
496
|
}
|
|
495
497
|
}
|
|
496
498
|
catch (error) {
|
|
497
|
-
|
|
499
|
+
const err = error;
|
|
500
|
+
this.logWarning(`Could not remove: ${socket} (${err.message})`);
|
|
498
501
|
}
|
|
499
502
|
}
|
|
500
503
|
}
|
|
@@ -521,7 +524,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
|
|
|
521
524
|
}
|
|
522
525
|
}
|
|
523
526
|
catch (error) {
|
|
524
|
-
|
|
527
|
+
const err = error;
|
|
528
|
+
this.logWarning(`Could not remove: ${pidFile} (${err.message})`);
|
|
525
529
|
}
|
|
526
530
|
}
|
|
527
531
|
}
|
|
@@ -573,7 +577,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
|
|
|
573
577
|
}
|
|
574
578
|
}
|
|
575
579
|
catch (error) {
|
|
576
|
-
|
|
580
|
+
const err = error;
|
|
581
|
+
throw new Error(`Cleanup failed: ${err.message}`);
|
|
577
582
|
}
|
|
578
583
|
}
|
|
579
584
|
}
|
|
@@ -220,9 +220,11 @@ API_KEY=
|
|
|
220
220
|
});
|
|
221
221
|
// Get a specific secret value
|
|
222
222
|
program
|
|
223
|
-
.command('get
|
|
224
|
-
.description('Get a specific secret value from .env file')
|
|
223
|
+
.command('get [key]')
|
|
224
|
+
.description('Get a specific secret value from .env file, or all secrets with --all')
|
|
225
225
|
.option('-f, --file <path>', 'Path to .env file', '.env')
|
|
226
|
+
.option('--all', 'Get all secrets from the file')
|
|
227
|
+
.option('--export', 'Output in export format for shell evaluation')
|
|
226
228
|
.action(async (key, options) => {
|
|
227
229
|
try {
|
|
228
230
|
const envPath = path.resolve(options.file);
|
|
@@ -232,6 +234,45 @@ API_KEY=
|
|
|
232
234
|
}
|
|
233
235
|
const content = fs.readFileSync(envPath, 'utf8');
|
|
234
236
|
const lines = content.split('\n');
|
|
237
|
+
// Handle --all flag
|
|
238
|
+
if (options.all) {
|
|
239
|
+
const secrets = [];
|
|
240
|
+
for (const line of lines) {
|
|
241
|
+
if (line.trim().startsWith('#') || !line.trim())
|
|
242
|
+
continue;
|
|
243
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
244
|
+
if (match) {
|
|
245
|
+
const key = match[1].trim();
|
|
246
|
+
let value = match[2].trim();
|
|
247
|
+
// Remove quotes if present
|
|
248
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
249
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
250
|
+
value = value.slice(1, -1);
|
|
251
|
+
}
|
|
252
|
+
secrets.push({ key, value });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (options.export) {
|
|
256
|
+
// Output in export format for shell evaluation
|
|
257
|
+
for (const { key, value } of secrets) {
|
|
258
|
+
// Escape single quotes in value and wrap in single quotes
|
|
259
|
+
const escapedValue = value.replace(/'/g, "'\\''");
|
|
260
|
+
console.log(`export ${key}='${escapedValue}'`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// Output in KEY=VALUE format
|
|
265
|
+
for (const { key, value } of secrets) {
|
|
266
|
+
console.log(`${key}=${value}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// Handle single key lookup
|
|
272
|
+
if (!key) {
|
|
273
|
+
console.error('❌ Please provide a key or use --all flag');
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
235
276
|
for (const line of lines) {
|
|
236
277
|
if (line.trim().startsWith('#') || !line.trim())
|
|
237
278
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
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": {
|