@burdenoff/vibe-agent 1.0.1 → 1.0.2
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 +14 -14
- package/dist/app.d.ts +4 -4
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +144 -130
- package/dist/app.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +342 -332
- package/dist/cli.js.map +1 -1
- package/dist/db/schema.d.ts +15 -15
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +65 -62
- package/dist/db/schema.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/middleware/ModuleAuth.d.ts +2 -2
- package/dist/middleware/ModuleAuth.d.ts.map +1 -1
- package/dist/middleware/ModuleAuth.js +32 -29
- package/dist/middleware/ModuleAuth.js.map +1 -1
- package/dist/middleware/auth.d.ts +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +4 -4
- package/dist/middleware/auth.js.map +1 -1
- package/dist/migrations/remove-notes-prompts.d.ts.map +1 -1
- package/dist/migrations/remove-notes-prompts.js +26 -26
- package/dist/migrations/remove-notes-prompts.js.map +1 -1
- package/dist/routes/bookmarks.d.ts +1 -1
- package/dist/routes/bookmarks.d.ts.map +1 -1
- package/dist/routes/bookmarks.js +53 -44
- package/dist/routes/bookmarks.js.map +1 -1
- package/dist/routes/config.d.ts +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +29 -27
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/files.d.ts +1 -1
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +175 -134
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/git.d.ts +1 -1
- package/dist/routes/git.d.ts.map +1 -1
- package/dist/routes/git.js +183 -169
- package/dist/routes/git.js.map +1 -1
- package/dist/routes/moduleRegistry.d.ts +3 -3
- package/dist/routes/moduleRegistry.d.ts.map +1 -1
- package/dist/routes/moduleRegistry.js +58 -58
- package/dist/routes/moduleRegistry.js.map +1 -1
- package/dist/routes/notifications.d.ts +1 -1
- package/dist/routes/notifications.d.ts.map +1 -1
- package/dist/routes/notifications.js +69 -64
- package/dist/routes/notifications.js.map +1 -1
- package/dist/routes/port-forward.d.ts +1 -1
- package/dist/routes/port-forward.d.ts.map +1 -1
- package/dist/routes/port-forward.js +59 -50
- package/dist/routes/port-forward.js.map +1 -1
- package/dist/routes/projects.d.ts +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +134 -120
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/ssh.d.ts +1 -1
- package/dist/routes/ssh.d.ts.map +1 -1
- package/dist/routes/ssh.js +47 -47
- package/dist/routes/ssh.js.map +1 -1
- package/dist/routes/tasks.d.ts +1 -1
- package/dist/routes/tasks.d.ts.map +1 -1
- package/dist/routes/tasks.js +53 -49
- package/dist/routes/tasks.js.map +1 -1
- package/dist/routes/tmux.d.ts +1 -1
- package/dist/routes/tmux.d.ts.map +1 -1
- package/dist/routes/tmux.js +337 -241
- package/dist/routes/tmux.js.map +1 -1
- package/dist/routes/tunnel.d.ts +2 -2
- package/dist/routes/tunnel.d.ts.map +1 -1
- package/dist/routes/tunnel.js +115 -74
- package/dist/routes/tunnel.js.map +1 -1
- package/dist/services/ModulePermissions.d.ts +2 -2
- package/dist/services/ModulePermissions.d.ts.map +1 -1
- package/dist/services/ModulePermissions.js +50 -40
- package/dist/services/ModulePermissions.js.map +1 -1
- package/dist/services/ModuleRegistryService.d.ts +10 -10
- package/dist/services/ModuleRegistryService.d.ts.map +1 -1
- package/dist/services/ModuleRegistryService.js +156 -131
- package/dist/services/ModuleRegistryService.js.map +1 -1
- package/dist/services/agent.service.d.ts.map +1 -1
- package/dist/services/agent.service.js +24 -21
- package/dist/services/agent.service.js.map +1 -1
- package/dist/services/bootstrap.d.ts +1 -1
- package/dist/services/bootstrap.d.ts.map +1 -1
- package/dist/services/bootstrap.js +146 -69
- package/dist/services/bootstrap.js.map +1 -1
- package/dist/services/service-manager.d.ts +2 -2
- package/dist/services/service-manager.d.ts.map +1 -1
- package/dist/services/service-manager.js +75 -63
- package/dist/services/service-manager.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
2
|
-
import { spawn } from
|
|
3
|
-
import { promises as fs } from
|
|
4
|
-
import path from
|
|
5
|
-
import { fileURLToPath } from
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
export class ModuleRegistryService extends EventEmitter {
|
|
8
8
|
activeModules = new Map();
|
|
@@ -20,7 +20,7 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
20
20
|
try {
|
|
21
21
|
// Validate module manifest
|
|
22
22
|
if (!this.validateModule(moduleData)) {
|
|
23
|
-
return { success: false, message:
|
|
23
|
+
return { success: false, message: "Invalid module manifest" };
|
|
24
24
|
}
|
|
25
25
|
// Check for port conflicts
|
|
26
26
|
const portConflict = this.checkPortConflicts(moduleData);
|
|
@@ -32,28 +32,31 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
32
32
|
...moduleData,
|
|
33
33
|
registeredAt: new Date(),
|
|
34
34
|
lastHeartbeat: new Date(),
|
|
35
|
-
status:
|
|
35
|
+
status: "running",
|
|
36
36
|
};
|
|
37
37
|
// Store module
|
|
38
38
|
this.activeModules.set(registeredModule.name, registeredModule);
|
|
39
39
|
// Start health monitoring
|
|
40
40
|
this.startHealthMonitoring(registeredModule.name);
|
|
41
41
|
// Log activity
|
|
42
|
-
this.logActivity(
|
|
42
|
+
this.logActivity("register", registeredModule.name);
|
|
43
43
|
// Emit event
|
|
44
|
-
this.emit(
|
|
44
|
+
this.emit("module:registered", registeredModule);
|
|
45
45
|
console.log(`Module ${registeredModule.name} registered successfully`);
|
|
46
|
-
return { success: true, message:
|
|
46
|
+
return { success: true, message: "Module registered successfully" };
|
|
47
47
|
}
|
|
48
48
|
catch (error) {
|
|
49
|
-
console.error(
|
|
50
|
-
return {
|
|
49
|
+
console.error("Module registration failed:", error);
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
53
|
+
};
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
async unregisterModule(moduleId) {
|
|
54
57
|
const module = this.activeModules.get(moduleId);
|
|
55
58
|
if (!module) {
|
|
56
|
-
return { success: false, message:
|
|
59
|
+
return { success: false, message: "Module not found" };
|
|
57
60
|
}
|
|
58
61
|
try {
|
|
59
62
|
// Stop health monitoring
|
|
@@ -63,80 +66,89 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
63
66
|
// Remove from active modules
|
|
64
67
|
this.activeModules.delete(moduleId);
|
|
65
68
|
// Log activity
|
|
66
|
-
this.logActivity(
|
|
69
|
+
this.logActivity("unregister", moduleId);
|
|
67
70
|
// Emit event
|
|
68
|
-
this.emit(
|
|
71
|
+
this.emit("module:unregistered", module);
|
|
69
72
|
console.log(`Module ${moduleId} unregistered successfully`);
|
|
70
|
-
return { success: true, message:
|
|
73
|
+
return { success: true, message: "Module unregistered successfully" };
|
|
71
74
|
}
|
|
72
75
|
catch (error) {
|
|
73
|
-
console.error(
|
|
74
|
-
return {
|
|
76
|
+
console.error("Module unregistration failed:", error);
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
80
|
+
};
|
|
75
81
|
}
|
|
76
82
|
}
|
|
77
83
|
// Module lifecycle methods
|
|
78
84
|
async activateModule(moduleId) {
|
|
79
85
|
const module = this.activeModules.get(moduleId);
|
|
80
86
|
if (!module) {
|
|
81
|
-
return { success: false, message:
|
|
87
|
+
return { success: false, message: "Module not found" };
|
|
82
88
|
}
|
|
83
|
-
if (module.status ===
|
|
84
|
-
return { success: false, message:
|
|
89
|
+
if (module.status === "running") {
|
|
90
|
+
return { success: false, message: "Module is already active" };
|
|
85
91
|
}
|
|
86
92
|
try {
|
|
87
93
|
// Update status
|
|
88
|
-
module.status =
|
|
94
|
+
module.status = "starting";
|
|
89
95
|
this.activeModules.set(moduleId, module);
|
|
90
96
|
// Start module processes
|
|
91
97
|
await this.startModuleProcesses(module);
|
|
92
98
|
// Update status
|
|
93
|
-
module.status =
|
|
99
|
+
module.status = "running";
|
|
94
100
|
this.activeModules.set(moduleId, module);
|
|
95
101
|
// Start health monitoring
|
|
96
102
|
this.startHealthMonitoring(moduleId);
|
|
97
103
|
// Log activity
|
|
98
|
-
this.logActivity(
|
|
104
|
+
this.logActivity("activate", moduleId);
|
|
99
105
|
// Emit event
|
|
100
|
-
this.emit(
|
|
101
|
-
return { success: true, message:
|
|
106
|
+
this.emit("module:activated", module);
|
|
107
|
+
return { success: true, message: "Module activated successfully" };
|
|
102
108
|
}
|
|
103
109
|
catch (error) {
|
|
104
|
-
module.status =
|
|
110
|
+
module.status = "error";
|
|
105
111
|
this.activeModules.set(moduleId, module);
|
|
106
|
-
console.error(
|
|
107
|
-
return {
|
|
112
|
+
console.error("Module activation failed:", error);
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
116
|
+
};
|
|
108
117
|
}
|
|
109
118
|
}
|
|
110
119
|
async deactivateModule(moduleId) {
|
|
111
120
|
const module = this.activeModules.get(moduleId);
|
|
112
121
|
if (!module) {
|
|
113
|
-
return { success: false, message:
|
|
122
|
+
return { success: false, message: "Module not found" };
|
|
114
123
|
}
|
|
115
|
-
if (module.status ===
|
|
116
|
-
return { success: false, message:
|
|
124
|
+
if (module.status === "stopped") {
|
|
125
|
+
return { success: false, message: "Module is already inactive" };
|
|
117
126
|
}
|
|
118
127
|
try {
|
|
119
128
|
// Update status
|
|
120
|
-
module.status =
|
|
129
|
+
module.status = "stopping";
|
|
121
130
|
this.activeModules.set(moduleId, module);
|
|
122
131
|
// Stop health monitoring
|
|
123
132
|
this.stopHealthMonitoring(moduleId);
|
|
124
133
|
// Stop module processes
|
|
125
134
|
await this.stopModuleProcesses(moduleId);
|
|
126
135
|
// Update status
|
|
127
|
-
module.status =
|
|
136
|
+
module.status = "stopped";
|
|
128
137
|
this.activeModules.set(moduleId, module);
|
|
129
138
|
// Log activity
|
|
130
|
-
this.logActivity(
|
|
139
|
+
this.logActivity("deactivate", moduleId);
|
|
131
140
|
// Emit event
|
|
132
|
-
this.emit(
|
|
133
|
-
return { success: true, message:
|
|
141
|
+
this.emit("module:deactivated", module);
|
|
142
|
+
return { success: true, message: "Module deactivated successfully" };
|
|
134
143
|
}
|
|
135
144
|
catch (error) {
|
|
136
|
-
module.status =
|
|
145
|
+
module.status = "error";
|
|
137
146
|
this.activeModules.set(moduleId, module);
|
|
138
|
-
console.error(
|
|
139
|
-
return {
|
|
147
|
+
console.error("Module deactivation failed:", error);
|
|
148
|
+
return {
|
|
149
|
+
success: false,
|
|
150
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
151
|
+
};
|
|
140
152
|
}
|
|
141
153
|
}
|
|
142
154
|
// Module installation methods
|
|
@@ -145,46 +157,47 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
145
157
|
const installation = {
|
|
146
158
|
id: installationId,
|
|
147
159
|
moduleId,
|
|
148
|
-
version: version ||
|
|
160
|
+
version: version || "latest",
|
|
149
161
|
source,
|
|
150
162
|
installedAt: new Date(),
|
|
151
|
-
status:
|
|
163
|
+
status: "pending",
|
|
152
164
|
progress: 0,
|
|
153
|
-
logs: []
|
|
165
|
+
logs: [],
|
|
154
166
|
};
|
|
155
167
|
this.installHistory.set(installationId, installation);
|
|
156
168
|
try {
|
|
157
169
|
// Update status
|
|
158
|
-
installation.status =
|
|
170
|
+
installation.status = "downloading";
|
|
159
171
|
installation.progress = 10;
|
|
160
172
|
this.installHistory.set(installationId, installation);
|
|
161
173
|
// Download and install module based on source type
|
|
162
174
|
switch (source.type) {
|
|
163
|
-
case
|
|
175
|
+
case "remote":
|
|
164
176
|
await this.installFromRemote(installation);
|
|
165
177
|
break;
|
|
166
|
-
case
|
|
178
|
+
case "marketplace":
|
|
167
179
|
await this.installFromMarketplace(installation);
|
|
168
180
|
break;
|
|
169
|
-
case
|
|
181
|
+
case "container":
|
|
170
182
|
await this.installFromContainer(installation);
|
|
171
183
|
break;
|
|
172
184
|
default:
|
|
173
185
|
throw new Error(`Unsupported source type: ${source.type}`);
|
|
174
186
|
}
|
|
175
|
-
installation.status =
|
|
187
|
+
installation.status = "installed";
|
|
176
188
|
installation.progress = 100;
|
|
177
189
|
this.installHistory.set(installationId, installation);
|
|
178
190
|
// Log activity
|
|
179
|
-
this.logActivity(
|
|
191
|
+
this.logActivity("install", moduleId);
|
|
180
192
|
// Emit event
|
|
181
|
-
this.emit(
|
|
193
|
+
this.emit("module:installed", installation);
|
|
182
194
|
console.log(`Module ${moduleId} installed successfully`);
|
|
183
195
|
}
|
|
184
196
|
catch (error) {
|
|
185
|
-
installation.status =
|
|
186
|
-
installation.error =
|
|
187
|
-
|
|
197
|
+
installation.status = "failed";
|
|
198
|
+
installation.error =
|
|
199
|
+
error instanceof Error ? error.message : "Unknown error";
|
|
200
|
+
installation.logs?.push(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
188
201
|
this.installHistory.set(installationId, installation);
|
|
189
202
|
console.error(`Module installation failed:`, error);
|
|
190
203
|
}
|
|
@@ -197,32 +210,32 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
197
210
|
async getModule(moduleId) {
|
|
198
211
|
return this.activeModules.get(moduleId) || null;
|
|
199
212
|
}
|
|
200
|
-
async searchModules(query, category, tags, status =
|
|
213
|
+
async searchModules(query, category, tags, status = "all", limit = 50, offset = 0) {
|
|
201
214
|
let modules = Array.from(this.activeModules.values());
|
|
202
215
|
// Filter by status
|
|
203
|
-
if (status !==
|
|
204
|
-
modules = modules.filter(module => {
|
|
205
|
-
if (status ===
|
|
206
|
-
return module.status ===
|
|
207
|
-
if (status ===
|
|
208
|
-
return module.status !==
|
|
216
|
+
if (status !== "all") {
|
|
217
|
+
modules = modules.filter((module) => {
|
|
218
|
+
if (status === "active")
|
|
219
|
+
return module.status === "running";
|
|
220
|
+
if (status === "inactive")
|
|
221
|
+
return module.status !== "running";
|
|
209
222
|
return true;
|
|
210
223
|
});
|
|
211
224
|
}
|
|
212
225
|
// Filter by search query
|
|
213
226
|
if (query) {
|
|
214
227
|
const searchTerm = query.toLowerCase();
|
|
215
|
-
modules = modules.filter(module => module.name.toLowerCase().includes(searchTerm) ||
|
|
228
|
+
modules = modules.filter((module) => module.name.toLowerCase().includes(searchTerm) ||
|
|
216
229
|
module.displayName.toLowerCase().includes(searchTerm) ||
|
|
217
230
|
module.description.toLowerCase().includes(searchTerm));
|
|
218
231
|
}
|
|
219
232
|
// Filter by category
|
|
220
233
|
if (category) {
|
|
221
|
-
modules = modules.filter(module => module.category === category);
|
|
234
|
+
modules = modules.filter((module) => module.category === category);
|
|
222
235
|
}
|
|
223
236
|
// Filter by tags
|
|
224
237
|
if (tags && tags.length > 0) {
|
|
225
|
-
modules = modules.filter(module => tags.some(tag => module.tags.includes(tag)));
|
|
238
|
+
modules = modules.filter((module) => tags.some((tag) => module.tags.includes(tag)));
|
|
226
239
|
}
|
|
227
240
|
// Apply pagination
|
|
228
241
|
return modules.slice(offset, offset + limit);
|
|
@@ -230,40 +243,44 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
230
243
|
async getStats() {
|
|
231
244
|
const modules = Array.from(this.activeModules.values());
|
|
232
245
|
const categoryCounts = {};
|
|
233
|
-
modules.forEach(module => {
|
|
234
|
-
categoryCounts[module.category] =
|
|
246
|
+
modules.forEach((module) => {
|
|
247
|
+
categoryCounts[module.category] =
|
|
248
|
+
(categoryCounts[module.category] || 0) + 1;
|
|
235
249
|
});
|
|
236
250
|
return {
|
|
237
251
|
totalModules: modules.length,
|
|
238
|
-
activeModules: modules.filter(m => m.status ===
|
|
239
|
-
stoppedModules: modules.filter(m => m.status ===
|
|
240
|
-
errorModules: modules.filter(m => m.status ===
|
|
252
|
+
activeModules: modules.filter((m) => m.status === "running").length,
|
|
253
|
+
stoppedModules: modules.filter((m) => m.status === "stopped").length,
|
|
254
|
+
errorModules: modules.filter((m) => m.status === "error").length,
|
|
241
255
|
totalInstallations: this.installHistory.size,
|
|
242
256
|
categoryCounts,
|
|
243
|
-
recentActivity: this.recentActivity.slice(-10)
|
|
257
|
+
recentActivity: this.recentActivity.slice(-10),
|
|
244
258
|
};
|
|
245
259
|
}
|
|
246
260
|
// Health and monitoring methods
|
|
247
261
|
async updateHeartbeat(moduleId, heartbeatData) {
|
|
248
262
|
const module = this.activeModules.get(moduleId);
|
|
249
263
|
if (!module) {
|
|
250
|
-
return { success: false, message:
|
|
264
|
+
return { success: false, message: "Module not found" };
|
|
251
265
|
}
|
|
252
266
|
try {
|
|
253
267
|
module.lastHeartbeat = new Date();
|
|
254
268
|
module.metrics = heartbeatData.metrics;
|
|
255
|
-
if (heartbeatData.status ===
|
|
256
|
-
module.status =
|
|
269
|
+
if (heartbeatData.status === "healthy") {
|
|
270
|
+
module.status = "running";
|
|
257
271
|
}
|
|
258
|
-
else if (heartbeatData.status ===
|
|
259
|
-
module.status =
|
|
272
|
+
else if (heartbeatData.status === "unhealthy") {
|
|
273
|
+
module.status = "error";
|
|
260
274
|
}
|
|
261
275
|
this.activeModules.set(moduleId, module);
|
|
262
|
-
return { success: true, message:
|
|
276
|
+
return { success: true, message: "Heartbeat updated" };
|
|
263
277
|
}
|
|
264
278
|
catch (error) {
|
|
265
|
-
console.error(
|
|
266
|
-
return {
|
|
279
|
+
console.error("Failed to update heartbeat:", error);
|
|
280
|
+
return {
|
|
281
|
+
success: false,
|
|
282
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
283
|
+
};
|
|
267
284
|
}
|
|
268
285
|
}
|
|
269
286
|
async checkModuleHealth(moduleId) {
|
|
@@ -273,7 +290,7 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
273
290
|
}
|
|
274
291
|
try {
|
|
275
292
|
const response = await fetch(`http://localhost:${module.api.backend.port}/health`, {
|
|
276
|
-
signal: AbortSignal.timeout(5000)
|
|
293
|
+
signal: AbortSignal.timeout(5000),
|
|
277
294
|
});
|
|
278
295
|
const health = {
|
|
279
296
|
healthy: response.ok,
|
|
@@ -283,8 +300,8 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
283
300
|
details: response.ok ? await response.json() : null,
|
|
284
301
|
checks: {
|
|
285
302
|
http: response.ok,
|
|
286
|
-
status: response.status
|
|
287
|
-
}
|
|
303
|
+
status: response.status,
|
|
304
|
+
},
|
|
288
305
|
};
|
|
289
306
|
module.health = health;
|
|
290
307
|
this.activeModules.set(moduleId, module);
|
|
@@ -293,12 +310,12 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
293
310
|
catch (error) {
|
|
294
311
|
const health = {
|
|
295
312
|
healthy: false,
|
|
296
|
-
error: error instanceof Error ? error.message :
|
|
313
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
297
314
|
timestamp: new Date(),
|
|
298
315
|
checks: {
|
|
299
316
|
http: false,
|
|
300
|
-
error: error instanceof Error ? error.message :
|
|
301
|
-
}
|
|
317
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
318
|
+
},
|
|
302
319
|
};
|
|
303
320
|
module.health = health;
|
|
304
321
|
this.activeModules.set(moduleId, module);
|
|
@@ -307,8 +324,8 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
307
324
|
}
|
|
308
325
|
// Utility methods
|
|
309
326
|
validateModule(module) {
|
|
310
|
-
const requiredFields = [
|
|
311
|
-
return requiredFields.every(field => module[field] !== undefined);
|
|
327
|
+
const requiredFields = ["name", "version", "api"];
|
|
328
|
+
return requiredFields.every((field) => module[field] !== undefined);
|
|
312
329
|
}
|
|
313
330
|
checkPortConflicts(module) {
|
|
314
331
|
for (const [_, existingModule] of this.activeModules) {
|
|
@@ -337,29 +354,29 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
337
354
|
}
|
|
338
355
|
}
|
|
339
356
|
async startModuleProcesses(module) {
|
|
340
|
-
const modulePath = path.join(process.cwd(),
|
|
357
|
+
const modulePath = path.join(process.cwd(), "installed_modules", module.name);
|
|
341
358
|
try {
|
|
342
359
|
// Start backend process
|
|
343
|
-
const backendProcess = spawn(
|
|
344
|
-
cwd: path.join(modulePath,
|
|
345
|
-
stdio:
|
|
346
|
-
env: { ...process.env, NODE_ENV:
|
|
360
|
+
const backendProcess = spawn("npm", ["run", "start"], {
|
|
361
|
+
cwd: path.join(modulePath, "src", "backend"),
|
|
362
|
+
stdio: "pipe",
|
|
363
|
+
env: { ...process.env, NODE_ENV: "production" },
|
|
347
364
|
});
|
|
348
365
|
// Start frontend process
|
|
349
|
-
const frontendProcess = spawn(
|
|
350
|
-
cwd: path.join(modulePath,
|
|
351
|
-
stdio:
|
|
352
|
-
env: { ...process.env, NODE_ENV:
|
|
366
|
+
const frontendProcess = spawn("npm", ["run", "start"], {
|
|
367
|
+
cwd: path.join(modulePath, "src", "frontend"),
|
|
368
|
+
stdio: "pipe",
|
|
369
|
+
env: { ...process.env, NODE_ENV: "production" },
|
|
353
370
|
});
|
|
354
371
|
this.moduleProcesses.set(module.name, {
|
|
355
372
|
backend: backendProcess,
|
|
356
|
-
frontend: frontendProcess
|
|
373
|
+
frontend: frontendProcess,
|
|
357
374
|
});
|
|
358
375
|
// Handle process events
|
|
359
|
-
backendProcess.on(
|
|
376
|
+
backendProcess.on("error", (error) => {
|
|
360
377
|
console.error(`Backend process error for ${module.name}:`, error);
|
|
361
378
|
});
|
|
362
|
-
frontendProcess.on(
|
|
379
|
+
frontendProcess.on("error", (error) => {
|
|
363
380
|
console.error(`Frontend process error for ${module.name}:`, error);
|
|
364
381
|
});
|
|
365
382
|
}
|
|
@@ -374,10 +391,10 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
374
391
|
return;
|
|
375
392
|
try {
|
|
376
393
|
if (processes.backend) {
|
|
377
|
-
processes.backend.kill(
|
|
394
|
+
processes.backend.kill("SIGTERM");
|
|
378
395
|
}
|
|
379
396
|
if (processes.frontend) {
|
|
380
|
-
processes.frontend.kill(
|
|
397
|
+
processes.frontend.kill("SIGTERM");
|
|
381
398
|
}
|
|
382
399
|
this.moduleProcesses.delete(moduleId);
|
|
383
400
|
}
|
|
@@ -387,57 +404,57 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
387
404
|
}
|
|
388
405
|
async installFromRemote(installation) {
|
|
389
406
|
// Implementation for remote Git repository installation
|
|
390
|
-
const { exec } = await import(
|
|
391
|
-
const util = await import(
|
|
407
|
+
const { exec } = await import("child_process");
|
|
408
|
+
const util = await import("util");
|
|
392
409
|
const execAsync = util.promisify(exec);
|
|
393
|
-
const targetDir = path.join(process.cwd(),
|
|
410
|
+
const targetDir = path.join(process.cwd(), "installed_modules", installation.moduleId);
|
|
394
411
|
try {
|
|
395
412
|
// Update progress
|
|
396
413
|
installation.progress = 20;
|
|
397
|
-
installation.logs?.push(
|
|
414
|
+
installation.logs?.push("Cloning repository...");
|
|
398
415
|
// Clone repository
|
|
399
416
|
await execAsync(`git clone ${installation.source.url} ${targetDir}`);
|
|
400
417
|
// Update progress
|
|
401
418
|
installation.progress = 40;
|
|
402
|
-
installation.logs?.push(
|
|
419
|
+
installation.logs?.push("Repository cloned");
|
|
403
420
|
// Checkout specific version if provided
|
|
404
|
-
if (installation.version && installation.version !==
|
|
421
|
+
if (installation.version && installation.version !== "latest") {
|
|
405
422
|
await execAsync(`cd ${targetDir} && git checkout ${installation.version}`);
|
|
406
423
|
installation.logs?.push(`Checked out version ${installation.version}`);
|
|
407
424
|
}
|
|
408
425
|
// Update progress
|
|
409
426
|
installation.progress = 60;
|
|
410
|
-
installation.logs?.push(
|
|
427
|
+
installation.logs?.push("Installing dependencies...");
|
|
411
428
|
// Install dependencies
|
|
412
429
|
await execAsync(`cd ${targetDir} && npm run install:all`);
|
|
413
430
|
// Update progress
|
|
414
431
|
installation.progress = 80;
|
|
415
|
-
installation.logs?.push(
|
|
432
|
+
installation.logs?.push("Building module...");
|
|
416
433
|
// Build module
|
|
417
434
|
await execAsync(`cd ${targetDir} && npm run build`);
|
|
418
435
|
// Update progress
|
|
419
436
|
installation.progress = 90;
|
|
420
|
-
installation.logs?.push(
|
|
437
|
+
installation.logs?.push("Loading module manifest...");
|
|
421
438
|
// Load module manifest
|
|
422
|
-
const manifestPath = path.join(targetDir,
|
|
423
|
-
const manifestContent = await fs.readFile(manifestPath,
|
|
439
|
+
const manifestPath = path.join(targetDir, "module.json");
|
|
440
|
+
const manifestContent = await fs.readFile(manifestPath, "utf-8");
|
|
424
441
|
const manifest = JSON.parse(manifestContent);
|
|
425
442
|
// Add to available modules
|
|
426
443
|
this.availableModules.set(installation.moduleId, manifest);
|
|
427
|
-
installation.logs?.push(
|
|
444
|
+
installation.logs?.push("Module installed successfully");
|
|
428
445
|
}
|
|
429
446
|
catch (error) {
|
|
430
|
-
installation.logs?.push(`Error: ${error instanceof Error ? error.message :
|
|
447
|
+
installation.logs?.push(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
431
448
|
throw error;
|
|
432
449
|
}
|
|
433
450
|
}
|
|
434
451
|
async installFromMarketplace(installation) {
|
|
435
452
|
// Implementation for marketplace installation
|
|
436
|
-
throw new Error(
|
|
453
|
+
throw new Error("Marketplace installation not yet implemented");
|
|
437
454
|
}
|
|
438
455
|
async installFromContainer(installation) {
|
|
439
456
|
// Implementation for container-based installation
|
|
440
|
-
throw new Error(
|
|
457
|
+
throw new Error("Container installation not yet implemented");
|
|
441
458
|
}
|
|
442
459
|
generateInstallationId() {
|
|
443
460
|
return `install_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
@@ -446,7 +463,7 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
446
463
|
this.recentActivity.push({
|
|
447
464
|
type,
|
|
448
465
|
moduleId,
|
|
449
|
-
timestamp: new Date()
|
|
466
|
+
timestamp: new Date(),
|
|
450
467
|
});
|
|
451
468
|
// Keep only last 100 activities
|
|
452
469
|
if (this.recentActivity.length > 100) {
|
|
@@ -482,40 +499,48 @@ export class ModuleRegistryService extends EventEmitter {
|
|
|
482
499
|
try {
|
|
483
500
|
let result;
|
|
484
501
|
switch (operation) {
|
|
485
|
-
case
|
|
502
|
+
case "activate":
|
|
486
503
|
result = await this.activateModule(moduleId);
|
|
487
504
|
break;
|
|
488
|
-
case
|
|
505
|
+
case "deactivate":
|
|
489
506
|
result = await this.deactivateModule(moduleId);
|
|
490
507
|
break;
|
|
491
|
-
case
|
|
508
|
+
case "restart":
|
|
492
509
|
await this.deactivateModule(moduleId);
|
|
493
510
|
result = await this.activateModule(moduleId);
|
|
494
511
|
break;
|
|
495
|
-
case
|
|
512
|
+
case "uninstall":
|
|
496
513
|
result = await this.unregisterModule(moduleId);
|
|
497
514
|
break;
|
|
498
515
|
}
|
|
499
|
-
results.push({
|
|
516
|
+
results.push({
|
|
517
|
+
moduleId,
|
|
518
|
+
success: result.success,
|
|
519
|
+
message: result.message,
|
|
520
|
+
});
|
|
500
521
|
}
|
|
501
522
|
catch (error) {
|
|
502
|
-
results.push({
|
|
523
|
+
results.push({
|
|
524
|
+
moduleId,
|
|
525
|
+
success: false,
|
|
526
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
527
|
+
});
|
|
503
528
|
}
|
|
504
529
|
}
|
|
505
530
|
return results;
|
|
506
531
|
}
|
|
507
532
|
subscribeToEvents(callback) {
|
|
508
|
-
this.on(
|
|
509
|
-
this.on(
|
|
510
|
-
this.on(
|
|
511
|
-
this.on(
|
|
512
|
-
this.on(
|
|
533
|
+
this.on("module:registered", callback);
|
|
534
|
+
this.on("module:unregistered", callback);
|
|
535
|
+
this.on("module:activated", callback);
|
|
536
|
+
this.on("module:deactivated", callback);
|
|
537
|
+
this.on("module:installed", callback);
|
|
513
538
|
return () => {
|
|
514
|
-
this.off(
|
|
515
|
-
this.off(
|
|
516
|
-
this.off(
|
|
517
|
-
this.off(
|
|
518
|
-
this.off(
|
|
539
|
+
this.off("module:registered", callback);
|
|
540
|
+
this.off("module:unregistered", callback);
|
|
541
|
+
this.off("module:activated", callback);
|
|
542
|
+
this.off("module:deactivated", callback);
|
|
543
|
+
this.off("module:installed", callback);
|
|
519
544
|
};
|
|
520
545
|
}
|
|
521
546
|
}
|