@qelos/plugins-cli 0.0.24 → 0.0.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qelos/plugins-cli",
3
- "version": "0.0.24",
3
+ "version": "0.0.27",
4
4
  "description": "CLI to manage QELOS plugins",
5
5
  "main": "cli.mjs",
6
6
  "bin": {
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { logger } from './logger.mjs';
4
+ import { removeIdFromObject } from '../utils/object-utils.mjs';
4
5
 
5
6
  /**
6
7
  * Push blueprints from local directory to remote
@@ -137,11 +138,6 @@ export async function pullBlueprints(sdk, targetPath) {
137
138
  // Fetch full blueprint details
138
139
  const fullBlueprint = await sdk.manageBlueprints.getBlueprint(blueprint.identifier);
139
140
 
140
- function removeIdFromObject(obj) {
141
- const { _id, ...rest } = obj;
142
- return rest;
143
- }
144
-
145
141
  const relevantFields = {
146
142
  identifier: fullBlueprint.identifier,
147
143
  name: fullBlueprint.name,
@@ -3,6 +3,61 @@ import { logger } from './logger.mjs';
3
3
  import path from 'node:path';
4
4
  import fs from 'node:fs';
5
5
 
6
+ /**
7
+ * Resolve the actual file path from Git output
8
+ * Git might show temp paths or different formats, so we need to find the real file
9
+ * @param {string} gitPath - Path as reported by Git
10
+ * @param {string} basePath - Base path to search for the actual file
11
+ * @returns {string|null} The actual file path or null if not found
12
+ */
13
+ function resolveActualFilePath(gitPath, basePath) {
14
+ // First try the direct path
15
+ const directPath = path.resolve(basePath, gitPath);
16
+ if (fs.existsSync(directPath)) {
17
+ return directPath;
18
+ }
19
+
20
+ // If it's an HTML file, it might be in a micro-frontends directory
21
+ if (gitPath.endsWith('.html')) {
22
+ // Try to find it in any plugin's micro-frontends directory
23
+ const pluginsDir = path.join(basePath, 'plugins');
24
+ if (fs.existsSync(pluginsDir)) {
25
+ const plugins = fs.readdirSync(pluginsDir);
26
+ const filename = path.basename(gitPath);
27
+
28
+ for (const plugin of plugins) {
29
+ const mfPath = path.join(pluginsDir, plugin, 'micro-frontends', filename);
30
+ if (fs.existsSync(mfPath)) {
31
+ return mfPath;
32
+ }
33
+ }
34
+ }
35
+ }
36
+
37
+ // For other files, try searching in common directories
38
+ const filename = path.basename(gitPath);
39
+ const searchDirs = [
40
+ 'components',
41
+ 'blueprints',
42
+ 'configs',
43
+ 'plugins',
44
+ 'blocks',
45
+ 'integrations',
46
+ 'connections',
47
+ 'prompts'
48
+ ];
49
+
50
+ for (const dir of searchDirs) {
51
+ const searchPath = path.join(basePath, dir, filename);
52
+ if (fs.existsSync(searchPath)) {
53
+ return searchPath;
54
+ }
55
+ }
56
+
57
+ // If still not found, return null
58
+ return null;
59
+ }
60
+
6
61
  /**
7
62
  * Get the list of files committed in the last commit
8
63
  * @returns {string[]} Array of file paths
@@ -114,8 +169,22 @@ function classifyFiles(files, basePath) {
114
169
  };
115
170
 
116
171
  for (const file of files) {
172
+ // Try to resolve the actual file path (handles Git temp paths)
173
+ let fullPath = path.resolve(basePath, file);
174
+
175
+ // If the direct path doesn't exist, try to find the actual file
176
+ if (!fs.existsSync(fullPath)) {
177
+ const resolvedPath = resolveActualFilePath(file, basePath);
178
+ if (resolvedPath) {
179
+ logger.debug(`Resolved Git path ${file} to actual path ${resolvedPath}`);
180
+ fullPath = resolvedPath;
181
+ } else {
182
+ logger.warning(`File not found, skipping: ${file}`);
183
+ continue;
184
+ }
185
+ }
186
+
117
187
  // Make sure the file exists
118
- const fullPath = path.resolve(basePath, file);
119
188
  if (!fs.existsSync(fullPath)) {
120
189
  logger.warning(`File not found, skipping: ${file}`);
121
190
  continue;
@@ -164,8 +233,33 @@ function classifyFiles(files, basePath) {
164
233
 
165
234
  // For HTML files, we need to find which plugin contains them
166
235
  // HTML files in plugins are typically part of the plugin structure
167
- const pluginDir = path.dirname(fullPath);
168
- const pluginJson = path.join(pluginDir, 'plugin.json');
236
+ let pluginDir = path.dirname(fullPath);
237
+ let pluginJson = path.join(pluginDir, 'plugin.json');
238
+
239
+ // If the file is in a temp path or unusual location, try to find the actual plugin
240
+ if (!fs.existsSync(pluginJson)) {
241
+ // Check if we're in a micro-frontends subdirectory
242
+ if (path.basename(pluginDir) === 'micro-frontends' ||
243
+ relativePath.includes('micro-frontends/') ||
244
+ relativePath.includes('micro-frontends\\')) {
245
+ // Go up one more level to find the plugin directory
246
+ pluginDir = path.dirname(pluginDir);
247
+ pluginJson = path.join(pluginDir, 'plugin.json');
248
+ }
249
+
250
+ // If still not found, try searching for plugin.json in parent directories
251
+ if (!fs.existsSync(pluginJson)) {
252
+ let searchDir = pluginDir;
253
+ for (let i = 0; i < 3; i++) { // Search up to 3 levels up
254
+ searchDir = path.dirname(searchDir);
255
+ const testPluginJson = path.join(searchDir, 'plugin.json');
256
+ if (fs.existsSync(testPluginJson)) {
257
+ pluginJson = testPluginJson;
258
+ break;
259
+ }
260
+ }
261
+ }
262
+ }
169
263
 
170
264
  if (fs.existsSync(pluginJson)) {
171
265
  // This HTML file is part of a plugin
@@ -173,6 +267,8 @@ function classifyFiles(files, basePath) {
173
267
  classified.plugins.push(pluginJson);
174
268
  logger.debug(`Found plugin containing HTML ${relativePath}: ${path.basename(pluginJson)}`);
175
269
  }
270
+ } else {
271
+ logger.warning(`Could not find plugin.json for HTML file: ${relativePath}`);
176
272
  }
177
273
  } else {
178
274
  logger.debug(`Unclassified file: ${relativePath}`);
@@ -281,6 +377,43 @@ export function prepareTempDirectories(classifiedFiles, tempDir) {
281
377
  logger.debug(`Failed to process refs for ${path.basename(file)}: ${error.message}`);
282
378
  }
283
379
  }
380
+
381
+ // If this is a plugin, check for micro-frontend HTML files and copy them too
382
+ if (type === 'plugins' && file.endsWith('.plugin.json')) {
383
+ try {
384
+ const content = fs.readFileSync(dest, 'utf-8');
385
+ const plugin = JSON.parse(content);
386
+
387
+ // Check if plugin has micro-frontends
388
+ if (plugin.microFrontends && plugin.microFrontends.length > 0) {
389
+ // Create micro-frontends directory in temp
390
+ const mfTempDir = path.join(tempDir, 'plugins', 'micro-frontends');
391
+ fs.mkdirSync(mfTempDir, { recursive: true });
392
+
393
+ for (const mf of plugin.microFrontends) {
394
+ if (mf.structure && mf.structure.$ref) {
395
+ const refPath = mf.structure.$ref;
396
+
397
+ // Resolve the ref path relative to the original plugin file location
398
+ const originalDir = path.dirname(file);
399
+ const mfSourcePath = path.resolve(originalDir, refPath);
400
+
401
+ if (fs.existsSync(mfSourcePath)) {
402
+ const mfFileName = path.basename(refPath);
403
+ const mfDestPath = path.join(mfTempDir, mfFileName);
404
+
405
+ fs.copyFileSync(mfSourcePath, mfDestPath);
406
+ logger.debug(`Copied micro-frontend ${refPath} from ${mfSourcePath} to ${mfDestPath}`);
407
+ } else {
408
+ logger.debug(`Micro-frontend file not found: ${mfSourcePath}`);
409
+ }
410
+ }
411
+ }
412
+ }
413
+ } catch (error) {
414
+ logger.debug(`Failed to process micro-frontends for ${path.basename(file)}: ${error.message}`);
415
+ }
416
+ }
284
417
  }
285
418
  }
286
419
 
@@ -2,6 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { logger } from './logger.mjs';
4
4
  import { loadReference } from './file-refs.mjs';
5
+ import { removeIdFromObject } from '../utils/object-utils.mjs';
5
6
 
6
7
  /**
7
8
  * Convert a string to kebab-case
@@ -55,6 +56,7 @@ export function extractMicroFrontendStructures(microFrontends, pluginPath) {
55
56
  // Return micro-frontend with $ref instead of structure
56
57
  return {
57
58
  ...mf,
59
+ requirements: (mf.requirements || []).map(removeIdFromObject),
58
60
  structure: { $ref: relativeRef }
59
61
  };
60
62
  });
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  import { join } from 'node:path';
4
4
  import { logger } from './logger.mjs';
5
5
  import { extractMicroFrontendStructures, resolveMicroFrontendStructures } from './micro-frontends.mjs';
6
+ import { removeIdFromObject } from '../utils/object-utils.mjs';
6
7
 
7
8
  function sanitizePluginForFile(plugin) {
8
9
  const sanitized = JSON.parse(JSON.stringify(plugin));
@@ -194,11 +195,6 @@ export async function pullPlugins(sdk, targetPath) {
194
195
  // Fetch full plugin details
195
196
  const fullPlugin = await sdk.managePlugins.getById(plugin._id);
196
197
 
197
- function removeIdFromObject(obj) {
198
- const { _id, ...rest } = obj;
199
- return rest;
200
- }
201
-
202
198
  // Extract micro-frontend structures to separate files
203
199
  const processedMicroFrontends = extractMicroFrontendStructures(
204
200
  (fullPlugin.microFrontends || []).map(removeIdFromObject),
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Removes the _id property from an object
3
+ * @param {Object} obj - The object to remove _id from
4
+ * @returns {Object} - The object without _id
5
+ */
6
+ export function removeIdFromObject(obj) {
7
+ const { _id, ...rest } = obj;
8
+ return rest;
9
+ }