promptgraph-mcp 1.5.9 → 1.5.10
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/marketplace.js +36 -10
- package/package.json +1 -1
package/marketplace.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
+
import https from 'https';
|
|
4
5
|
import { spawnSync } from 'child_process';
|
|
5
6
|
import { getDb } from './db.js';
|
|
6
7
|
import { validateSkill } from './validator.js';
|
|
@@ -8,11 +9,39 @@ import { validateSkill } from './validator.js';
|
|
|
8
9
|
const REGISTRY_URL = 'https://raw.githubusercontent.com/NeiP4n/promptgraph-registry/main/registry.json';
|
|
9
10
|
const SKILLS_DIR = path.join(os.homedir(), '.claude', 'skills-store', 'marketplace');
|
|
10
11
|
|
|
12
|
+
// Robust fetch: try undici fetch, fall back to node:https (works where undici fails on Windows)
|
|
13
|
+
function httpGet(url) {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
https.get(url, { headers: { 'User-Agent': 'promptgraph-mcp' } }, (res) => {
|
|
16
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
17
|
+
return httpGet(res.headers.location).then(resolve, reject);
|
|
18
|
+
}
|
|
19
|
+
if (res.statusCode !== 200) {
|
|
20
|
+
res.resume();
|
|
21
|
+
return reject(new Error(`HTTP ${res.statusCode}`));
|
|
22
|
+
}
|
|
23
|
+
let data = '';
|
|
24
|
+
res.setEncoding('utf8');
|
|
25
|
+
res.on('data', c => data += c);
|
|
26
|
+
res.on('end', () => resolve(data));
|
|
27
|
+
}).on('error', reject);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function fetchText(url) {
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(url, { headers: { 'User-Agent': 'promptgraph-mcp' } });
|
|
34
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
35
|
+
return await res.text();
|
|
36
|
+
} catch {
|
|
37
|
+
return await httpGet(url);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
11
41
|
export async function browseMarketplace(topK = 20) {
|
|
12
42
|
try {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const registry = await res.json();
|
|
43
|
+
const text = await fetchText(REGISTRY_URL);
|
|
44
|
+
const registry = JSON.parse(text);
|
|
16
45
|
if (!Array.isArray(registry.skills)) return { error: 'Invalid registry format' };
|
|
17
46
|
return registry.skills
|
|
18
47
|
.sort((a, b) => (b.stars || 0) - (a.stars || 0))
|
|
@@ -24,9 +53,8 @@ export async function browseMarketplace(topK = 20) {
|
|
|
24
53
|
|
|
25
54
|
export async function installSkill(skillId) {
|
|
26
55
|
try {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const registry = await res.json();
|
|
56
|
+
const text = await fetchText(REGISTRY_URL);
|
|
57
|
+
const registry = JSON.parse(text);
|
|
30
58
|
const skill = registry.skills?.find(s => s.id === skillId);
|
|
31
59
|
if (!skill) return { error: `Skill "${skillId}" not found in registry` };
|
|
32
60
|
if (!skill.raw_url) return { error: `Skill "${skillId}" has no download URL` };
|
|
@@ -34,10 +62,8 @@ export async function installSkill(skillId) {
|
|
|
34
62
|
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
35
63
|
const dest = path.join(SKILLS_DIR, `${skillId}.md`);
|
|
36
64
|
|
|
37
|
-
const content = await
|
|
38
|
-
|
|
39
|
-
const text = await content.text();
|
|
40
|
-
fs.writeFileSync(dest, text);
|
|
65
|
+
const content = await fetchText(skill.raw_url);
|
|
66
|
+
fs.writeFileSync(dest, content);
|
|
41
67
|
|
|
42
68
|
return { success: true, path: dest, name: skill.name };
|
|
43
69
|
} catch (e) {
|