@qelos/plugins-cli 0.0.30 → 0.1.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/cli.mjs +2 -0
- package/commands/get.mjs +26 -0
- package/controllers/get.mjs +54 -0
- package/package.json +1 -1
- package/services/git-files.mjs +134 -47
package/cli.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import pushCommand from './commands/push.mjs';
|
|
|
11
11
|
import pullCommand from './commands/pull.mjs';
|
|
12
12
|
import generateCommand from './commands/generate.mjs';
|
|
13
13
|
import blueprintsCommand from './commands/blueprints.mjs';
|
|
14
|
+
import getCommand from './commands/get.mjs';
|
|
14
15
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
|
|
16
17
|
const program = yargs(hideBin(process.argv));
|
|
@@ -28,5 +29,6 @@ pushCommand(program)
|
|
|
28
29
|
pullCommand(program)
|
|
29
30
|
generateCommand(program)
|
|
30
31
|
blueprintsCommand(program)
|
|
32
|
+
getCommand(program)
|
|
31
33
|
|
|
32
34
|
program.help().argv;
|
package/commands/get.mjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import getController from "../controllers/get.mjs";
|
|
2
|
+
|
|
3
|
+
export default function getCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command('get [type] [path]', 'get files from git without pushing. Ability to view components, blueprints, configurations, plugins, blocks, committed files, or staged files.',
|
|
6
|
+
(yargs) => {
|
|
7
|
+
return yargs
|
|
8
|
+
.positional('type', {
|
|
9
|
+
describe: 'Type of the resource to get. Can be components, blueprints, configurations, plugins, blocks, integrations, connections, committed, staged, or all.',
|
|
10
|
+
type: 'string',
|
|
11
|
+
choices: ['components', 'blueprints', 'configs', 'plugins', 'blocks', 'integrations', 'connections', 'committed', 'staged', 'all', '*'],
|
|
12
|
+
required: true
|
|
13
|
+
})
|
|
14
|
+
.positional('path', {
|
|
15
|
+
describe: 'Path to search for resources.',
|
|
16
|
+
type: 'string',
|
|
17
|
+
required: true
|
|
18
|
+
})
|
|
19
|
+
.option('json', {
|
|
20
|
+
alias: 'j',
|
|
21
|
+
type: 'boolean',
|
|
22
|
+
description: 'Output in JSON format'
|
|
23
|
+
})
|
|
24
|
+
},
|
|
25
|
+
getController)
|
|
26
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { logger } from '../services/logger.mjs';
|
|
2
|
+
import { getGitFiles } from '../services/git-files.mjs';
|
|
3
|
+
import { green, blue, yellow, red } from '../utils/colors.mjs';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
|
|
7
|
+
export default async function getController(argv) {
|
|
8
|
+
const { type, path: basePath, json, verbose } = argv;
|
|
9
|
+
|
|
10
|
+
if (verbose) {
|
|
11
|
+
process.env.VERBOSE = 'true';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// For git-based types (committed, staged)
|
|
16
|
+
if (type === 'committed' || type === 'staged') {
|
|
17
|
+
const classified = getGitFiles(type, basePath || '.');
|
|
18
|
+
|
|
19
|
+
if (json) {
|
|
20
|
+
console.log(JSON.stringify(classified, null, 2));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Display results
|
|
25
|
+
console.log(blue(`\n=== ${type.toUpperCase()} FILES ===\n`));
|
|
26
|
+
|
|
27
|
+
Object.entries(classified).forEach(([fileType, files]) => {
|
|
28
|
+
if (files.length > 0) {
|
|
29
|
+
console.log(yellow(`${fileType.toUpperCase()} (${files.length}):`));
|
|
30
|
+
files.forEach(file => {
|
|
31
|
+
const relativePath = path.relative(basePath || '.', file);
|
|
32
|
+
console.log(` - ${relativePath}`);
|
|
33
|
+
});
|
|
34
|
+
console.log('');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// For other types, we would need to implement similar logic to push
|
|
42
|
+
// For now, just show what would be searched for
|
|
43
|
+
console.log(blue(`\n=== SEARCH FOR ${type.toUpperCase()} ===\n`));
|
|
44
|
+
console.log(yellow(`Base path: ${basePath || '.'}`));
|
|
45
|
+
console.log(red(`Note: Only 'committed' and 'staged' types are currently supported for preview.`));
|
|
46
|
+
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logger.error(error.message);
|
|
49
|
+
if (verbose) {
|
|
50
|
+
console.error(error.stack);
|
|
51
|
+
}
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
package/package.json
CHANGED
package/services/git-files.mjs
CHANGED
|
@@ -73,13 +73,17 @@ function getCommittedFiles() {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Get the list of staged files
|
|
76
|
+
* Get the list of staged files (excluding deleted files)
|
|
77
77
|
* @returns {string[]} Array of file paths
|
|
78
78
|
*/
|
|
79
79
|
function getStagedFiles() {
|
|
80
80
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
// Use --name-status to get file status, then filter out deleted files (status D)
|
|
82
|
+
const output = execSync('git diff --cached --name-status', { encoding: 'utf-8' });
|
|
83
|
+
return output.trim()
|
|
84
|
+
.split('\n')
|
|
85
|
+
.filter(line => line && !line.startsWith('D')) // Skip deleted files
|
|
86
|
+
.map(line => line.substring(1).trim()); // Remove status prefix and get file path
|
|
83
87
|
} catch (error) {
|
|
84
88
|
logger.error('Failed to get staged files', error);
|
|
85
89
|
throw new Error('Unable to retrieve staged files from git');
|
|
@@ -130,11 +134,95 @@ function findReferencingConfigs(refPath, basePath) {
|
|
|
130
134
|
return referencingConfigs;
|
|
131
135
|
}
|
|
132
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Find plugins that reference a specific HTML file through $ref
|
|
139
|
+
* @param {string} htmlRelativePath - Relative path of the HTML file from the plugin directory
|
|
140
|
+
* @param {string} basePath - Base path to search for plugins
|
|
141
|
+
* @returns {Array} Array of plugin.json file paths that reference the HTML file
|
|
142
|
+
*/
|
|
143
|
+
function findReferencingPlugins(htmlRelativePath, basePath) {
|
|
144
|
+
const referencingPlugins = [];
|
|
145
|
+
// Ensure basePath is absolute
|
|
146
|
+
const absoluteBasePath = path.resolve(basePath);
|
|
147
|
+
const pluginsDir = path.join(absoluteBasePath, 'plugins');
|
|
148
|
+
|
|
149
|
+
if (!fs.existsSync(pluginsDir)) {
|
|
150
|
+
return referencingPlugins;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Get all plugin directories and .plugin.json files in the plugins directory
|
|
154
|
+
const pluginDirs = fs.readdirSync(pluginsDir, { withFileTypes: true })
|
|
155
|
+
.filter(dirent => dirent.isDirectory())
|
|
156
|
+
.map(dirent => dirent.name);
|
|
157
|
+
|
|
158
|
+
// Also check for .plugin.json files directly in the plugins directory
|
|
159
|
+
const pluginFiles = fs.readdirSync(pluginsDir)
|
|
160
|
+
.filter(file => file.endsWith('.plugin.json'));
|
|
161
|
+
|
|
162
|
+
// Check plugin files in subdirectories
|
|
163
|
+
for (const pluginDir of pluginDirs) {
|
|
164
|
+
const pluginJsonPath = path.join(pluginsDir, pluginDir, 'plugin.json');
|
|
165
|
+
|
|
166
|
+
if (fs.existsSync(pluginJsonPath)) {
|
|
167
|
+
try {
|
|
168
|
+
const content = fs.readFileSync(pluginJsonPath, 'utf-8');
|
|
169
|
+
const plugin = JSON.parse(content);
|
|
170
|
+
|
|
171
|
+
// Check all $ref references in the plugin
|
|
172
|
+
const refs = findAllRefs(plugin);
|
|
173
|
+
|
|
174
|
+
// Check if any ref matches our target HTML file
|
|
175
|
+
// The ref might be like "./micro-frontends/categories.html"
|
|
176
|
+
for (const ref of refs) {
|
|
177
|
+
if (ref.includes(htmlRelativePath) || ref.endsWith(path.basename(htmlRelativePath))) {
|
|
178
|
+
if (!referencingPlugins.includes(pluginJsonPath)) {
|
|
179
|
+
referencingPlugins.push(pluginJsonPath);
|
|
180
|
+
}
|
|
181
|
+
logger.debug(`Plugin ${pluginDir} references HTML file: ${ref}`);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
logger.warning(`Error reading plugin.json ${pluginJsonPath}: ${error.message}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check .plugin.json files directly in plugins directory
|
|
192
|
+
for (const pluginFile of pluginFiles) {
|
|
193
|
+
const pluginJsonPath = path.join(pluginsDir, pluginFile);
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const content = fs.readFileSync(pluginJsonPath, 'utf-8');
|
|
197
|
+
const plugin = JSON.parse(content);
|
|
198
|
+
|
|
199
|
+
// Check all $ref references in the plugin
|
|
200
|
+
const refs = findAllRefs(plugin);
|
|
201
|
+
|
|
202
|
+
// Check if any ref matches our target HTML file
|
|
203
|
+
// The ref might be like "./micro-frontends/categories.html"
|
|
204
|
+
for (const ref of refs) {
|
|
205
|
+
if (ref.includes(htmlRelativePath) || ref.endsWith(path.basename(htmlRelativePath))) {
|
|
206
|
+
if (!referencingPlugins.includes(pluginJsonPath)) {
|
|
207
|
+
referencingPlugins.push(pluginJsonPath);
|
|
208
|
+
}
|
|
209
|
+
logger.debug(`Plugin ${pluginFile} references HTML file: ${ref}`);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
logger.warning(`Error reading plugin.json ${pluginJsonPath}: ${error.message}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return referencingPlugins;
|
|
219
|
+
}
|
|
220
|
+
|
|
133
221
|
/**
|
|
134
222
|
* Find integration files that reference a specific file via $ref
|
|
135
|
-
* @param {string} refPath -
|
|
223
|
+
* @param {string} refPath - Reference path to look for
|
|
136
224
|
* @param {string} basePath - Base path to search for integrations
|
|
137
|
-
* @returns {
|
|
225
|
+
* @returns {Array} Array of integration file paths that reference the target
|
|
138
226
|
*/
|
|
139
227
|
function findReferencingIntegrations(refPath, basePath) {
|
|
140
228
|
const referencingIntegrations = [];
|
|
@@ -240,21 +328,23 @@ function classifyFiles(files, basePath) {
|
|
|
240
328
|
const basename = path.basename(fullPath, ext);
|
|
241
329
|
|
|
242
330
|
// Check for specific file types
|
|
243
|
-
if (relativePath.
|
|
331
|
+
if (relativePath.startsWith('components/') && ext === '.vue') {
|
|
244
332
|
classified.components.push(fullPath);
|
|
245
|
-
} else if (relativePath.
|
|
333
|
+
} else if (relativePath.startsWith('blueprints/') && ext === '.json') {
|
|
246
334
|
classified.blueprints.push(fullPath);
|
|
247
|
-
} else if (relativePath.
|
|
335
|
+
} else if (relativePath.startsWith('configs/') && ext === '.json') {
|
|
248
336
|
classified.configs.push(fullPath);
|
|
249
|
-
} else if (relativePath.
|
|
250
|
-
classified.plugins.
|
|
251
|
-
|
|
337
|
+
} else if (relativePath.startsWith('plugins/') && ext === '.json') {
|
|
338
|
+
if (!classified.plugins.includes(fullPath)) {
|
|
339
|
+
classified.plugins.push(fullPath);
|
|
340
|
+
}
|
|
341
|
+
} else if (relativePath.startsWith('blocks/') && ext === '.json') {
|
|
252
342
|
classified.blocks.push(fullPath);
|
|
253
|
-
} else if (relativePath.
|
|
343
|
+
} else if (relativePath.startsWith('integrations/') && ext === '.json') {
|
|
254
344
|
classified.integrations.push(fullPath);
|
|
255
|
-
} else if (relativePath.
|
|
345
|
+
} else if (relativePath.startsWith('connections/') && ext === '.json') {
|
|
256
346
|
classified.connections.push(fullPath);
|
|
257
|
-
} else if (
|
|
347
|
+
} else if (relativePath.startsWith('integrations/prompts/') && ext === '.md') {
|
|
258
348
|
// Find integrations that reference this prompt file
|
|
259
349
|
classified.prompts.push(fullPath);
|
|
260
350
|
|
|
@@ -277,7 +367,7 @@ function classifyFiles(files, basePath) {
|
|
|
277
367
|
// 2. In configs directory -> These are typically referenced by configs, not pushed directly
|
|
278
368
|
// 3. Other locations -> treat as micro-frontends
|
|
279
369
|
|
|
280
|
-
if (relativePath.
|
|
370
|
+
if (relativePath.startsWith('configs/') || relativePath.startsWith('configs\\')) {
|
|
281
371
|
// HTML file in configs directory - these are usually referenced by config files, not pushed directly
|
|
282
372
|
logger.debug(`Found HTML file in configs directory (will be pushed via referencing config): ${relativePath}`);
|
|
283
373
|
|
|
@@ -296,44 +386,41 @@ function classifyFiles(files, basePath) {
|
|
|
296
386
|
// Find plugins that contain this HTML file (micro-frontends)
|
|
297
387
|
classified.microFrontends.push(fullPath);
|
|
298
388
|
|
|
299
|
-
// For HTML files, we need to find which plugin
|
|
300
|
-
// HTML
|
|
301
|
-
|
|
302
|
-
let pluginJson = path.join(pluginDir, 'plugin.json');
|
|
389
|
+
// For HTML files, we need to find which plugin references them
|
|
390
|
+
// The HTML file should be in a micro-frontends directory within a plugin
|
|
391
|
+
const htmlBasename = path.basename(fullPath);
|
|
303
392
|
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
393
|
+
// Try to find plugins that reference this HTML file
|
|
394
|
+
// The ref path should be relative to the plugin directory
|
|
395
|
+
// e.g., "./micro-frontends/categories.html"
|
|
396
|
+
let refPath = `./micro-frontends/${htmlBasename}`;
|
|
397
|
+
|
|
398
|
+
// If the file is in a nested path, preserve that structure
|
|
399
|
+
if (relativePath.startsWith('plugins/micro-frontends/')) {
|
|
400
|
+
const parts = relativePath.split('plugins/micro-frontends/');
|
|
401
|
+
if (parts[1]) {
|
|
402
|
+
refPath = `./micro-frontends/${parts[1]}`;
|
|
313
403
|
}
|
|
314
|
-
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
searchDir = path.dirname(searchDir);
|
|
320
|
-
const testPluginJson = path.join(searchDir, 'plugin.json');
|
|
321
|
-
if (fs.existsSync(testPluginJson)) {
|
|
322
|
-
pluginJson = testPluginJson;
|
|
323
|
-
break;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
404
|
+
} else if (relativePath.includes('micro-frontends/')) {
|
|
405
|
+
// Handle other micro-frontends paths
|
|
406
|
+
const parts = relativePath.split('micro-frontends/');
|
|
407
|
+
if (parts[1]) {
|
|
408
|
+
refPath = `./micro-frontends/${parts[1]}`;
|
|
326
409
|
}
|
|
327
410
|
}
|
|
328
411
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
412
|
+
const referencingPlugins = findReferencingPlugins(refPath, basePath);
|
|
413
|
+
|
|
414
|
+
// Add all referencing plugins to the classified list
|
|
415
|
+
for (const pluginPath of referencingPlugins) {
|
|
416
|
+
if (!classified.plugins.includes(pluginPath)) {
|
|
417
|
+
classified.plugins.push(pluginPath);
|
|
418
|
+
logger.debug(`Found plugin referencing HTML ${relativePath}: ${path.basename(pluginPath)}`);
|
|
334
419
|
}
|
|
335
|
-
}
|
|
336
|
-
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (referencingPlugins.length === 0) {
|
|
423
|
+
logger.warning(`Could not find any plugin referencing HTML file: ${relativePath} (searched for ref: ${refPath})`);
|
|
337
424
|
}
|
|
338
425
|
}
|
|
339
426
|
} else {
|