lsh-framework 1.2.0 → 1.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/README.md +40 -3
- package/dist/cli.js +104 -486
- package/dist/commands/doctor.js +427 -0
- package/dist/commands/init.js +371 -0
- package/dist/constants/api.js +94 -0
- package/dist/constants/commands.js +64 -0
- package/dist/constants/config.js +56 -0
- package/dist/constants/database.js +21 -0
- package/dist/constants/errors.js +79 -0
- package/dist/constants/index.js +28 -0
- package/dist/constants/paths.js +28 -0
- package/dist/constants/ui.js +73 -0
- package/dist/constants/validation.js +124 -0
- package/dist/daemon/lshd.js +11 -32
- package/dist/lib/daemon-client-helper.js +7 -4
- package/dist/lib/daemon-client.js +9 -2
- package/dist/lib/format-utils.js +163 -0
- package/dist/lib/fuzzy-match.js +123 -0
- package/dist/lib/job-manager.js +2 -1
- package/dist/lib/platform-utils.js +211 -0
- package/dist/lib/secrets-manager.js +11 -1
- package/dist/lib/string-utils.js +128 -0
- package/dist/services/daemon/daemon-registrar.js +3 -2
- package/dist/services/secrets/secrets.js +119 -59
- package/package.json +10 -74
- package/dist/app.js +0 -33
- package/dist/cicd/analytics.js +0 -261
- package/dist/cicd/auth.js +0 -269
- package/dist/cicd/cache-manager.js +0 -172
- package/dist/cicd/data-retention.js +0 -305
- package/dist/cicd/performance-monitor.js +0 -224
- package/dist/cicd/webhook-receiver.js +0 -640
- package/dist/commands/api.js +0 -346
- package/dist/commands/theme.js +0 -261
- package/dist/commands/zsh-import.js +0 -240
- package/dist/components/App.js +0 -1
- package/dist/components/Divider.js +0 -29
- package/dist/components/REPL.js +0 -43
- package/dist/components/Terminal.js +0 -232
- package/dist/components/UserInput.js +0 -30
- package/dist/daemon/api-server.js +0 -316
- package/dist/daemon/monitoring-api.js +0 -220
- package/dist/lib/api-error-handler.js +0 -185
- package/dist/lib/associative-arrays.js +0 -285
- package/dist/lib/base-api-server.js +0 -290
- package/dist/lib/brace-expansion.js +0 -160
- package/dist/lib/builtin-commands.js +0 -439
- package/dist/lib/executors/builtin-executor.js +0 -52
- package/dist/lib/extended-globbing.js +0 -411
- package/dist/lib/extended-parameter-expansion.js +0 -227
- package/dist/lib/interactive-shell.js +0 -460
- package/dist/lib/job-builtins.js +0 -582
- package/dist/lib/pathname-expansion.js +0 -216
- package/dist/lib/script-runner.js +0 -226
- package/dist/lib/shell-executor.js +0 -2504
- package/dist/lib/shell-parser.js +0 -958
- package/dist/lib/shell-types.js +0 -6
- package/dist/lib/shell.lib.js +0 -40
- package/dist/lib/theme-manager.js +0 -476
- package/dist/lib/variable-expansion.js +0 -385
- package/dist/lib/zsh-compatibility.js +0 -659
- package/dist/lib/zsh-import-manager.js +0 -707
- package/dist/lib/zsh-options.js +0 -328
- package/dist/pipeline/job-tracker.js +0 -491
- package/dist/pipeline/mcli-bridge.js +0 -309
- package/dist/pipeline/pipeline-service.js +0 -1119
- package/dist/pipeline/workflow-engine.js +0 -870
- package/dist/services/api/api.js +0 -58
- package/dist/services/api/auth.js +0 -35
- package/dist/services/api/config.js +0 -7
- package/dist/services/api/file.js +0 -22
- package/dist/services/shell/shell.js +0 -28
- package/dist/services/zapier.js +0 -16
- package/dist/simple-api-server.js +0 -148
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import axios from 'axios';
|
|
3
|
-
import { JobStatus } from './job-tracker.js';
|
|
4
|
-
export class MCLIBridge extends EventEmitter {
|
|
5
|
-
client;
|
|
6
|
-
jobTracker;
|
|
7
|
-
config;
|
|
8
|
-
jobMapping = new Map(); // MCLI ID -> Pipeline Job ID
|
|
9
|
-
constructor(config, jobTracker) {
|
|
10
|
-
super();
|
|
11
|
-
this.config = config;
|
|
12
|
-
this.jobTracker = jobTracker;
|
|
13
|
-
this.client = axios.create({
|
|
14
|
-
baseURL: config.baseUrl,
|
|
15
|
-
timeout: config.timeout || 30000,
|
|
16
|
-
headers: {
|
|
17
|
-
'Content-Type': 'application/json',
|
|
18
|
-
...(config.apiKey && { 'X-API-Key': config.apiKey })
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
this.setupJobTrackerListeners();
|
|
22
|
-
}
|
|
23
|
-
setupJobTrackerListeners() {
|
|
24
|
-
// Listen for job created events
|
|
25
|
-
this.jobTracker.on('job:created', async (event) => {
|
|
26
|
-
const job = event.data;
|
|
27
|
-
if (job.targetSystem === 'mcli') {
|
|
28
|
-
try {
|
|
29
|
-
await this.submitJobToMCLI(job);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
console.error(`Failed to submit job ${job.id} to MCLI:`, error);
|
|
33
|
-
await this.jobTracker.updateJobStatus(job.id, JobStatus.FAILED, `Failed to submit to MCLI: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
// Listen for job retry events
|
|
38
|
-
this.jobTracker.on('job:retry', async (event) => {
|
|
39
|
-
const job = await this.jobTracker.getJob(event.jobId);
|
|
40
|
-
if (job && job.targetSystem === 'mcli') {
|
|
41
|
-
try {
|
|
42
|
-
await this.submitJobToMCLI(job);
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
console.error(`Failed to retry job ${job.id} to MCLI:`, error);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
async submitJobToMCLI(job) {
|
|
51
|
-
const request = {
|
|
52
|
-
name: job.name,
|
|
53
|
-
type: job.type,
|
|
54
|
-
config: job.config,
|
|
55
|
-
parameters: job.parameters,
|
|
56
|
-
callback_url: this.config.webhookUrl ? `${this.config.webhookUrl}/webhook/mcli` : undefined,
|
|
57
|
-
metadata: {
|
|
58
|
-
pipeline_job_id: job.id,
|
|
59
|
-
source_system: job.sourceSystem,
|
|
60
|
-
owner: job.owner,
|
|
61
|
-
team: job.team,
|
|
62
|
-
tags: job.tags
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
try {
|
|
66
|
-
// Submit to MCLI
|
|
67
|
-
const response = await this.client.post('/api/jobs/submit', request);
|
|
68
|
-
// Store mapping
|
|
69
|
-
this.jobMapping.set(response.data.job_id, job.id);
|
|
70
|
-
// Update job with external ID
|
|
71
|
-
await this.updateJobExternalId(job.id, response.data.job_id);
|
|
72
|
-
// Update status to queued
|
|
73
|
-
await this.jobTracker.updateJobStatus(job.id, JobStatus.QUEUED);
|
|
74
|
-
// Get current execution
|
|
75
|
-
const executions = await this.getLatestExecution(job.id);
|
|
76
|
-
if (executions) {
|
|
77
|
-
await this.jobTracker.startExecution(executions.id, 'mcli', response.data.job_id);
|
|
78
|
-
}
|
|
79
|
-
// Emit submission event
|
|
80
|
-
this.emit('mcli:submitted', {
|
|
81
|
-
pipelineJobId: job.id,
|
|
82
|
-
mcliJobId: response.data.job_id,
|
|
83
|
-
timestamp: new Date()
|
|
84
|
-
});
|
|
85
|
-
return response.data;
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
if (axios.isAxiosError(error)) {
|
|
89
|
-
const errorMessage = error.response?.data?.error || error.message;
|
|
90
|
-
throw new Error(`MCLI submission failed: ${errorMessage}`);
|
|
91
|
-
}
|
|
92
|
-
throw error;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
async getJobStatus(mcliJobId) {
|
|
96
|
-
try {
|
|
97
|
-
const response = await this.client.get(`/api/jobs/${mcliJobId}`);
|
|
98
|
-
return response.data;
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
if (axios.isAxiosError(error)) {
|
|
102
|
-
throw new Error(`Failed to get MCLI job status: ${error.response?.data?.error || error.message}`);
|
|
103
|
-
}
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async cancelJob(mcliJobId) {
|
|
108
|
-
try {
|
|
109
|
-
await this.client.post(`/api/jobs/${mcliJobId}/cancel`);
|
|
110
|
-
// Update pipeline job status
|
|
111
|
-
const pipelineJobId = this.jobMapping.get(mcliJobId);
|
|
112
|
-
if (pipelineJobId) {
|
|
113
|
-
await this.jobTracker.updateJobStatus(pipelineJobId, JobStatus.CANCELLED);
|
|
114
|
-
}
|
|
115
|
-
this.emit('mcli:cancelled', {
|
|
116
|
-
mcliJobId,
|
|
117
|
-
pipelineJobId,
|
|
118
|
-
timestamp: new Date()
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
if (axios.isAxiosError(error)) {
|
|
123
|
-
throw new Error(`Failed to cancel MCLI job: ${error.response?.data?.error || error.message}`);
|
|
124
|
-
}
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
async getJobLogs(mcliJobId) {
|
|
129
|
-
try {
|
|
130
|
-
const response = await this.client.get(`/api/jobs/${mcliJobId}/logs`);
|
|
131
|
-
return response.data.logs;
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
if (axios.isAxiosError(error)) {
|
|
135
|
-
throw new Error(`Failed to get MCLI job logs: ${error.response?.data?.error || error.message}`);
|
|
136
|
-
}
|
|
137
|
-
throw error;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// Webhook handler for MCLI callbacks
|
|
141
|
-
async handleWebhook(payload) {
|
|
142
|
-
const { job_id, status, result, error, metrics, artifacts } = payload;
|
|
143
|
-
const jobIdStr = job_id;
|
|
144
|
-
// Get 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;
|
|
149
|
-
if (pipelineJobId) {
|
|
150
|
-
this.jobMapping.set(jobIdStr, pipelineJobId);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (!pipelineJobId) {
|
|
154
|
-
console.warn(`Received webhook for unknown MCLI job: ${job_id}`);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
// Get latest execution
|
|
158
|
-
const execution = await this.getLatestExecution(pipelineJobId);
|
|
159
|
-
if (!execution) {
|
|
160
|
-
console.warn(`No execution found for pipeline job: ${pipelineJobId}`);
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
// Update based on status
|
|
164
|
-
switch (status) {
|
|
165
|
-
case 'running':
|
|
166
|
-
await this.jobTracker.updateJobStatus(pipelineJobId, JobStatus.RUNNING);
|
|
167
|
-
break;
|
|
168
|
-
case 'completed':
|
|
169
|
-
case 'success':
|
|
170
|
-
await this.jobTracker.completeExecution(execution.id, result, metrics, artifacts);
|
|
171
|
-
break;
|
|
172
|
-
case 'failed':
|
|
173
|
-
case 'error': {
|
|
174
|
-
const errorObj = error;
|
|
175
|
-
await this.jobTracker.failExecution(execution.id, errorObj?.message || 'Job failed in MCLI', error);
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
case 'cancelled':
|
|
179
|
-
await this.jobTracker.updateJobStatus(pipelineJobId, JobStatus.CANCELLED);
|
|
180
|
-
break;
|
|
181
|
-
default:
|
|
182
|
-
console.warn(`Unknown MCLI job status: ${status}`);
|
|
183
|
-
}
|
|
184
|
-
// Record event
|
|
185
|
-
await this.jobTracker.recordEvent('mcli_webhook', 'mcli', payload, pipelineJobId, execution.id);
|
|
186
|
-
// Emit webhook event
|
|
187
|
-
this.emit('mcli:webhook', {
|
|
188
|
-
mcliJobId: job_id,
|
|
189
|
-
pipelineJobId,
|
|
190
|
-
status,
|
|
191
|
-
timestamp: new Date()
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
// Sync job status from MCLI
|
|
195
|
-
async syncJobStatus(mcliJobId) {
|
|
196
|
-
try {
|
|
197
|
-
const mcliJob = await this.getJobStatus(mcliJobId);
|
|
198
|
-
const pipelineJobId = this.jobMapping.get(mcliJobId);
|
|
199
|
-
if (!pipelineJobId) {
|
|
200
|
-
console.warn(`No pipeline job found for MCLI job: ${mcliJobId}`);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
// Map MCLI status to pipeline status
|
|
204
|
-
const statusMap = {
|
|
205
|
-
'pending': JobStatus.PENDING,
|
|
206
|
-
'queued': JobStatus.QUEUED,
|
|
207
|
-
'running': JobStatus.RUNNING,
|
|
208
|
-
'completed': JobStatus.COMPLETED,
|
|
209
|
-
'success': JobStatus.COMPLETED,
|
|
210
|
-
'failed': JobStatus.FAILED,
|
|
211
|
-
'error': JobStatus.FAILED,
|
|
212
|
-
'cancelled': JobStatus.CANCELLED
|
|
213
|
-
};
|
|
214
|
-
const pipelineStatus = statusMap[mcliJob.status] || JobStatus.PENDING;
|
|
215
|
-
await this.jobTracker.updateJobStatus(pipelineJobId, pipelineStatus);
|
|
216
|
-
// If completed or failed, update execution
|
|
217
|
-
if (mcliJob.status === 'completed' || mcliJob.status === 'success') {
|
|
218
|
-
const execution = await this.getLatestExecution(pipelineJobId);
|
|
219
|
-
if (execution) {
|
|
220
|
-
await this.jobTracker.completeExecution(execution.id, mcliJob.result, undefined, undefined);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
else if (mcliJob.status === 'failed' || mcliJob.status === 'error') {
|
|
224
|
-
const execution = await this.getLatestExecution(pipelineJobId);
|
|
225
|
-
if (execution) {
|
|
226
|
-
await this.jobTracker.failExecution(execution.id, mcliJob.error || 'Job failed in MCLI', undefined);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
this.emit('mcli:synced', {
|
|
230
|
-
mcliJobId,
|
|
231
|
-
pipelineJobId,
|
|
232
|
-
status: pipelineStatus,
|
|
233
|
-
timestamp: new Date()
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
catch (error) {
|
|
237
|
-
console.error(`Failed to sync MCLI job status for ${mcliJobId}:`, error);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
// Batch sync multiple jobs
|
|
241
|
-
async syncAllActiveJobs() {
|
|
242
|
-
const activeJobs = await this.jobTracker.getActiveJobs();
|
|
243
|
-
for (const job of activeJobs) {
|
|
244
|
-
if (job.targetSystem === 'mcli' && job.externalId) {
|
|
245
|
-
await this.syncJobStatus(job.externalId);
|
|
246
|
-
// Add delay to avoid overwhelming MCLI API
|
|
247
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// Start periodic sync
|
|
252
|
-
startPeriodicSync(intervalMs = 30000) {
|
|
253
|
-
return setInterval(async () => {
|
|
254
|
-
try {
|
|
255
|
-
await this.syncAllActiveJobs();
|
|
256
|
-
}
|
|
257
|
-
catch (error) {
|
|
258
|
-
console.error('Periodic sync error:', error);
|
|
259
|
-
}
|
|
260
|
-
}, intervalMs);
|
|
261
|
-
}
|
|
262
|
-
// Helper methods
|
|
263
|
-
async updateJobExternalId(jobId, externalId) {
|
|
264
|
-
// This would be implemented in JobTracker, but for now we'll use raw SQL
|
|
265
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
266
|
-
const pool = this.jobTracker.pool;
|
|
267
|
-
await pool.query('UPDATE pipeline_jobs SET external_id = $1 WHERE id = $2', [externalId, jobId]);
|
|
268
|
-
}
|
|
269
|
-
async getLatestExecution(jobId) {
|
|
270
|
-
// This would be implemented in JobTracker
|
|
271
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
272
|
-
const pool = this.jobTracker.pool;
|
|
273
|
-
const result = await pool.query(`SELECT * FROM job_executions
|
|
274
|
-
WHERE job_id = $1
|
|
275
|
-
ORDER BY execution_number DESC
|
|
276
|
-
LIMIT 1`, [jobId]);
|
|
277
|
-
if (result.rows.length === 0) {
|
|
278
|
-
return null;
|
|
279
|
-
}
|
|
280
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
281
|
-
return this.jobTracker.parseExecutionRow(result.rows[0]);
|
|
282
|
-
}
|
|
283
|
-
// Health check
|
|
284
|
-
async healthCheck() {
|
|
285
|
-
try {
|
|
286
|
-
const response = await this.client.get('/health');
|
|
287
|
-
return response.status === 200;
|
|
288
|
-
}
|
|
289
|
-
catch (_error) {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
// Get MCLI statistics
|
|
294
|
-
async getStatistics() {
|
|
295
|
-
try {
|
|
296
|
-
const response = await this.client.get('/api/statistics');
|
|
297
|
-
return response.data;
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
console.error('Failed to get MCLI statistics:', error);
|
|
301
|
-
return null;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// Cleanup
|
|
305
|
-
cleanup() {
|
|
306
|
-
this.removeAllListeners();
|
|
307
|
-
this.jobMapping.clear();
|
|
308
|
-
}
|
|
309
|
-
}
|