promptgraph-mcp 1.4.0 → 1.5.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.
Files changed (4) hide show
  1. package/cli.js +95 -0
  2. package/index.js +40 -34
  3. package/indexer.js +14 -6
  4. package/package.json +4 -1
package/cli.js ADDED
@@ -0,0 +1,95 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import boxen from 'boxen';
4
+
5
+ export const colors = {
6
+ primary: chalk.hex('#7C3AED'),
7
+ success: chalk.hex('#10B981'),
8
+ warning: chalk.hex('#F59E0B'),
9
+ error: chalk.hex('#EF4444'),
10
+ muted: chalk.hex('#6B7280'),
11
+ white: chalk.white,
12
+ bold: chalk.bold,
13
+ };
14
+
15
+ export function banner() {
16
+ console.log(
17
+ boxen(
18
+ colors.primary.bold('PromptGraph') + ' ' + colors.muted('v' + (await getVersion())) + '\n' +
19
+ colors.muted('Semantic skill router for Claude Code'),
20
+ {
21
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
22
+ borderStyle: 'round',
23
+ borderColor: '#7C3AED',
24
+ dimBorder: true,
25
+ }
26
+ )
27
+ );
28
+ }
29
+
30
+ async function getVersion() {
31
+ try {
32
+ const { createRequire } = await import('module');
33
+ const require = createRequire(import.meta.url);
34
+ return require('./package.json').version;
35
+ } catch { return ''; }
36
+ }
37
+
38
+ export function spinner(text) {
39
+ return ora({
40
+ text: colors.muted(text),
41
+ spinner: 'dots',
42
+ color: 'magenta',
43
+ });
44
+ }
45
+
46
+ export function success(msg) {
47
+ console.log(colors.success('✓') + ' ' + msg);
48
+ }
49
+
50
+ export function error(msg) {
51
+ console.log(colors.error('✗') + ' ' + msg);
52
+ }
53
+
54
+ export function info(msg) {
55
+ console.log(colors.muted('·') + ' ' + msg);
56
+ }
57
+
58
+ export function section(title) {
59
+ console.log('\n' + colors.primary.bold(title));
60
+ }
61
+
62
+ export function progress(current, total, extra = '') {
63
+ const pct = Math.round(current / total * 100);
64
+ const bar = buildBar(pct);
65
+ process.stdout.write(
66
+ `\r ${bar} ${colors.white.bold(pct + '%')} ${colors.muted(current + '/' + total)} ${colors.muted(extra)} `
67
+ );
68
+ }
69
+
70
+ function buildBar(pct) {
71
+ const width = 20;
72
+ const filled = Math.round(pct / 100 * width);
73
+ const empty = width - filled;
74
+ return colors.primary('█'.repeat(filled)) + colors.muted('░'.repeat(empty));
75
+ }
76
+
77
+ export function table(rows) {
78
+ if (!rows.length) { info('No results'); return; }
79
+ const cols = Object.keys(rows[0]);
80
+ const widths = cols.map(c => Math.max(c.length, ...rows.map(r => String(r[c] ?? '').length)));
81
+ const header = cols.map((c, i) => colors.muted(c.toUpperCase().padEnd(widths[i]))).join(' ');
82
+ const divider = colors.muted(widths.map(w => '─'.repeat(w)).join(' '));
83
+ console.log('\n' + header);
84
+ console.log(divider);
85
+ for (const row of rows) {
86
+ const line = cols.map((c, i) => {
87
+ const val = String(row[c] ?? '');
88
+ if (c === 'score' || c === 'rating') return colors.primary(val.padEnd(widths[i]));
89
+ if (c === 'name') return colors.white.bold(val.padEnd(widths[i]));
90
+ return colors.muted(val.padEnd(widths[i]));
91
+ }).join(' ');
92
+ console.log(line);
93
+ }
94
+ console.log();
95
+ }
package/index.js CHANGED
@@ -10,25 +10,34 @@ import { importFromGitHub } from './github-import.js';
10
10
  import { detectPlatforms, PLATFORMS } from './platform.js';
11
11
  import { browseMarketplace, installSkill, publishSkill, getTopRated, recordUse, recordSuccess, recordFail } from './marketplace.js';
12
12
 
13
- const args = process.argv.slice(2);
14
-
15
- if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
16
- console.log(`
17
- PromptGraph — semantic skill router for Claude Code
18
-
19
- Usage:
20
- promptgraph-mcp init First-time setup + index all skills
21
- promptgraph-mcp reindex Re-index all skills
22
- promptgraph-mcp import <owner/repo> Import skills from GitHub repo
23
- promptgraph-mcp setup <platform> Register MCP in platform config
24
- promptgraph-mcp Start MCP server (used by Claude)
25
- promptgraph-mcp help Show this help
13
+ import { colors, banner, success, error, info, section, table } from './cli.js';
14
+ import boxen from 'boxen';
15
+ import chalk from 'chalk';
26
16
 
27
- Platforms: claude-code, claude-desktop, cline, codex, cursor, windsurf
17
+ const args = process.argv.slice(2);
28
18
 
29
- GitHub: https://github.com/NeiP4n/promptgraph
30
- npm: https://npmjs.com/package/promptgraph-mcp
31
- `);
19
+ if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h' || !args[0]) {
20
+ console.log(
21
+ boxen(
22
+ chalk.hex('#7C3AED').bold('PromptGraph') + '\n' +
23
+ chalk.gray('Semantic skill router for Claude Code'),
24
+ { padding: { top: 0, bottom: 0, left: 2, right: 2 }, borderStyle: 'round', borderColor: '#7C3AED', dimBorder: true }
25
+ )
26
+ );
27
+ console.log(chalk.gray('\nUsage:\n'));
28
+ const cmds = [
29
+ ['init', 'First-time setup + index all skills'],
30
+ ['reindex', 'Re-index all skills'],
31
+ ['import <owner/repo>', 'Import skills from GitHub'],
32
+ ['setup <platform>', 'Register MCP in platform config'],
33
+ ['help', 'Show this help'],
34
+ ];
35
+ for (const [cmd, desc] of cmds) {
36
+ console.log(' ' + chalk.hex('#7C3AED')('promptgraph-mcp ' + cmd.padEnd(22)) + chalk.gray(desc));
37
+ }
38
+ console.log(chalk.gray('\nPlatforms: claude-code, claude-desktop, cline, codex, cursor, windsurf'));
39
+ console.log(chalk.gray('\n github.com/NeiP4n/promptgraph · npmjs.com/package/promptgraph-mcp\n'));
40
+ if (!args[0]) process.exit(0);
32
41
  process.exit(0);
33
42
  }
34
43
 
@@ -40,37 +49,34 @@ if (args[0] === 'import') {
40
49
  if (args[0] === 'setup') {
41
50
  const platformId = args[1];
42
51
  if (!platformId) {
43
- const detected = detectPlatforms();
44
- console.log('Detected platforms:');
45
- detected.forEach(p => console.log(` - ${p.id}: ${p.name}`));
46
- console.log('\nUsage: promptgraph-mcp setup <platform-id>');
52
+ section('Detected platforms');
53
+ detectPlatforms().forEach(p => info(`${chalk.white(p.id.padEnd(16))} ${chalk.gray(p.name)}`));
54
+ console.log(chalk.gray('\n Usage: promptgraph-mcp setup <platform-id>\n'));
47
55
  } else {
48
56
  const platform = PLATFORMS[platformId];
49
- if (!platform) { console.error(`Unknown platform: ${platformId}`); process.exit(1); }
57
+ if (!platform) { error(`Unknown platform: ${platformId}`); process.exit(1); }
50
58
  platform.addMcp(platform);
51
- console.log(`✓ Registered promptgraph MCP in ${platform.name} (${platform.configPath})`);
59
+ success(`Registered in ${chalk.white(platform.name)}`);
60
+ info(chalk.gray(platform.configPath));
52
61
  }
53
62
  process.exit(0);
54
63
  }
55
64
 
56
65
  if (args[0] === 'init') {
57
66
  const config = await promptConfig();
58
- console.log('\nIndexing skills...');
59
67
  await indexAll();
60
- console.log('\nDone! Add to Claude Code settings.json:');
61
- console.log(JSON.stringify({
62
- mcpServers: {
63
- promptgraph: {
64
- command: 'npx',
65
- args: ['promptgraph-mcp'],
66
- }
67
- }
68
- }, null, 2));
68
+ console.log();
69
+ console.log(
70
+ boxen(
71
+ chalk.white.bold('Add to Claude Code settings.json:') + '\n\n' +
72
+ chalk.gray(JSON.stringify({ mcpServers: { promptgraph: { command: 'npx', args: ['promptgraph-mcp'] } } }, null, 2)),
73
+ { padding: 1, borderStyle: 'round', borderColor: '#7C3AED', dimBorder: true }
74
+ )
75
+ );
69
76
  process.exit(0);
70
77
  }
71
78
 
72
79
  if (args[0] === 'reindex') {
73
- console.log('[PromptGraph] Reindexing...');
74
80
  await indexAll();
75
81
  process.exit(0);
76
82
  }
package/indexer.js CHANGED
@@ -7,6 +7,8 @@ import { getDb, skillId } from './db.js';
7
7
  import { loadConfig } from './config.js';
8
8
  import { chunkText } from './chunker.js';
9
9
  import { buildAnnIndex } from './ann.js';
10
+ import { progress, success, info, spinner } from './cli.js';
11
+ import chalk from 'chalk';
10
12
 
11
13
  function fileHash(filePath) {
12
14
  const content = fs.readFileSync(filePath);
@@ -74,7 +76,7 @@ export async function indexAll() {
74
76
  files.forEach(f => allFiles.push({ file: f, source }));
75
77
  total += files.length;
76
78
  }
77
- console.log(` Total files: ${total}`);
79
+ info(`Found ${chalk.white.bold(total)} files`);
78
80
 
79
81
  let count = 0;
80
82
  let errors = 0;
@@ -93,9 +95,9 @@ export async function indexAll() {
93
95
  if (existing?.hash === hash) {
94
96
  skipped++;
95
97
  count++;
96
- if (count % 100 === 0) {
97
- const pct = Math.round(count / total * 100);
98
- process.stdout.write(`\r [${pct}%] ${count}/${total} | skipped: ${skipped} | errors: ${errors} `);
98
+ if (count % 50 === 0) {
99
+ const eta = count > 0 ? Math.round((total - count) * (Date.now() - start) / count / 1000) : '?';
100
+ progress(count, total, `skipped: ${skipped} eta: ${eta}s`);
99
101
  }
100
102
  continue;
101
103
  }
@@ -120,9 +122,15 @@ export async function indexAll() {
120
122
  count += batch.length;
121
123
  }
122
124
 
123
- process.stdout.write('\r Building ANN index...');
125
+ progress(total, total, 'done');
126
+ console.log();
127
+ const spin = spinner('Building ANN index...');
128
+ spin.start();
124
129
  await buildAnnIndex();
125
- console.log(`\n Done. ${count} skills indexed.`);
130
+ spin.stop();
131
+ success(`Indexed ${chalk.white.bold(count)} skills ${chalk.gray(`(${errors} errors, ${skipped} skipped)`)}`);
132
+ const elapsed = ((Date.now() - start) / 1000).toFixed(1);
133
+ info(chalk.gray(`Time: ${elapsed}s`));
126
134
  }
127
135
 
128
136
  export async function indexFile(filePath, source) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,10 +34,13 @@
34
34
  "dependencies": {
35
35
  "@modelcontextprotocol/sdk": "^1.29.0",
36
36
  "better-sqlite3": "^12.10.0",
37
+ "boxen": "^8.0.1",
38
+ "chalk": "^5.6.2",
37
39
  "chokidar": "^5.0.0",
38
40
  "fastembed": "^2.1.0",
39
41
  "glob": "^13.0.6",
40
42
  "gray-matter": "^4.0.3",
43
+ "ora": "^9.4.0",
41
44
  "vectra": "^0.15.0"
42
45
  }
43
46
  }