lsh-framework 0.8.2 → 0.9.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.
@@ -140,12 +140,14 @@ export class MCLIBridge extends EventEmitter {
140
140
  // Webhook handler for MCLI callbacks
141
141
  async handleWebhook(payload) {
142
142
  const { job_id, status, result, error, metrics, artifacts } = payload;
143
+ const jobIdStr = job_id;
143
144
  // Get pipeline job ID
144
- let pipelineJobId = this.jobMapping.get(job_id);
145
- if (!pipelineJobId && payload.metadata?.pipeline_job_id) {
146
- pipelineJobId = payload.metadata.pipeline_job_id;
145
+ let pipelineJobId = this.jobMapping.get(jobIdStr);
146
+ const metadata = payload.metadata;
147
+ if (!pipelineJobId && metadata?.pipeline_job_id) {
148
+ pipelineJobId = metadata.pipeline_job_id;
147
149
  if (pipelineJobId) {
148
- this.jobMapping.set(job_id, pipelineJobId);
150
+ this.jobMapping.set(jobIdStr, pipelineJobId);
149
151
  }
150
152
  }
151
153
  if (!pipelineJobId) {
@@ -169,7 +171,8 @@ export class MCLIBridge extends EventEmitter {
169
171
  break;
170
172
  case 'failed':
171
173
  case 'error':
172
- await this.jobTracker.failExecution(execution.id, error?.message || 'Job failed in MCLI', error);
174
+ const errorObj = error;
175
+ await this.jobTracker.failExecution(execution.id, errorObj?.message || 'Job failed in MCLI', error);
173
176
  break;
174
177
  case 'cancelled':
175
178
  await this.jobTracker.updateJobStatus(pipelineJobId, JobStatus.CANCELLED);
@@ -258,11 +261,13 @@ export class MCLIBridge extends EventEmitter {
258
261
  // Helper methods
259
262
  async updateJobExternalId(jobId, externalId) {
260
263
  // This would be implemented in JobTracker, but for now we'll use raw SQL
264
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
261
265
  const pool = this.jobTracker.pool;
262
266
  await pool.query('UPDATE pipeline_jobs SET external_id = $1 WHERE id = $2', [externalId, jobId]);
263
267
  }
264
268
  async getLatestExecution(jobId) {
265
269
  // This would be implemented in JobTracker
270
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
266
271
  const pool = this.jobTracker.pool;
267
272
  const result = await pool.query(`SELECT * FROM job_executions
268
273
  WHERE job_id = $1
@@ -271,6 +276,7 @@ export class MCLIBridge extends EventEmitter {
271
276
  if (result.rows.length === 0) {
272
277
  return null;
273
278
  }
279
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
274
280
  return this.jobTracker.parseExecutionRow(result.rows[0]);
275
281
  }
276
282
  // Health check
@@ -208,22 +208,23 @@ export class WorkflowEngine extends EventEmitter {
208
208
  }
209
209
  async executeJobNode(execution, node) {
210
210
  // Create job from node configuration
211
+ const config = node.config;
211
212
  const jobConfig = {
212
213
  name: `${execution.runId}-${node.name}`,
213
- type: node.config.type || 'workflow_job',
214
+ type: config.type || 'workflow_job',
214
215
  sourceSystem: 'workflow',
215
- targetSystem: node.config.targetSystem || 'mcli',
216
+ targetSystem: config.targetSystem || 'mcli',
216
217
  status: JobStatus.PENDING,
217
- priority: node.config.priority || JobPriority.NORMAL,
218
+ priority: config.priority || JobPriority.NORMAL,
218
219
  config: {
219
- ...node.config,
220
+ ...config,
220
221
  workflowExecutionId: execution.id,
221
222
  workflowNodeId: node.id,
222
223
  workflowRunId: execution.runId
223
224
  },
224
225
  parameters: {
225
226
  ...execution.parameters,
226
- ...node.config.parameters
227
+ ...(config.parameters || {})
227
228
  },
228
229
  owner: execution.triggeredBy,
229
230
  tags: [`workflow:${execution.workflowId}`, `run:${execution.runId}`]
@@ -262,7 +263,8 @@ export class WorkflowEngine extends EventEmitter {
262
263
  await this.checkAndContinueExecution(execution);
263
264
  }
264
265
  async executeWaitNode(execution, node) {
265
- const waitMs = node.config.waitMs || 1000;
266
+ const config = node.config;
267
+ const waitMs = config.waitMs || 1000;
266
268
  setTimeout(async () => {
267
269
  const nodeState = execution.nodeStates[node.id];
268
270
  nodeState.status = NodeStatus.COMPLETED;
@@ -300,7 +302,8 @@ export class WorkflowEngine extends EventEmitter {
300
302
  nodeState.durationMs = nodeState.completedAt.getTime() - nodeState.startedAt.getTime();
301
303
  }
302
304
  if (status === 'failed') {
303
- nodeState.error = data.errorMessage || 'Job failed';
305
+ const errorData = data;
306
+ nodeState.error = errorData.errorMessage || 'Job failed';
304
307
  // Check retry policy
305
308
  const workflow = await this.getWorkflow(targetExecution.workflowId);
306
309
  const node = workflow?.nodes.find(n => n.id === targetNodeId);
@@ -48,22 +48,23 @@ export class CronCommandRegistrar extends BaseCommandRegistrar {
48
48
  { flags: '-p, --priority <priority>', description: 'Priority (0-10)', defaultValue: '5' }
49
49
  ],
50
50
  action: async (templateId, options) => {
51
+ const opts = options;
51
52
  const result = await this.withCronManager(async (manager) => {
52
53
  const customizations = {};
53
- if (options.name)
54
- customizations.name = options.name;
55
- if (options.command)
56
- customizations.command = options.command;
57
- if (options.schedule)
58
- customizations.schedule = { cron: options.schedule };
59
- if (options.workingDir)
60
- customizations.workingDirectory = options.workingDir;
61
- if (options.env)
62
- customizations.environment = this.parseJSON(options.env, 'environment variables');
63
- if (options.tags)
64
- customizations.tags = this.parseTags(options.tags);
65
- if (options.priority)
66
- customizations.priority = parseInt(options.priority);
54
+ if (opts.name)
55
+ customizations.name = opts.name;
56
+ if (opts.command)
57
+ customizations.command = opts.command;
58
+ if (opts.schedule)
59
+ customizations.schedule = { cron: opts.schedule };
60
+ if (opts.workingDir)
61
+ customizations.workingDirectory = opts.workingDir;
62
+ if (opts.env)
63
+ customizations.environment = this.parseJSON(opts.env, 'environment variables');
64
+ if (opts.tags)
65
+ customizations.tags = this.parseTags(opts.tags);
66
+ if (opts.priority)
67
+ customizations.priority = parseInt(opts.priority);
67
68
  return await manager.createJobFromTemplate(templateId, customizations);
68
69
  });
69
70
  this.logSuccess('Job created from template:');
@@ -84,8 +85,9 @@ export class CronCommandRegistrar extends BaseCommandRegistrar {
84
85
  { flags: '-f, --filter <filter>', description: 'Filter by status' }
85
86
  ],
86
87
  action: async (options) => {
88
+ const opts = options;
87
89
  const jobs = await this.withCronManager(async (manager) => {
88
- return await manager.listJobs(options.filter ? { status: options.filter } : undefined);
90
+ return await manager.listJobs(opts.filter ? { status: opts.filter } : undefined);
89
91
  });
90
92
  this.logInfo(`Cron Jobs (${jobs.length} total):`);
91
93
  jobs.forEach(job => {
@@ -146,10 +148,11 @@ export class CronCommandRegistrar extends BaseCommandRegistrar {
146
148
  { flags: '-s, --signal <signal>', description: 'Signal to send', defaultValue: 'SIGTERM' }
147
149
  ],
148
150
  action: async (jobId, options) => {
151
+ const opts = options;
149
152
  await this.withCronManager(async (manager) => {
150
- await manager.stopJob(jobId, options.signal);
153
+ await manager.stopJob(jobId, opts.signal);
151
154
  });
152
- this.logSuccess(`Job ${jobId} stopped with signal ${options.signal}`);
155
+ this.logSuccess(`Job ${jobId} stopped with signal ${opts.signal}`);
153
156
  }
154
157
  });
155
158
  // Remove job
@@ -161,8 +164,9 @@ export class CronCommandRegistrar extends BaseCommandRegistrar {
161
164
  { flags: '-f, --force', description: 'Force removal', defaultValue: false }
162
165
  ],
163
166
  action: async (jobId, options) => {
167
+ const opts = options;
164
168
  await this.withCronManager(async (manager) => {
165
- await manager.removeJob(jobId, options.force);
169
+ await manager.removeJob(jobId, opts.force);
166
170
  });
167
171
  this.logSuccess(`Job ${jobId} removed`);
168
172
  }
@@ -218,13 +222,14 @@ export class CronCommandRegistrar extends BaseCommandRegistrar {
218
222
  { flags: '-o, --output <file>', description: 'Output file path' }
219
223
  ],
220
224
  action: async (options) => {
225
+ const opts = options;
221
226
  const data = await this.withCronManager(async (manager) => {
222
- return await manager.exportJobData(options.format);
227
+ return await manager.exportJobData(opts.format);
223
228
  });
224
- if (options.output) {
229
+ if (opts.output) {
225
230
  const fs = await import('fs');
226
- fs.writeFileSync(options.output, data);
227
- this.logSuccess(`Data exported to ${options.output}`);
231
+ fs.writeFileSync(opts.output, data);
232
+ this.logSuccess(`Data exported to ${opts.output}`);
228
233
  }
229
234
  else {
230
235
  this.logInfo(data);
@@ -29,8 +29,12 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
29
29
  this.logInfo('Daemon Status:');
30
30
  this.logInfo(` PID: ${status.pid}`);
31
31
  this.logInfo(` Uptime: ${Math.floor(status.uptime / 60)} minutes`);
32
- this.logInfo(` Memory: ${Math.round(status.memoryUsage.heapUsed / 1024 / 1024)} MB`);
33
- this.logInfo(` Jobs: ${status.jobs.total} total, ${status.jobs.running} running`);
32
+ if (status.memoryUsage) {
33
+ this.logInfo(` Memory: ${Math.round(status.memoryUsage.heapUsed / 1024 / 1024)} MB`);
34
+ }
35
+ if (status.jobs) {
36
+ this.logInfo(` Jobs: ${status.jobs.total} total, ${status.jobs.running} running`);
37
+ }
34
38
  }
35
39
  });
36
40
  // Start command
@@ -95,7 +99,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
95
99
  { flags: '-f, --force', description: 'Force cleanup without prompts', defaultValue: false }
96
100
  ],
97
101
  action: async (options) => {
98
- await this.cleanupDaemon(options.force);
102
+ const opts = options;
103
+ await this.cleanupDaemon(opts.force);
99
104
  }
100
105
  });
101
106
  }
@@ -122,11 +127,13 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
122
127
  { flags: '--no-database-sync', description: 'Disable database synchronization' }
123
128
  ],
124
129
  action: async (options) => {
125
- if (!options.name || !options.command || (!options.schedule && !options.interval)) {
130
+ const opts = options;
131
+ if (!opts.name || !opts.command || (!opts.schedule && !opts.interval)) {
126
132
  throw new Error('Missing required options: --name, --command, and (--schedule or --interval)');
127
133
  }
128
- const jobSpec = this.createJobSpec(options);
134
+ const jobSpec = this.createJobSpec(opts);
129
135
  await this.withDaemonAction(async (client) => {
136
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
130
137
  await client.createDatabaseCronJob(jobSpec);
131
138
  });
132
139
  this.logSuccess('Job created successfully:');
@@ -145,8 +152,9 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
145
152
  { flags: '-f, --filter <filter>', description: 'Filter jobs by status' }
146
153
  ],
147
154
  action: async (options) => {
155
+ const opts = options;
148
156
  const jobs = await this.withDaemonAction(async (client) => {
149
- return await client.listJobs(options.filter ? { status: options.filter } : undefined);
157
+ return await client.listJobs(opts.filter ? { status: opts.filter } : undefined);
150
158
  });
151
159
  this.displayJobs(jobs);
152
160
  }
@@ -185,8 +193,9 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
185
193
  { flags: '-f, --filter <status>', description: 'Filter by job status', defaultValue: 'created' }
186
194
  ],
187
195
  action: async (options) => {
196
+ const opts = options;
188
197
  await this.withDaemonAction(async (client) => {
189
- const jobs = await client.listJobs({ status: options.filter });
198
+ const jobs = await client.listJobs({ status: opts.filter });
190
199
  this.logInfo(`Triggering ${jobs.length} jobs...`);
191
200
  for (const job of jobs) {
192
201
  try {
@@ -215,10 +224,11 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
215
224
  { flags: '-s, --signal <signal>', description: 'Signal to send', defaultValue: 'SIGTERM' }
216
225
  ],
217
226
  action: async (jobId, options) => {
227
+ const opts = options;
218
228
  await this.withDaemonAction(async (client) => {
219
- await client.stopJob(jobId, options.signal);
229
+ await client.stopJob(jobId, opts.signal);
220
230
  });
221
- this.logSuccess(`Job ${jobId} stopped with signal ${options.signal}`);
231
+ this.logSuccess(`Job ${jobId} stopped with signal ${opts.signal}`);
222
232
  }
223
233
  });
224
234
  // Remove job
@@ -230,8 +240,9 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
230
240
  { flags: '-f, --force', description: 'Force removal', defaultValue: false }
231
241
  ],
232
242
  action: async (jobId, options) => {
243
+ const opts = options;
233
244
  await this.withDaemonAction(async (client) => {
234
- await client.removeJob(jobId, options.force);
245
+ await client.removeJob(jobId, opts.force);
235
246
  });
236
247
  this.logSuccess(`Job ${jobId} removed`);
237
248
  }
@@ -275,7 +286,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
275
286
  { flags: '-l, --limit <limit>', description: 'Limit number of results', defaultValue: '50' }
276
287
  ],
277
288
  action: async (options) => {
278
- const jobs = await this.withDaemonAction(async (client) => await client.getJobHistory(options.jobId, parseInt(options.limit)), { forUser: true, requireRunning: false });
289
+ const opts = options;
290
+ const jobs = await this.withDaemonAction(async (client) => await client.getJobHistory(opts.jobId, parseInt(opts.limit)), { forUser: true, requireRunning: false });
279
291
  this.logInfo(`Job History (${jobs.length} records):`);
280
292
  jobs.forEach(job => {
281
293
  const started = new Date(job.started_at).toLocaleString();
@@ -297,7 +309,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
297
309
  { flags: '-j, --job-id <jobId>', description: 'Filter by job ID' }
298
310
  ],
299
311
  action: async (options) => {
300
- const stats = await this.withDaemonAction(async (client) => await client.getJobStatistics(options.jobId), { forUser: true, requireRunning: false });
312
+ const opts = options;
313
+ const stats = await this.withDaemonAction(async (client) => await client.getJobStatistics(opts.jobId), { forUser: true, requireRunning: false });
301
314
  this.logInfo('Job Statistics:');
302
315
  this.logInfo(` Total Jobs: ${stats.totalJobs}`);
303
316
  this.logInfo(` Success Rate: ${stats.successRate.toFixed(1)}%`);
@@ -316,7 +329,8 @@ export class DaemonCommandRegistrar extends BaseCommandRegistrar {
316
329
  { flags: '-l, --limit <limit>', description: 'Number of recent executions to show', defaultValue: '5' }
317
330
  ],
318
331
  action: async (options) => {
319
- const jobs = await this.withDaemonAction(async (client) => await client.getJobHistory(undefined, parseInt(options.limit)), { forUser: true });
332
+ const opts = options;
333
+ const jobs = await this.withDaemonAction(async (client) => await client.getJobHistory(undefined, parseInt(opts.limit)), { forUser: true });
320
334
  this.logInfo(`Recent Job Executions (${jobs.length} records):`);
321
335
  jobs.forEach((job, index) => {
322
336
  const started = new Date(job.started_at).toLocaleString();
@@ -7,27 +7,26 @@ import * as fs from 'fs';
7
7
  import * as path from 'path';
8
8
  import * as readline from 'readline';
9
9
  export async function init_secrets(program) {
10
- const secretsCmd = program
11
- .command('secrets')
12
- .description('Manage environment secrets across machines');
13
10
  // Push secrets to cloud
14
- secretsCmd
11
+ program
15
12
  .command('push')
16
13
  .description('Push local .env to encrypted cloud storage')
17
14
  .option('-f, --file <path>', 'Path to .env file', '.env')
18
15
  .option('-e, --env <name>', 'Environment name (dev/staging/prod)', 'dev')
16
+ .option('--force', 'Force push even if destructive changes detected')
19
17
  .action(async (options) => {
20
18
  try {
21
19
  const manager = new SecretsManager();
22
- await manager.push(options.file, options.env);
20
+ await manager.push(options.file, options.env, options.force);
23
21
  }
24
22
  catch (error) {
25
- console.error('āŒ Failed to push secrets:', error.message);
23
+ const err = error;
24
+ console.error('āŒ Failed to push secrets:', err.message);
26
25
  process.exit(1);
27
26
  }
28
27
  });
29
28
  // Pull secrets from cloud
30
- secretsCmd
29
+ program
31
30
  .command('pull')
32
31
  .description('Pull .env from encrypted cloud storage')
33
32
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -39,12 +38,13 @@ export async function init_secrets(program) {
39
38
  await manager.pull(options.file, options.env, options.force);
40
39
  }
41
40
  catch (error) {
42
- console.error('āŒ Failed to pull secrets:', error.message);
41
+ const err = error;
42
+ console.error('āŒ Failed to pull secrets:', err.message);
43
43
  process.exit(1);
44
44
  }
45
45
  });
46
46
  // List environments
47
- secretsCmd
47
+ program
48
48
  .command('list [environment]')
49
49
  .alias('ls')
50
50
  .description('List all stored environments or show secrets for specific environment')
@@ -56,7 +56,7 @@ export async function init_secrets(program) {
56
56
  if (options.allFiles) {
57
57
  const files = await manager.listAllFiles();
58
58
  if (files.length === 0) {
59
- console.log('No .env files found. Push your first file with: lsh secrets push --file <filename>');
59
+ console.log('No .env files found. Push your first file with: lsh push --file <filename>');
60
60
  return;
61
61
  }
62
62
  console.log('\nšŸ“¦ Tracked .env files:\n');
@@ -74,7 +74,7 @@ export async function init_secrets(program) {
74
74
  // Otherwise, list all environments
75
75
  const envs = await manager.listEnvironments();
76
76
  if (envs.length === 0) {
77
- console.log('No environments found. Push your first .env with: lsh secrets push');
77
+ console.log('No environments found. Push your first .env with: lsh push');
78
78
  return;
79
79
  }
80
80
  console.log('\nšŸ“¦ Available environments:\n');
@@ -84,12 +84,13 @@ export async function init_secrets(program) {
84
84
  console.log();
85
85
  }
86
86
  catch (error) {
87
- console.error('āŒ Failed to list environments:', error.message);
87
+ const err = error;
88
+ console.error('āŒ Failed to list environments:', err.message);
88
89
  process.exit(1);
89
90
  }
90
91
  });
91
92
  // Show secrets (masked)
92
- secretsCmd
93
+ program
93
94
  .command('show')
94
95
  .description('Show secrets for an environment (masked)')
95
96
  .option('-e, --env <name>', 'Environment name', 'dev')
@@ -99,12 +100,13 @@ export async function init_secrets(program) {
99
100
  await manager.show(options.env);
100
101
  }
101
102
  catch (error) {
102
- console.error('āŒ Failed to show secrets:', error.message);
103
+ const err = error;
104
+ console.error('āŒ Failed to show secrets:', err.message);
103
105
  process.exit(1);
104
106
  }
105
107
  });
106
108
  // Generate encryption key
107
- secretsCmd
109
+ program
108
110
  .command('key')
109
111
  .description('Generate a new encryption key')
110
112
  .action(async () => {
@@ -116,7 +118,7 @@ export async function init_secrets(program) {
116
118
  console.log(' Never commit it to git!\n');
117
119
  });
118
120
  // Create .env file
119
- secretsCmd
121
+ program
120
122
  .command('create')
121
123
  .description('Create a new .env file')
122
124
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -165,12 +167,13 @@ API_KEY=
165
167
  console.log('');
166
168
  }
167
169
  catch (error) {
168
- console.error('āŒ Failed to create .env file:', error.message);
170
+ const err = error;
171
+ console.error('āŒ Failed to create .env file:', err.message);
169
172
  process.exit(1);
170
173
  }
171
174
  });
172
175
  // Sync command - automatically set up and synchronize secrets
173
- secretsCmd
176
+ program
174
177
  .command('sync')
175
178
  .description('Automatically set up and synchronize secrets (smart mode)')
176
179
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -178,6 +181,7 @@ API_KEY=
178
181
  .option('--dry-run', 'Show what would be done without executing')
179
182
  .option('--legacy', 'Use legacy sync mode (suggestions only)')
180
183
  .option('--load', 'Output eval-able export commands for loading secrets')
184
+ .option('--force', 'Force sync even if destructive changes detected')
181
185
  .action(async (options) => {
182
186
  try {
183
187
  const manager = new SecretsManager();
@@ -187,16 +191,17 @@ API_KEY=
187
191
  }
188
192
  else {
189
193
  // Use new smart sync (auto-execute)
190
- await manager.smartSync(options.file, options.env, !options.dryRun, options.load);
194
+ await manager.smartSync(options.file, options.env, !options.dryRun, options.load, options.force);
191
195
  }
192
196
  }
193
197
  catch (error) {
194
- console.error('āŒ Failed to sync:', error.message);
198
+ const err = error;
199
+ console.error('āŒ Failed to sync:', err.message);
195
200
  process.exit(1);
196
201
  }
197
202
  });
198
203
  // Status command - get detailed status info
199
- secretsCmd
204
+ program
200
205
  .command('status')
201
206
  .description('Get detailed secrets status (JSON output)')
202
207
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -208,12 +213,13 @@ API_KEY=
208
213
  console.log(JSON.stringify(status, null, 2));
209
214
  }
210
215
  catch (error) {
211
- console.error('āŒ Failed to get status:', error.message);
216
+ const err = error;
217
+ console.error('āŒ Failed to get status:', err.message);
212
218
  process.exit(1);
213
219
  }
214
220
  });
215
221
  // Get a specific secret value
216
- secretsCmd
222
+ program
217
223
  .command('get <key>')
218
224
  .description('Get a specific secret value from .env file')
219
225
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -245,12 +251,13 @@ API_KEY=
245
251
  process.exit(1);
246
252
  }
247
253
  catch (error) {
248
- console.error('āŒ Failed to get secret:', error.message);
254
+ const err = error;
255
+ console.error('āŒ Failed to get secret:', err.message);
249
256
  process.exit(1);
250
257
  }
251
258
  });
252
259
  // Set a specific secret value
253
- secretsCmd
260
+ program
254
261
  .command('set <key> <value>')
255
262
  .description('Set a specific secret value in .env file')
256
263
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -297,12 +304,13 @@ API_KEY=
297
304
  console.log(`āœ… Set ${key} in ${options.file}`);
298
305
  }
299
306
  catch (error) {
300
- console.error('āŒ Failed to set secret:', error.message);
307
+ const err = error;
308
+ console.error('āŒ Failed to set secret:', err.message);
301
309
  process.exit(1);
302
310
  }
303
311
  });
304
312
  // Delete .env file with confirmation
305
- secretsCmd
313
+ program
306
314
  .command('delete')
307
315
  .description('Delete .env file (requires confirmation)')
308
316
  .option('-f, --file <path>', 'Path to .env file', '.env')
@@ -351,7 +359,8 @@ API_KEY=
351
359
  console.log('');
352
360
  }
353
361
  catch (error) {
354
- console.error('āŒ Failed to delete .env file:', error.message);
362
+ const err = error;
363
+ console.error('āŒ Failed to delete .env file:', err.message);
355
364
  process.exit(1);
356
365
  }
357
366
  });