promptgraph-mcp 2.9.33 → 2.9.35

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 CHANGED
@@ -253,9 +253,13 @@ function sparseClone(url, dest, subdir) {
253
253
  if (git(['init'], dest, 'pipe').status !== 0) return false;
254
254
  if (git(['remote', 'add', 'origin', url], dest, 'pipe').status !== 0) return false;
255
255
 
256
- // 2. sparse-checkout — non-cone mode with *.md glob
256
+ // 2. sparse-checkout — non-cone mode with *.md + script files
257
257
  git(['sparse-checkout', 'init'], dest, 'pipe');
258
- git(['sparse-checkout', 'set', '--no-cone', `${subdir}/*.md`, `${subdir}/**/*.md`], dest, 'pipe');
258
+ git(['sparse-checkout', 'set', '--no-cone',
259
+ `${subdir}/*.md`, `${subdir}/**/*.md`,
260
+ `${subdir}/**/*.py`, `${subdir}/**/*.sh`, `${subdir}/**/*.js`,
261
+ `${subdir}/**/*.ts`, `${subdir}/**/*.rb`, `${subdir}/**/*.bash`,
262
+ ], dest, 'pipe');
259
263
 
260
264
  // 3. fetch + checkout (depth=1, skip large blobs)
261
265
  const fetch = git(['fetch', '--depth=1', '--filter=blob:none', 'origin'], dest);
@@ -363,7 +367,11 @@ function sparseUpdate(dest, subdir) {
363
367
  const fetch = git(['fetch', '--depth=1', 'origin'], dest);
364
368
  if (fetch.status !== 0) return false;
365
369
 
366
- git(['sparse-checkout', 'set', '--no-cone', `${subdir}/*.md`, `${subdir}/**/*.md`], dest, 'pipe');
370
+ git(['sparse-checkout', 'set', '--no-cone',
371
+ `${subdir}/*.md`, `${subdir}/**/*.md`,
372
+ `${subdir}/**/*.py`, `${subdir}/**/*.sh`, `${subdir}/**/*.js`,
373
+ `${subdir}/**/*.ts`, `${subdir}/**/*.rb`, `${subdir}/**/*.bash`,
374
+ ], dest, 'pipe');
367
375
 
368
376
  for (const ref of ['origin/main', 'origin/master']) {
369
377
  const r = git(['checkout', ref], dest, 'pipe');
@@ -376,7 +384,17 @@ function sparseUpdate(dest, subdir) {
376
384
 
377
385
  // After checkout, force materialization of sparse-matched files.
378
386
  function finalizeCheckout(dest, success) {
379
- if (success) forceMaterialize(dest);
387
+ if (success) {
388
+ forceMaterialize(dest);
389
+ // Make scripts executable on unix
390
+ if (process.platform !== 'win32') {
391
+ const scriptExts = ['.py', '.sh', '.bash', '.rb'];
392
+ try {
393
+ const scripts = globSync(`${dest}/**/*{${scriptExts.join(',')}}`, { absolute: true });
394
+ for (const s of scripts) { try { fs.chmodSync(s, 0o755); } catch {} }
395
+ } catch {}
396
+ }
397
+ }
380
398
  return success;
381
399
  }
382
400
 
@@ -396,7 +414,10 @@ function fullClone(url, dest) {
396
414
  if (git(['init'], dest, 'pipe').status !== 0) return false;
397
415
  if (git(['remote', 'add', 'origin', url], dest, 'pipe').status !== 0) return false;
398
416
  git(['sparse-checkout', 'init'], dest, 'pipe');
399
- git(['sparse-checkout', 'set', '--no-cone', '*.md', '**/*.md'], dest, 'pipe');
417
+ git(['sparse-checkout', 'set', '--no-cone',
418
+ '*.md', '**/*.md',
419
+ '**/*.py', '**/*.sh', '**/*.js', '**/*.ts', '**/*.rb', '**/*.bash',
420
+ ], dest, 'pipe');
400
421
  const fetch = git(['fetch', '--depth=1', '--filter=blob:none', 'origin'], dest);
401
422
  if (fetch.status !== 0) return false;
402
423
  for (const branch of ['FETCH_HEAD', 'main', 'master']) {
package/index.js CHANGED
@@ -299,7 +299,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
299
299
  case 'pg_marketplace_install': result = await installSkill(args.skill_id); break;
300
300
  case 'pg_marketplace_publish': result = await publishSkill(args.file_path); break;
301
301
  case 'pg_bundle_browse': result = await browseBundles(args.top_k || 20); break;
302
- case 'pg_bundle_install': result = await installBundle(args.bundle_id); break;
302
+ case 'pg_bundle_install': {
303
+ result = await installBundle(args.bundle_id);
304
+ if (result.toolsInstalled?.length) {
305
+ result.message = `Installed ${result.installed?.length || 0} skills + ${result.toolsInstalled.length} tool files`;
306
+ }
307
+ break;
308
+ }
303
309
  case 'pg_install_url': result = await installSkillFromUrl(args.url); break;
304
310
  case 'pg_bundle_publish': result = await publishBundle(args.bundle); break;
305
311
  case 'pg_config': {
package/marketplace.js CHANGED
@@ -397,26 +397,47 @@ async function _execRepoInstall(bundle) {
397
397
  }
398
398
 
399
399
  async function _execSkillsInstall(bundle, validSkills) {
400
- fs.mkdirSync(getSkillsDir(), { recursive: true });
400
+ const skillsDir = getSkillsDir();
401
+ fs.mkdirSync(skillsDir, { recursive: true });
401
402
  ensureMarketplaceSource();
402
403
  const installed = [];
403
404
  const failed = [];
405
+ const toolsInstalled = [];
404
406
  const delay = (ms) => new Promise(r => setTimeout(r, ms));
407
+
405
408
  for (const skillId of bundle.skills || []) {
406
409
  const skill = validSkills.find(s => s.id === skillId);
407
410
  if (!skill?.raw_url) { failed.push(skillId); continue; }
408
411
  try {
409
412
  if (installed.length > 0) await delay(300);
410
413
  const content = await fetchText(skill.raw_url);
411
- const dest = path.join(getSkillsDir(), `${skillId}.md`);
412
- const resolvedDest = path.resolve(dest);
413
- if (!resolvedDest.startsWith(path.resolve(getSkillsDir()))) { failed.push(skillId); continue; }
414
+ const dest = path.join(skillsDir, `${skillId}.md`);
415
+ if (!path.resolve(dest).startsWith(path.resolve(skillsDir))) { failed.push(skillId); continue; }
414
416
  const v = writeSkillAtomic(dest, content);
415
417
  if (!v.ok) { failed.push(skillId); continue; }
416
418
  installed.push(skillId);
417
419
  } catch { failed.push(skillId); }
418
420
  }
419
- return { success: true, bundle: bundle.name, installed, failed, dir: getSkillsDir() };
421
+
422
+ // Install tool files if bundle has them (scripts, .py, .sh, .js etc)
423
+ for (const tool of bundle.tool_files || []) {
424
+ if (!tool?.raw_url || !tool?.path) continue;
425
+ try {
426
+ await delay(200);
427
+ const content = await fetchText(tool.raw_url);
428
+ const dest = path.join(skillsDir, tool.path);
429
+ if (!path.resolve(dest).startsWith(path.resolve(skillsDir))) continue;
430
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
431
+ fs.writeFileSync(dest, content);
432
+ // Make executable on unix
433
+ if (process.platform !== 'win32') {
434
+ try { fs.chmodSync(dest, 0o755); } catch {}
435
+ }
436
+ toolsInstalled.push(tool.path);
437
+ } catch {}
438
+ }
439
+
440
+ return { success: true, bundle: bundle.name, installed, failed, toolsInstalled, dir: skillsDir, has_tools: bundle.has_tools || false };
420
441
  }
421
442
 
422
443
  export async function installBundle(bundleId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.9.33",
3
+ "version": "2.9.35",
4
4
  "files": [
5
5
  "*.js",
6
6
  "commands/",
package/tui.js CHANGED
@@ -50,7 +50,7 @@ function buildItems(skills, bundles) {
50
50
  items.push({ type: 'skill', id: s.id, name: s.name || s.id, description: s.description || '', category: s.category || 'Community', tags: s.tags || [], stars: s.stars || 0, code: s.code, created_at: s.created_at || null });
51
51
  }
52
52
  for (const b of bundles) {
53
- items.push({ type: 'bundle', id: b.id, name: b.name || b.id, description: b.description || '', category: b.category || 'Community', tags: b.tags || [], stars: b.stars || 0, skillCount: b.skillCount, repo_url: b.repo_url, skills: b.skills, created_at: b.created_at || null });
53
+ items.push({ type: 'bundle', id: b.id, name: b.name || b.id, description: b.description || '', category: b.category || 'Community', tags: b.tags || [], stars: b.stars || 0, skillCount: b.skillCount, repo_url: b.repo_url, skills: b.skills, has_tools: b.has_tools || false, created_at: b.created_at || null });
54
54
  }
55
55
  return items;
56
56
  }
@@ -162,12 +162,13 @@ function render(state, installedSet = new Set()) {
162
162
  const namePad = nameStr.padEnd(NAME_W);
163
163
  const nameCol = selected ? white.bold(namePad) : white(namePad);
164
164
  const installed = installedSet.has(item.id) || installedSet.has(item.code);
165
+ const toolsBadge = item.has_tools ? chalk.hex('#F59E0B')(' 🔧') : '';
165
166
  const extra = item.type === 'bundle'
166
167
  ? item.skillCount
167
- ? blue(((installed ? '' : '~') + item.skillCount + ' sk').padEnd(8))
168
+ ? blue(((installed ? '' : '~') + item.skillCount + ' sk').padEnd(8)) + toolsBadge
168
169
  : item.repo_url
169
- ? chalk.hex('#3B82F6')('↗ GitHub')
170
- : dim(((item.skills?.length || 0) + ' sk').padEnd(8))
170
+ ? chalk.hex('#3B82F6')('↗ GitHub') + toolsBadge
171
+ : dim(((item.skills?.length || 0) + ' sk').padEnd(8)) + toolsBadge
171
172
  : chalk.hex('#A78BFA')((item.code || '').padEnd(10));
172
173
  const desc = dim(truncate(item.description, Math.max(10, DESC_W)));
173
174
  const dateStr = item.created_at ? dim(item.created_at.slice(0, 7)) : ' ';