promptgraph-mcp 2.3.5 → 2.3.7

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.
Files changed (3) hide show
  1. package/github-import.js +33 -21
  2. package/package.json +1 -1
  3. package/tui.js +2 -1
package/github-import.js CHANGED
@@ -81,9 +81,9 @@ function sparseClone(url, dest, subdir) {
81
81
  if (git(['init'], dest, 'pipe').status !== 0) return false;
82
82
  if (git(['remote', 'add', 'origin', url], dest, 'pipe').status !== 0) return false;
83
83
 
84
- // 2. sparse-checkout config
85
- git(['sparse-checkout', 'init', '--cone'], dest, 'pipe');
86
- git(['sparse-checkout', 'set', subdir], dest, 'pipe');
84
+ // 2. sparse-checkout — non-cone mode with *.md glob
85
+ git(['sparse-checkout', 'init'], dest, 'pipe');
86
+ git(['sparse-checkout', 'set', '--no-cone', `${subdir}/*.md`, `${subdir}/**/*.md`], dest, 'pipe');
87
87
 
88
88
  // 3. fetch + checkout (depth=1, skip large blobs)
89
89
  const fetch = git(['fetch', '--depth=1', '--filter=blob:none', 'origin'], dest);
@@ -134,7 +134,7 @@ function sparseUpdate(dest, subdir) {
134
134
  if (fetch.status !== 0) return false;
135
135
 
136
136
  // Ensure sparse-checkout still set correctly
137
- git(['sparse-checkout', 'set', subdir], dest, 'pipe');
137
+ git(['sparse-checkout', 'set', '--no-cone', `${subdir}/*.md`, `${subdir}/**/*.md`], dest, 'pipe');
138
138
 
139
139
  for (const ref of ['origin/HEAD', 'origin/main', 'origin/master']) {
140
140
  const r = git(['reset', '--hard', ref], dest, 'pipe');
@@ -143,8 +143,7 @@ function sparseUpdate(dest, subdir) {
143
143
  return false;
144
144
  }
145
145
 
146
- // Fallback: full clone (when no subdir found)
147
- // --filter=blob:none skips large binaries (images, zips) — only fetches text files
146
+ // Fallback: clone root but only checkout .md files
148
147
  function fullClone(url, dest) {
149
148
  if (fs.existsSync(dest)) {
150
149
  const fetch = git(['fetch', '--depth=1', '--filter=blob:none', 'origin'], dest);
@@ -154,7 +153,19 @@ function fullClone(url, dest) {
154
153
  }
155
154
  return false;
156
155
  }
157
- return git(['clone', '--depth=1', '--filter=blob:none', url, dest]).status === 0;
156
+ // init + sparse *.md + fetch + checkout
157
+ fs.mkdirSync(dest, { recursive: true });
158
+ if (git(['init'], dest, 'pipe').status !== 0) return false;
159
+ if (git(['remote', 'add', 'origin', url], dest, 'pipe').status !== 0) return false;
160
+ git(['sparse-checkout', 'init'], dest, 'pipe');
161
+ git(['sparse-checkout', 'set', '--no-cone', '*.md', '**/*.md'], dest, 'pipe');
162
+ const fetch = git(['fetch', '--depth=1', '--filter=blob:none', 'origin'], dest);
163
+ if (fetch.status !== 0) return false;
164
+ for (const branch of ['FETCH_HEAD', 'main', 'master']) {
165
+ const r = git(['checkout', branch], dest, 'pipe');
166
+ if (r.status === 0) return true;
167
+ }
168
+ return false;
158
169
  }
159
170
 
160
171
  // After clone: detect actual skills dir on disk
@@ -200,20 +211,21 @@ export async function importFromGitHub(repoUrl) {
200
211
  const detected = await detectSkillsDirFromAPI(ownerRepo);
201
212
  skillsSubdir = detected?.subdir || null;
202
213
 
203
- if (skillsSubdir) {
204
- console.log(`found: ${detected.label}/`);
205
- console.log(`Sparse-cloning ${url} (${skillsSubdir}/ only)...`);
206
- cloneOk = sparseClone(url, dest, skillsSubdir);
207
- if (!cloneOk) {
208
- console.log('Sparse-checkout failed, falling back to full clone...');
209
- fs.rmSync(dest, { recursive: true, force: true });
210
- cloneOk = fullClone(url, dest);
211
- skillsSubdir = null;
212
- }
213
- } else {
214
- console.log(`no subdir found, cloning root...`);
215
- cloneOk = fullClone(url, dest);
216
- if (cloneOk) cleanupRepoRoot(dest);
214
+ if (!skillsSubdir) {
215
+ throw new Error(
216
+ `No skill subdirectory found in ${ownerRepo}.\n` +
217
+ `Expected one of: ${SKILL_DIRS.join(', ')}\n` +
218
+ `Or any subfolder with .md files.\n` +
219
+ `Visit https://github.com/${ownerRepo} to check the repo structure.`
220
+ );
221
+ }
222
+
223
+ console.log(`found: ${detected.label}/`);
224
+ console.log(`Sparse-cloning ${url} (${skillsSubdir}/ only)...`);
225
+ cloneOk = sparseClone(url, dest, skillsSubdir);
226
+ if (!cloneOk) {
227
+ fs.rmSync(dest, { recursive: true, force: true });
228
+ throw new Error(`Sparse-checkout failed for ${url}`);
217
229
  }
218
230
 
219
231
  if (!cloneOk) throw new Error(`Clone failed for ${url}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.3.5",
3
+ "version": "2.3.7",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "bin": {
package/tui.js CHANGED
@@ -178,7 +178,8 @@ function render(state, installedSet = new Set()) {
178
178
  ? green(' ✓ installed') + dim(' ') + dim('d') + chalk.red(' remove') + dim(' ')
179
179
  : dim(' Enter') + chalk.white(' install') + dim(' ');
180
180
  write(instLabel + dim('Tab') + ' switch ' + dim('/') + ' search ' + dim('q') + ' quit' + CLEAR_EOL + '\n');
181
- write(dim(` → pg ${installCmd}`) + CLEAR_EOL + '\n');
181
+ const ghUrl = sel.repo_url ? chalk.hex('#3B82F6')(` github.com/${sel.repo_url}`) : '';
182
+ write(dim(` → pg ${installCmd}`) + ghUrl + CLEAR_EOL + '\n');
182
183
  } else if (state.confirming) {
183
184
  write(chalk.red.bold(' Remove ') + chalk.white(state.confirming.name) + chalk.red('? ') +
184
185
  chalk.white.bold('[y]') + chalk.gray('es ') + chalk.white.bold('[n]') + chalk.gray('o') + CLEAR_EOL + '\n');