promptgraph-mcp 2.4.0 → 2.4.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/github-import.js +54 -1
- package/marketplace.js +14 -1
- package/package.json +2 -2
package/github-import.js
CHANGED
|
@@ -4,7 +4,8 @@ import fs from 'fs';
|
|
|
4
4
|
import https from 'https';
|
|
5
5
|
import { globSync } from 'glob';
|
|
6
6
|
import { indexAll, indexSource } from './indexer.js';
|
|
7
|
-
import { loadConfig, saveConfig, SKILLS_STORE_DIR } from './config.js';
|
|
7
|
+
import { loadConfig, saveConfig, PROMPTGRAPH_DIR, SKILLS_STORE_DIR } from './config.js';
|
|
8
|
+
import { validateSkill } from './validator.js';
|
|
8
9
|
|
|
9
10
|
const SKILL_DIRS = ['skills', 'commands', 'prompts', 'agents', 'skills-store', 'slash-commands', 'custom-commands', 'templates'];
|
|
10
11
|
|
|
@@ -33,6 +34,58 @@ function repoExists(ownerRepo) {
|
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
// Validate all .md files in a repo's skills subdir against validateSkill().
|
|
38
|
+
// Returns { ok, errors[], warnings[] }.
|
|
39
|
+
export async function validateRepoSkills(ownerRepo) {
|
|
40
|
+
const errors = [];
|
|
41
|
+
const warnings = [];
|
|
42
|
+
|
|
43
|
+
const detected = await detectSkillsDirFromAPI(ownerRepo);
|
|
44
|
+
if (!detected) {
|
|
45
|
+
return { ok: false, errors: [`No skills directory found in ${ownerRepo}`], warnings: [] };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const subdir = detected.subdir;
|
|
49
|
+
const listUrl = `https://api.github.com/repos/${ownerRepo}/contents/${subdir}`;
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
const json = await httpsGet(listUrl);
|
|
53
|
+
entries = JSON.parse(json);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
return { ok: false, errors: [`Failed to list ${subdir}/ contents: ${e.message}`], warnings: [] };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const mdFiles = entries.filter(e => e.type === 'file' && e.name.endsWith('.md'));
|
|
59
|
+
if (mdFiles.length === 0) {
|
|
60
|
+
return { ok: false, errors: [`No .md files found in ${subdir}/`], warnings: [] };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const tmpDir = path.join(PROMPTGRAPH_DIR, '.validate-tmp');
|
|
64
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
65
|
+
|
|
66
|
+
for (const file of mdFiles) {
|
|
67
|
+
try {
|
|
68
|
+
const content = await httpsGet(file.download_url);
|
|
69
|
+
const tmpPath = path.join(tmpDir, file.name);
|
|
70
|
+
fs.writeFileSync(tmpPath, content);
|
|
71
|
+
const result = validateSkill(tmpPath);
|
|
72
|
+
if (!result.ok) {
|
|
73
|
+
errors.push(`${file.name}: ${result.errors.join('; ')}`);
|
|
74
|
+
}
|
|
75
|
+
if (result.warnings?.length) {
|
|
76
|
+
warnings.push(...result.warnings.map(w => `${file.name}: ${w}`));
|
|
77
|
+
}
|
|
78
|
+
fs.unlinkSync(tmpPath);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
errors.push(`${file.name}: failed to validate — ${e.message}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
|
85
|
+
|
|
86
|
+
return { ok: errors.length === 0, errors, warnings };
|
|
87
|
+
}
|
|
88
|
+
|
|
36
89
|
// Ask GitHub API which subdir to use (without cloning anything). Exported for validation.
|
|
37
90
|
export
|
|
38
91
|
// Returns { subdir, label } or null (use root).
|
package/marketplace.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createRequire } from 'module';
|
|
|
7
7
|
import { getDb } from './db.js';
|
|
8
8
|
import { validateSkill, validateBundle } from './validator.js';
|
|
9
9
|
import { loadConfig, saveConfig, PROMPTGRAPH_DIR, SKILLS_STORE_DIR } from './config.js';
|
|
10
|
-
import { importFromGitHub } from './github-import.js';
|
|
10
|
+
import { importFromGitHub, validateRepoSkills } from './github-import.js';
|
|
11
11
|
|
|
12
12
|
const REGISTRY_URL = 'https://raw.githubusercontent.com/NeiP4n/promptgraph-registry/main/registry.json';
|
|
13
13
|
const SKILLS_DIR = path.join(SKILLS_STORE_DIR, 'marketplace');
|
|
@@ -316,6 +316,19 @@ export async function publishBundle(bundleDef) {
|
|
|
316
316
|
return { error: 'Bundle validation failed', issues: validation.errors, warnings: validation.warnings };
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
// Validate repo skills content if repo_url is set
|
|
320
|
+
if (def.repo_url) {
|
|
321
|
+
const ownerRepo = def.repo_url.replace(/^https?:\/\/github\.com\//, '').replace(/\.git$/, '');
|
|
322
|
+
const repoValidation = await validateRepoSkills(ownerRepo);
|
|
323
|
+
if (!repoValidation.ok) {
|
|
324
|
+
return {
|
|
325
|
+
error: 'Repo skills validation failed',
|
|
326
|
+
issues: repoValidation.errors,
|
|
327
|
+
warnings: repoValidation.warnings,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
319
332
|
const bundleJson = JSON.stringify(def, null, 2);
|
|
320
333
|
const tmpFile = path.join(PROMPTGRAPH_DIR, `bundle-${def.id}.json`);
|
|
321
334
|
fs.mkdirSync(PROMPTGRAPH_DIR, { recursive: true });
|