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.
- package/cli.js +95 -0
- package/index.js +40 -34
- package/indexer.js +14 -6
- 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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
17
|
+
const args = process.argv.slice(2);
|
|
28
18
|
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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) {
|
|
57
|
+
if (!platform) { error(`Unknown platform: ${platformId}`); process.exit(1); }
|
|
50
58
|
platform.addMcp(platform);
|
|
51
|
-
|
|
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(
|
|
61
|
-
console.log(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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 %
|
|
97
|
-
const
|
|
98
|
-
|
|
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
|
-
|
|
125
|
+
progress(total, total, 'done');
|
|
126
|
+
console.log();
|
|
127
|
+
const spin = spinner('Building ANN index...');
|
|
128
|
+
spin.start();
|
|
124
129
|
await buildAnnIndex();
|
|
125
|
-
|
|
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.
|
|
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
|
}
|