promptgraph-mcp 2.0.9 → 2.1.0

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
@@ -4,7 +4,7 @@ import os from 'os';
4
4
  import fs from 'fs';
5
5
  import https from 'https';
6
6
  import { globSync } from 'glob';
7
- import { indexAll } from './indexer.js';
7
+ import { indexAll, indexSource } from './indexer.js';
8
8
  import { loadConfig, saveConfig, SKILLS_STORE_DIR } from './config.js';
9
9
 
10
10
  function repoExists(repoUrl) {
@@ -99,7 +99,7 @@ export async function importFromGitHub(repoUrl) {
99
99
  console.log(`Indexing from: ${skillsDir}`);
100
100
  }
101
101
 
102
- console.log('\nReindexing...');
103
- await indexAll();
102
+ console.log();
103
+ await indexSource(skillsDir, repoSource);
104
104
  console.log(`Done! Imported from ${repoName}/${label}`);
105
105
  }
package/indexer.js CHANGED
@@ -200,6 +200,58 @@ export async function indexAll() {
200
200
 
201
201
  export async function indexFile(filePath, source) {
202
202
  const db = getDb();
203
- const skill = parseSkillFile(filePath, source);
204
- await indexBatch(db, [{ ...skill, hash: fileHash(filePath) }]);
203
+ const raw = fs.readFileSync(filePath, 'utf8');
204
+ const hash = createHash('md5').update(raw).digest('hex');
205
+ const skill = parseSkillFile(filePath, source, { raw });
206
+ await indexBatch(db, [{ ...skill, hash }]);
207
+ }
208
+
209
+ // Index only one source directory — much faster than indexAll after a bundle install
210
+ export async function indexSource(dir, sourceName) {
211
+ const db = getDb();
212
+ const files = globSync(`${dir}/**/*.md`);
213
+ const total = files.length;
214
+ info(`Indexing ${chalk.white.bold(total)} files from ${sourceName}...`);
215
+
216
+ const dbByPath = new Map();
217
+ for (const row of db.prepare('SELECT id, path, hash FROM skills WHERE source = ?').all(sourceName)) {
218
+ dbByPath.set(row.path, row);
219
+ }
220
+
221
+ // Remove skills from this source whose files are gone
222
+ const existingPaths = new Set(files.map(f => path.resolve(f)));
223
+ for (const [, row] of dbByPath) {
224
+ if (!existingPaths.has(path.resolve(row.path))) {
225
+ db.prepare('DELETE FROM skills WHERE id = ?').run(row.id);
226
+ db.prepare('DELETE FROM chunks WHERE skill_id = ?').run(row.id);
227
+ db.prepare('DELETE FROM edges WHERE from_skill = ? OR to_skill = ?').run(row.id, row.id);
228
+ }
229
+ }
230
+
231
+ let count = 0, skipped = 0, errors = 0, batch = [];
232
+ const start = Date.now();
233
+
234
+ for (const file of files) {
235
+ try {
236
+ const raw = fs.readFileSync(file, 'utf8');
237
+ const hash = createHash('md5').update(raw).digest('hex');
238
+ const dbRow = dbByPath.get(file);
239
+ if (dbRow?.hash === hash) { skipped++; count++; continue; }
240
+ if (!isSkillFile(file, raw)) { skipped++; count++; continue; }
241
+ const parsed = parseSkillFile(file, sourceName, { raw });
242
+ batch.push({ ...parsed, hash });
243
+ if (batch.length >= BATCH_SIZE) {
244
+ await indexBatch(db, batch);
245
+ count += batch.length; batch = [];
246
+ progress(count, total, { skipped, errors });
247
+ }
248
+ } catch (e) { errors++; count++; }
249
+ }
250
+
251
+ if (batch.length > 0) { await indexBatch(db, batch); count += batch.length; }
252
+ progress(total, total, { skipped, errors });
253
+ progressDone();
254
+ await buildAnnIndex();
255
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
256
+ success(`Indexed ${chalk.white.bold(count)} skills from ${sourceName} ${chalk.gray(`(${skipped} skipped, ${elapsed}s)`)}`);
205
257
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.0.9",
3
+ "version": "2.1.0",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "bin": {