promptgraph-mcp 2.2.6 → 2.2.8
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/index.js +91 -18
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -34,6 +34,7 @@ function showHelp() {
|
|
|
34
34
|
['import <owner/repo>', 'Import skills from GitHub'],
|
|
35
35
|
['status', 'Show installed skills, repos, and bundles'],
|
|
36
36
|
['marketplace', 'Interactive TUI: browse + search + install skills & bundles'],
|
|
37
|
+
['bundle update [id]', 'Update all (or one) installed GitHub bundles'],
|
|
37
38
|
['validate <file.md>', 'Validate a skill before publishing'],
|
|
38
39
|
['doctor', 'Clean orphaned chunks/edges/ratings'],
|
|
39
40
|
['update', 'Update to the latest version from npm'],
|
|
@@ -208,35 +209,38 @@ if (args[0] === 'marketplace') {
|
|
|
208
209
|
|
|
209
210
|
if (skills?.error) { error(skills.error); process.exit(1); }
|
|
210
211
|
|
|
211
|
-
// Build installed set
|
|
212
|
+
// Build installed set — source of truth is the FILESYSTEM, not DB/config
|
|
212
213
|
const installedSet = new Set();
|
|
213
214
|
try {
|
|
214
215
|
const cfg = _lcMkt();
|
|
215
216
|
const db = _getDbMkt();
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const dbSkillIds = new Set(db.prepare('SELECT id FROM skills').all().map(r => r.id));
|
|
219
|
-
|
|
220
|
-
// Build set of cloned repo names from config sources (exact: github:owner-repo)
|
|
221
|
-
const githubSources = new Set(
|
|
222
|
-
cfg.sources.filter(s => s.source.startsWith('github:')).map(s => s.source.replace('github:', '').toLowerCase())
|
|
223
|
-
);
|
|
217
|
+
const { SKILLS_STORE_DIR } = await import('./config.js');
|
|
218
|
+
const githubDir = path.join(SKILLS_STORE_DIR, 'github');
|
|
224
219
|
|
|
225
220
|
for (const b of (Array.isArray(bundles) ? bundles : [])) {
|
|
226
221
|
if (b.repo_url) {
|
|
227
|
-
//
|
|
228
|
-
const
|
|
229
|
-
|
|
222
|
+
// Check actual cloned directory exists and has files
|
|
223
|
+
const owner = b.repo_url.split('/')[0];
|
|
224
|
+
const repo = b.repo_url.split('/')[1];
|
|
225
|
+
const clonedName = `${owner}-${repo}`;
|
|
226
|
+
const clonedDir = path.join(githubDir, clonedName);
|
|
227
|
+
const dirExists = fs.existsSync(clonedDir) &&
|
|
228
|
+
fs.readdirSync(clonedDir).length > 0; // not empty
|
|
229
|
+
if (dirExists) installedSet.add(b.id);
|
|
230
230
|
} else if (Array.isArray(b.skills)) {
|
|
231
|
-
// skill-list bundle:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
231
|
+
// skill-list bundle: check files exist on disk via DB path column
|
|
232
|
+
const allOnDisk = b.skills.every(sid => {
|
|
233
|
+
const row = db.prepare('SELECT path FROM skills WHERE id = ?').get(sid);
|
|
234
|
+
return row && fs.existsSync(row.path);
|
|
235
|
+
});
|
|
236
|
+
if (b.skills.length > 0 && allOnDisk) installedSet.add(b.id);
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
239
|
|
|
238
|
-
// Individual skills
|
|
239
|
-
for (const
|
|
240
|
+
// Individual marketplace skills — check file exists on disk
|
|
241
|
+
for (const row of db.prepare('SELECT id, path FROM skills WHERE source = ?').all('marketplace')) {
|
|
242
|
+
if (fs.existsSync(row.path)) installedSet.add(row.id);
|
|
243
|
+
}
|
|
240
244
|
} catch {}
|
|
241
245
|
|
|
242
246
|
const { runTUI } = await import('./tui.js');
|
|
@@ -326,6 +330,75 @@ if (args[0] === 'search') {
|
|
|
326
330
|
}
|
|
327
331
|
|
|
328
332
|
if (args[0] === 'bundle') {
|
|
333
|
+
if (args[1] === 'update') {
|
|
334
|
+
const { loadConfig: _lcUpd, SKILLS_STORE_DIR: _ssDir } = await import('./config.js');
|
|
335
|
+
const { indexSource } = await import('./indexer.js');
|
|
336
|
+
const cfg = _lcUpd();
|
|
337
|
+
const githubSources = cfg.sources.filter(s => s.source.startsWith('github:'));
|
|
338
|
+
|
|
339
|
+
if (!githubSources.length) { info('No GitHub bundles installed.'); process.exit(0); }
|
|
340
|
+
|
|
341
|
+
const targetId = args[2]; // optional: pg bundle update <id>
|
|
342
|
+
const toUpdate = targetId
|
|
343
|
+
? githubSources.filter(s => s.source.toLowerCase().includes(targetId.toLowerCase()))
|
|
344
|
+
: githubSources;
|
|
345
|
+
|
|
346
|
+
if (!toUpdate.length) { error(`No installed bundle matching "${targetId}"`); process.exit(1); }
|
|
347
|
+
|
|
348
|
+
let updated = 0, unchanged = 0, failed = 0;
|
|
349
|
+
|
|
350
|
+
for (const src of toUpdate) {
|
|
351
|
+
const repoName = src.source.replace('github:', '');
|
|
352
|
+
const dest = src.dir.replace(/[/\\]skills$|[/\\]commands$|[/\\]prompts$/, ''); // get repo root
|
|
353
|
+
const repoRoot = fs.existsSync(path.join(dest, '.git')) ? dest : src.dir;
|
|
354
|
+
|
|
355
|
+
if (!fs.existsSync(path.join(repoRoot, '.git'))) {
|
|
356
|
+
console.log(chalk.gray(` skip ${repoName} (not a git repo)`));
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
process.stdout.write(` Checking ${chalk.white(repoName)}... `);
|
|
361
|
+
|
|
362
|
+
// Get current HEAD hash
|
|
363
|
+
const before = spawnSync('git', ['-C', repoRoot, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim();
|
|
364
|
+
|
|
365
|
+
// Fetch + reset (same as install)
|
|
366
|
+
const fetch = spawnSync('git', ['-C', repoRoot, 'fetch', '--depth=1', 'origin'], { stdio: 'pipe' });
|
|
367
|
+
if (fetch.status !== 0) {
|
|
368
|
+
console.log(chalk.red('fetch failed'));
|
|
369
|
+
failed++;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const reset = spawnSync('git', ['-C', repoRoot, 'reset', '--hard', 'origin/HEAD'], { stdio: 'pipe' });
|
|
373
|
+
if (reset.status !== 0) {
|
|
374
|
+
spawnSync('git', ['-C', repoRoot, 'reset', '--hard', 'origin/main'], { stdio: 'pipe' });
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const after = spawnSync('git', ['-C', repoRoot, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).stdout.trim();
|
|
378
|
+
|
|
379
|
+
if (before === after) {
|
|
380
|
+
console.log(chalk.gray('already up to date'));
|
|
381
|
+
unchanged++;
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Count changed .md files
|
|
386
|
+
const diff = spawnSync('git', ['-C', repoRoot, 'diff', '--name-only', before, after], { encoding: 'utf8' });
|
|
387
|
+
const changedMd = (diff.stdout || '').split('\n').filter(f => f.endsWith('.md')).length;
|
|
388
|
+
console.log(chalk.green(`${changedMd} files changed`) + chalk.gray(` (${before.slice(0,7)} → ${after.slice(0,7)})`));
|
|
389
|
+
|
|
390
|
+
// Reindex only this source — incremental hash check skips unchanged files
|
|
391
|
+
await indexSource(src.dir, src.source);
|
|
392
|
+
updated++;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
console.log();
|
|
396
|
+
if (updated) success(`Updated ${updated} bundle(s)`);
|
|
397
|
+
if (unchanged) info(chalk.gray(`${unchanged} already up to date`));
|
|
398
|
+
if (failed) error(`${failed} failed`);
|
|
399
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
400
|
+
}
|
|
401
|
+
|
|
329
402
|
if (args[1] === 'install') {
|
|
330
403
|
const { installBundle } = await import('./marketplace.js');
|
|
331
404
|
const result = await installBundle(args[2]);
|