g360-cli 1.9.0 → 1.10.1
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 +65 -7
- package/package.json +11 -2
- package/src/cli.js +54 -0
- package/src/commands/addon.js +188 -0
- package/src/commands/addon.test.js +37 -0
- package/src/commands/audit.test.js +32 -0
- package/src/commands/bring.test.js +37 -0
- package/src/commands/ingest.js +78 -84
- package/src/commands/init.js +11 -0
- package/src/commands/init.test.js +19 -0
- package/src/commands/list.test.js +132 -0
- package/src/commands/scan.js +68 -80
- package/src/commands/set-skill.js +21 -17
- package/src/commands/set-skill.test.js +134 -0
- package/src/commands/signature.js +46 -26
- package/src/commands/update.js +14 -2
- package/src/commands/validate.js +90 -66
- package/src/lib/asset-validator.test.js +237 -0
- package/src/lib/manifest.test.js +173 -0
- package/src/lib/python_runner.js +8 -8
- package/src/lib/validator.test.js +115 -0
- package/src/assets/engine/g360-data-validator.js +0 -44
- package/src/assets/engine/g360-engine.js +0 -12
- package/src/assets/engine/g360-field-mapper.js +0 -35
- package/src/assets/engine/g360-skill-audit.mjs +0 -37
- package/src/assets/engine/g360-skill-meta-evaluator.mjs +0 -33
- package/src/lib/assets.js +0 -38
- package/src/lib/checksum.js +0 -27
- package/src/lib/config.js +0 -23
- package/src/lib/offline.js +0 -33
- package/src/lib/presenter.js +0 -24
- package/src/lib/rollback.js +0 -49
- package/src/lib/theme.js +0 -30
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export async function audit(code, options = {}) {
|
|
2
|
-
const results = {
|
|
3
|
-
score: 0,
|
|
4
|
-
issues: [],
|
|
5
|
-
suggestions: []
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
if (!code || code.length === 0) {
|
|
9
|
-
results.issues.push({ line: 0, message: 'Empty code' });
|
|
10
|
-
return results;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const lines = code.split('\n');
|
|
14
|
-
let score = 100;
|
|
15
|
-
|
|
16
|
-
lines.forEach((line, index) => {
|
|
17
|
-
if (line.length > 120) {
|
|
18
|
-
results.issues.push({ line: index + 1, message: 'Line too long (>120 chars)' });
|
|
19
|
-
score -= 2;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (line.includes('TODO') || line.includes('FIXME')) {
|
|
23
|
-
results.suggestions.push({ line: index + 1, message: 'Unresolved TODO/FIXME' });
|
|
24
|
-
score -= 1;
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (!code.includes('g360') && !code.includes('G360')) {
|
|
29
|
-
results.suggestions.push({ line: 0, message: 'Consider adding G360 identity' });
|
|
30
|
-
score -= 5;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
results.score = Math.max(0, score);
|
|
34
|
-
return results;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default { audit };
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export async function evaluateMetaTags(html) {
|
|
2
|
-
const results = {
|
|
3
|
-
score: 0,
|
|
4
|
-
tags: [],
|
|
5
|
-
issues: [],
|
|
6
|
-
suggestions: []
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const requiredTags = ['title', 'description', 'viewport'];
|
|
10
|
-
const metaTags = html.match(/<meta[^>]+>/gi) || [];
|
|
11
|
-
|
|
12
|
-
requiredTags.forEach(tag => {
|
|
13
|
-
if (html.includes(`name="${tag}"`) || html.includes(`property="${tag}"`)) {
|
|
14
|
-
results.tags.push({ tag, found: true });
|
|
15
|
-
} else {
|
|
16
|
-
results.issues.push({ tag, message: `Missing ${tag} tag` });
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const ogTags = ['og:title', 'og:description', 'og:image'];
|
|
21
|
-
ogTags.forEach(tag => {
|
|
22
|
-
if (html.includes(`property="${tag}"`)) {
|
|
23
|
-
results.tags.push({ tag, found: true, type: 'og' });
|
|
24
|
-
} else {
|
|
25
|
-
results.suggestions.push({ tag, message: `Consider adding Open Graph: ${tag}` });
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
results.score = Math.round((results.tags.length / (requiredTags.length + ogTags.length)) * 100);
|
|
30
|
-
return results;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export default { evaluateMetaTags };
|
package/src/lib/assets.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
4
|
-
|
|
5
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
|
|
7
|
-
export const assets = {
|
|
8
|
-
path: path.join(__dirname, '../assets'),
|
|
9
|
-
|
|
10
|
-
exists(assetPath) {
|
|
11
|
-
return fs.existsSync(path.join(this.path, assetPath));
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
async copy(assetPath, destPath, options = {}) {
|
|
15
|
-
const { overwrite = false } = options;
|
|
16
|
-
const src = path.join(this.path, assetPath);
|
|
17
|
-
const dest = path.join(destPath, path.basename(assetPath));
|
|
18
|
-
|
|
19
|
-
if (!this.exists(assetPath)) {
|
|
20
|
-
throw new Error(`Asset not found: ${assetPath}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (fs.existsSync(dest) && !overwrite) {
|
|
24
|
-
throw new Error(`Destination already exists: ${dest}`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
await fs.copy(src, dest, { overwrite });
|
|
28
|
-
return dest;
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
list(category) {
|
|
32
|
-
const categoryPath = path.join(this.path, category);
|
|
33
|
-
if (!fs.existsSync(categoryPath)) {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
return fs.readdirSync(categoryPath);
|
|
37
|
-
}
|
|
38
|
-
};
|
package/src/lib/checksum.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import crypto from 'crypto';
|
|
3
|
-
|
|
4
|
-
export const checksum = {
|
|
5
|
-
async calculate(filePath) {
|
|
6
|
-
const content = await fs.readFile(filePath);
|
|
7
|
-
return crypto.createHash('md5').update(content).digest('hex');
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
async verify(filePath, expectedHash) {
|
|
11
|
-
const actualHash = await this.calculate(filePath);
|
|
12
|
-
return actualHash === expectedHash;
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
async generateManifest(dir, files = []) {
|
|
16
|
-
const manifest = {};
|
|
17
|
-
|
|
18
|
-
for (const file of files) {
|
|
19
|
-
const filePath = `${dir}/${file}`;
|
|
20
|
-
if (fs.existsSync(filePath)) {
|
|
21
|
-
manifest[file] = await this.calculate(filePath);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return manifest;
|
|
26
|
-
}
|
|
27
|
-
};
|
package/src/lib/config.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export const config = {
|
|
2
|
-
defaults: {
|
|
3
|
-
template: 'web-pwa',
|
|
4
|
-
assets: ['components', 'skills', 'engine'],
|
|
5
|
-
theme: 'cool-light'
|
|
6
|
-
},
|
|
7
|
-
|
|
8
|
-
projectTypes: {
|
|
9
|
-
'web-pwa': { framework: 'vanilla', features: ['pwa', 'offline'] },
|
|
10
|
-
'web-svelte': { framework: 'svelte', features: ['routing', 'stores'] },
|
|
11
|
-
'python-cli': { framework: 'python', features: ['cli', 'argparse'] },
|
|
12
|
-
'vba-excel': { framework: 'vba', features: ['excel', 'macros'] }
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
themes: {
|
|
16
|
-
'cool-light': { primary: '#3B82F6', secondary: '#10B981', accent: '#8B5CF6' },
|
|
17
|
-
'cool-dark': { primary: '#60A5FA', secondary: '#34D399', accent: '#A78BFA' },
|
|
18
|
-
'warm-light': { primary: '#F59E0B', secondary: '#EF4444', accent: '#8B5CF6' },
|
|
19
|
-
'warm-dark': { primary: '#FBBF24', secondary: '#F87171', accent: '#A78BFA' },
|
|
20
|
-
'neutral-light': { primary: '#6B7280', secondary: '#374151', accent: '#111827' },
|
|
21
|
-
'neutral-dark': { primary: '#9CA3AF', secondary: '#D1D5DB', accent: '#F9FAFB' }
|
|
22
|
-
}
|
|
23
|
-
};
|
package/src/lib/offline.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export const offline = {
|
|
5
|
-
cache: new Map(),
|
|
6
|
-
cacheDir: '.g360-cache',
|
|
7
|
-
|
|
8
|
-
async isAvailable() {
|
|
9
|
-
return true;
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
async getCached(asset) {
|
|
13
|
-
return this.cache.get(asset);
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
async setCache(asset, data) {
|
|
17
|
-
this.cache.set(asset, data);
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
async loadFromCache(asset) {
|
|
21
|
-
const cachePath = path.join(this.cacheDir, `${asset}.json`);
|
|
22
|
-
if (fs.existsSync(cachePath)) {
|
|
23
|
-
return fs.readJson(cachePath);
|
|
24
|
-
}
|
|
25
|
-
return null;
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
async saveToCache(asset, data) {
|
|
29
|
-
const cachePath = path.join(this.cacheDir, `${asset}.json`);
|
|
30
|
-
await fs.ensureDir(this.cacheDir);
|
|
31
|
-
await fs.writeJson(cachePath, data);
|
|
32
|
-
}
|
|
33
|
-
};
|
package/src/lib/presenter.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
export const presenter = {
|
|
4
|
-
formatTree(items, prefix = '', isLast = true) {
|
|
5
|
-
return items.map((item, index) => {
|
|
6
|
-
const isLastItem = index === items.length - 1;
|
|
7
|
-
const connector = isLastItem ? '└── ' : '├── ';
|
|
8
|
-
return `${prefix}${connector}${item}`;
|
|
9
|
-
}).join('\n');
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
formatList(items, columns = 2) {
|
|
13
|
-
const rows = [];
|
|
14
|
-
for (let i = 0; i < items.length; i += columns) {
|
|
15
|
-
const row = items.slice(i, i + columns);
|
|
16
|
-
rows.push(row.join('\t'));
|
|
17
|
-
}
|
|
18
|
-
return rows.join('\n');
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
formatJson(data) {
|
|
22
|
-
return JSON.stringify(data, null, 2);
|
|
23
|
-
}
|
|
24
|
-
};
|
package/src/lib/rollback.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export const rollback = {
|
|
5
|
-
history: new Map(),
|
|
6
|
-
|
|
7
|
-
async snapshot(projectDir, label) {
|
|
8
|
-
const snapshot = {
|
|
9
|
-
timestamp: new Date().toISOString(),
|
|
10
|
-
label,
|
|
11
|
-
files: []
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const g360Dir = path.join(projectDir, 'g360');
|
|
15
|
-
if (fs.existsSync(g360Dir)) {
|
|
16
|
-
const files = fs.readdirSync(g360Dir, { recursive: true, withFileTypes: true });
|
|
17
|
-
snapshot.files = files.map(f => ({
|
|
18
|
-
path: f.fullPath || path.join(g360Dir, f.name),
|
|
19
|
-
type: f.isDirectory() ? 'dir' : 'file'
|
|
20
|
-
}));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
this.history.set(projectDir, snapshot);
|
|
24
|
-
return snapshot;
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
async restore(projectDir) {
|
|
28
|
-
const snapshot = this.history.get(projectDir);
|
|
29
|
-
if (!snapshot) {
|
|
30
|
-
throw new Error('No snapshot found for this project');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const g360Dir = path.join(projectDir, 'g360');
|
|
34
|
-
|
|
35
|
-
if (fs.existsSync(g360Dir)) {
|
|
36
|
-
await fs.remove(g360Dir);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
for (const file of snapshot.files) {
|
|
40
|
-
if (file.type === 'dir') {
|
|
41
|
-
await fs.ensureDir(file.path);
|
|
42
|
-
} else {
|
|
43
|
-
await fs.ensureFile(file.path);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return snapshot;
|
|
48
|
-
}
|
|
49
|
-
};
|
package/src/lib/theme.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
|
|
3
|
-
export const theme = {
|
|
4
|
-
colors: {
|
|
5
|
-
primary: '#3B82F6',
|
|
6
|
-
secondary: '#10B981',
|
|
7
|
-
accent: '#8B5CF6',
|
|
8
|
-
success: '#22C55E',
|
|
9
|
-
warning: '#F59E0B',
|
|
10
|
-
error: '#EF4444',
|
|
11
|
-
info: '#06B6D4'
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
styles: {
|
|
15
|
-
header: chalk.bold.cyan,
|
|
16
|
-
success: chalk.green,
|
|
17
|
-
error: chalk.red,
|
|
18
|
-
warning: chalk.yellow,
|
|
19
|
-
info: chalk.blue,
|
|
20
|
-
muted: chalk.gray
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
format: {
|
|
24
|
-
title: (text) => chalk.bold.cyan(`\n${text}\n`),
|
|
25
|
-
section: (text) => chalk.bold.yellow(text),
|
|
26
|
-
item: (text) => chalk.white(text),
|
|
27
|
-
key: (text) => chalk.cyan(text),
|
|
28
|
-
value: (text) => chalk.white(text)
|
|
29
|
-
}
|
|
30
|
-
};
|