promptgraph-mcp 2.3.1 → 2.3.3
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 +32 -8
- package/package.json +1 -1
- package/parser.js +1 -1
package/github-import.js
CHANGED
|
@@ -33,19 +33,42 @@ function repoExists(ownerRepo) {
|
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
// Ask GitHub API which
|
|
36
|
+
// Ask GitHub API which subdir to use (without cloning anything).
|
|
37
|
+
// Returns { subdir, label } or null (use root).
|
|
37
38
|
async function detectSkillsDirFromAPI(ownerRepo) {
|
|
38
39
|
try {
|
|
39
40
|
const json = await httpsGet(`https://api.github.com/repos/${ownerRepo}/contents`);
|
|
40
41
|
const entries = JSON.parse(json);
|
|
41
|
-
|
|
42
|
+
|
|
43
|
+
// 1. Known skill dir names (priority order)
|
|
44
|
+
const dirMap = new Map(entries.filter(e => e.type === 'dir').map(e => [e.name.toLowerCase(), e.name]));
|
|
42
45
|
for (const d of SKILL_DIRS) {
|
|
43
|
-
if (
|
|
46
|
+
if (dirMap.has(d)) return { subdir: dirMap.get(d), label: d };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 2. Any subdir with 2+ .md files — pick the one with most .md files
|
|
50
|
+
const subdirCandidates = entries.filter(e => e.type === 'dir' && !SKIP_DIRS_API.has(e.name.toLowerCase()));
|
|
51
|
+
let best = null, bestCount = 0;
|
|
52
|
+
for (const dir of subdirCandidates) {
|
|
53
|
+
try {
|
|
54
|
+
const sub = await httpsGet(`https://api.github.com/repos/${ownerRepo}/contents/${dir.name}`);
|
|
55
|
+
const subEntries = JSON.parse(sub);
|
|
56
|
+
const mdCount = subEntries.filter(e => e.type === 'file' && e.name.endsWith('.md')).length;
|
|
57
|
+
if (mdCount >= 2 && mdCount > bestCount) { best = dir.name; bestCount = mdCount; }
|
|
58
|
+
} catch {}
|
|
44
59
|
}
|
|
60
|
+
if (best) return { subdir: best, label: best };
|
|
61
|
+
|
|
45
62
|
} catch {}
|
|
46
|
-
return null; // use
|
|
63
|
+
return null; // no good subdir found — use root
|
|
47
64
|
}
|
|
48
65
|
|
|
66
|
+
const SKIP_DIRS_API = new Set([
|
|
67
|
+
'.github', 'docs', 'doc', 'documentation', 'examples', 'example',
|
|
68
|
+
'tests', 'test', 'assets', 'images', 'img', 'media', 'static',
|
|
69
|
+
'node_modules', 'vendor', 'dist', 'build', '.git',
|
|
70
|
+
]);
|
|
71
|
+
|
|
49
72
|
function git(args, cwd, stdio = 'inherit') {
|
|
50
73
|
return spawnSync('git', args, { cwd, stdio });
|
|
51
74
|
}
|
|
@@ -142,21 +165,22 @@ export async function importFromGitHub(repoUrl) {
|
|
|
142
165
|
|
|
143
166
|
if (isNew) {
|
|
144
167
|
// Detect skills dir via API before cloning
|
|
145
|
-
|
|
146
|
-
|
|
168
|
+
process.stdout.write(`Detecting skills directory for ${ownerRepo}... `);
|
|
169
|
+
const detected = await detectSkillsDirFromAPI(ownerRepo);
|
|
170
|
+
skillsSubdir = detected?.subdir || null;
|
|
147
171
|
|
|
148
172
|
if (skillsSubdir) {
|
|
173
|
+
console.log(`found: ${detected.label}/`);
|
|
149
174
|
console.log(`Sparse-cloning ${url} (${skillsSubdir}/ only)...`);
|
|
150
175
|
cloneOk = sparseClone(url, dest, skillsSubdir);
|
|
151
176
|
if (!cloneOk) {
|
|
152
|
-
// Sparse failed — fall back to full clone
|
|
153
177
|
console.log('Sparse-checkout failed, falling back to full clone...');
|
|
154
178
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
155
179
|
cloneOk = fullClone(url, dest);
|
|
156
180
|
skillsSubdir = null;
|
|
157
181
|
}
|
|
158
182
|
} else {
|
|
159
|
-
console.log(`
|
|
183
|
+
console.log(`no subdir found, cloning root...`);
|
|
160
184
|
cloneOk = fullClone(url, dest);
|
|
161
185
|
}
|
|
162
186
|
|
package/package.json
CHANGED
package/parser.js
CHANGED
|
@@ -19,7 +19,7 @@ const SKIP_FILENAMES = new Set([
|
|
|
19
19
|
]);
|
|
20
20
|
|
|
21
21
|
// Filename patterns that are never skills
|
|
22
|
-
const SKIP_FILENAME_RE = /^(_|\.)|^v?\d+[\.\-]\d+|^\d{4}[\-_]\d{2}/i;
|
|
22
|
+
const SKIP_FILENAME_RE = /^(_|\.)|^v?\d+[\.\-]\d+|^\d{4}[\-_]\d{2}|^readme|^license|^changelog|^contributing/i;
|
|
23
23
|
|
|
24
24
|
// Path segments that indicate the file is NOT a skill
|
|
25
25
|
const SKIP_DIRS = new Set([
|