promptgraph-mcp 2.9.9 → 2.9.11
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/README.md +27 -0
- package/index.js +9 -1
- package/marketplace.js +14 -2
- package/package.json +1 -1
- package/tui.js +19 -12
package/README.md
CHANGED
|
@@ -9,6 +9,33 @@ Instead of loading every `.md` skill into context, Claude calls `pg_search` and
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
**Requirements:** Node.js 18+ — [nodejs.org](https://nodejs.org)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g promptgraph-mcp@latest
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Check version:
|
|
21
|
+
```bash
|
|
22
|
+
pg --version
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Update to latest:
|
|
26
|
+
```bash
|
|
27
|
+
pg update
|
|
28
|
+
# or
|
|
29
|
+
npm install -g promptgraph-mcp@latest
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Uninstall:
|
|
33
|
+
```bash
|
|
34
|
+
npm uninstall -g promptgraph-mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
12
39
|
## Quick Start
|
|
13
40
|
|
|
14
41
|
```bash
|
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@ const args = process.argv.slice(2);
|
|
|
18
18
|
const rawBin = process.argv[1]?.split(/[\\/]/).pop()?.replace(/\.js$/, '');
|
|
19
19
|
const bin = (rawBin && rawBin !== 'index') ? rawBin : 'pg';
|
|
20
20
|
|
|
21
|
-
const KNOWN_COMMANDS = new Set(['init', 'reindex', 'update', 'import', 'install', 'setup', 'validate', 'marketplace', 'doctor', 'search', 'help', '--help', '-h', 'bundle', 'status', 'train']);
|
|
21
|
+
const KNOWN_COMMANDS = new Set(['init', 'reindex', 'update', 'import', 'install', 'setup', 'validate', 'marketplace', 'doctor', 'search', 'help', '--help', '-h', '--version', '-v', 'version', 'bundle', 'status', 'train']);
|
|
22
22
|
|
|
23
23
|
function showHelp() {
|
|
24
24
|
console.log(
|
|
@@ -57,6 +57,14 @@ if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
|
|
|
57
57
|
process.exit(0);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// Version flag
|
|
61
|
+
if (args[0] === '--version' || args[0] === '-v' || args[0] === 'version') {
|
|
62
|
+
const { createRequire } = await import('module');
|
|
63
|
+
const _pkg = createRequire(import.meta.url)('./package.json');
|
|
64
|
+
console.log(_pkg.version);
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
|
|
60
68
|
// No args: if launched from an interactive terminal, show help.
|
|
61
69
|
// If stdin is a pipe (i.e. an MCP client like Claude), fall through and
|
|
62
70
|
// start the server — NEVER print to stdout here, it corrupts JSON-RPC.
|
package/marketplace.js
CHANGED
|
@@ -359,9 +359,21 @@ async function _findBundle(bundleId) {
|
|
|
359
359
|
const text = await fetchText(REGISTRY_URL);
|
|
360
360
|
const registry = JSON.parse(text);
|
|
361
361
|
const q = String(bundleId).trim().toLowerCase();
|
|
362
|
+
const valid = (registry.bundles || []).filter(b => validateRegistryEntry(b).ok);
|
|
362
363
|
const validSkills = (registry.skills || []).filter(s => validateRegistryEntry(s).ok);
|
|
363
|
-
|
|
364
|
-
|
|
364
|
+
// 1. Exact match (code, id, name)
|
|
365
|
+
let bundle = valid.find(b =>
|
|
366
|
+
(b.code || codeFor(b.id)).toLowerCase() === q ||
|
|
367
|
+
b.id?.toLowerCase() === q ||
|
|
368
|
+
b.name?.toLowerCase() === q
|
|
369
|
+
);
|
|
370
|
+
// 2. Partial name/id match (starts with)
|
|
371
|
+
if (!bundle) bundle = valid.find(b =>
|
|
372
|
+
b.name?.toLowerCase().startsWith(q) || b.id?.toLowerCase().startsWith(q)
|
|
373
|
+
);
|
|
374
|
+
// 3. Contains match
|
|
375
|
+
if (!bundle) bundle = valid.find(b =>
|
|
376
|
+
b.name?.toLowerCase().includes(q) || b.id?.toLowerCase().includes(q)
|
|
365
377
|
);
|
|
366
378
|
if (!bundle) return { error: `No bundle matching "${bundleId}"` };
|
|
367
379
|
return { bundle, validSkills };
|
package/package.json
CHANGED
package/tui.js
CHANGED
|
@@ -46,13 +46,11 @@ function truncate(s, n) {
|
|
|
46
46
|
|
|
47
47
|
function buildItems(skills, bundles) {
|
|
48
48
|
const items = [];
|
|
49
|
-
// skills
|
|
50
49
|
for (const s of skills) {
|
|
51
|
-
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 });
|
|
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 });
|
|
52
51
|
}
|
|
53
|
-
// bundles
|
|
54
52
|
for (const b of bundles) {
|
|
55
|
-
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 });
|
|
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 });
|
|
56
54
|
}
|
|
57
55
|
return items;
|
|
58
56
|
}
|
|
@@ -61,6 +59,11 @@ function filterItems(items, query, tab) {
|
|
|
61
59
|
let filtered = items;
|
|
62
60
|
if (tab === 'skills') filtered = items.filter(i => i.type === 'skill');
|
|
63
61
|
if (tab === 'bundles') filtered = items.filter(i => i.type === 'bundle');
|
|
62
|
+
if (tab === 'recent') {
|
|
63
|
+
filtered = items
|
|
64
|
+
.filter(i => i.created_at)
|
|
65
|
+
.sort((a, b) => (b.created_at > a.created_at ? 1 : b.created_at < a.created_at ? -1 : 0));
|
|
66
|
+
}
|
|
64
67
|
if (query) {
|
|
65
68
|
const q = query.toLowerCase();
|
|
66
69
|
filtered = filtered.filter(i =>
|
|
@@ -84,7 +87,7 @@ function render(state, installedSet = new Set()) {
|
|
|
84
87
|
const DATE_W = 8;
|
|
85
88
|
const DESC_W = cols - NAME_W - 28 - DATE_W;
|
|
86
89
|
|
|
87
|
-
const { items, cursor, scroll, query, searching, tab, status } = state;
|
|
90
|
+
const { items, allItems, cursor, scroll, query, searching, tab, status } = state;
|
|
88
91
|
const skills = items.filter(i => i.type === 'skill').length;
|
|
89
92
|
const bundles = items.filter(i => i.type === 'bundle').length;
|
|
90
93
|
|
|
@@ -93,7 +96,7 @@ function render(state, installedSet = new Set()) {
|
|
|
93
96
|
// ── header ─────────────────────────────────────────────────────────────────
|
|
94
97
|
// Row 1: title bar
|
|
95
98
|
const titleText = ' ◆ PromptGraph Marketplace';
|
|
96
|
-
const tabParts = ['all', 'skills', 'bundles'].map(t =>
|
|
99
|
+
const tabParts = ['all', 'skills', 'bundles', 'recent'].map(t =>
|
|
97
100
|
t === tab
|
|
98
101
|
? `\x1b[48;2;124;58;237m\x1b[97m ${t.toUpperCase()} \x1b[0m`
|
|
99
102
|
: dim(` ${t} `)
|
|
@@ -102,9 +105,12 @@ function render(state, installedSet = new Set()) {
|
|
|
102
105
|
write(titleLine + CLEAR_EOL + '\n');
|
|
103
106
|
|
|
104
107
|
// Row 2: counts
|
|
108
|
+
const recentCount = (allItems || items).filter(i => i.created_at).length;
|
|
105
109
|
const countLine = dim(' ') +
|
|
106
|
-
(tab
|
|
107
|
-
|
|
110
|
+
(tab === 'recent'
|
|
111
|
+
? chalk.yellow(`${items.length} recent`)
|
|
112
|
+
: (tab !== 'bundles' ? chalk.white(`${skills} skills`) + dim(' ') : '') +
|
|
113
|
+
(tab !== 'skills' ? chalk.blue(`${bundles} bundles`) : '')) +
|
|
108
114
|
(query ? dim(' · filter: ') + cyan(query) : '');
|
|
109
115
|
write(countLine + CLEAR_EOL + '\n');
|
|
110
116
|
|
|
@@ -137,8 +143,8 @@ function render(state, installedSet = new Set()) {
|
|
|
137
143
|
const bg = selected ? '\x1b[48;2;55;35;110m' : '';
|
|
138
144
|
const reset = '\x1b[0m';
|
|
139
145
|
|
|
140
|
-
// category header (
|
|
141
|
-
if (item.category !== lastCat) {
|
|
146
|
+
// category header (skip in recent tab — sorted by date, not category)
|
|
147
|
+
if (tab !== 'recent' && item.category !== lastCat) {
|
|
142
148
|
if (rendered >= LIST_ROWS) break;
|
|
143
149
|
const icon = CAT_ICON[item.category] || '📦';
|
|
144
150
|
write((selected ? bg : '') + ' ' + purple.bold(icon + ' ' + item.category) + reset + CLEAR_EOL + '\n');
|
|
@@ -185,7 +191,7 @@ function render(state, installedSet = new Set()) {
|
|
|
185
191
|
const instLabel = isInst
|
|
186
192
|
? green(' ✓ installed') + dim(' ') + dim('d') + chalk.red(' remove') + dim(' ')
|
|
187
193
|
: dim(' Enter') + chalk.white(' install') + dim(' ');
|
|
188
|
-
write(instLabel + dim('Tab') + '
|
|
194
|
+
write(instLabel + dim('Tab') + ' all/skills/bundles/recent ' + dim('/') + ' search ' + dim('q') + ' quit' + CLEAR_EOL + '\n');
|
|
189
195
|
const ghUrl = sel.repo_url ? chalk.hex('#3B82F6')(` ↗ github.com/${sel.repo_url}`) : '';
|
|
190
196
|
write(dim(` → pg ${installCmd}`) + ghUrl + CLEAR_EOL + '\n');
|
|
191
197
|
} else if (state.confirming) {
|
|
@@ -250,6 +256,7 @@ export async function runTUI(allSkills, allBundles, installFn, installedSet = ne
|
|
|
250
256
|
cursor: 0,
|
|
251
257
|
scroll: 0,
|
|
252
258
|
items: allItems,
|
|
259
|
+
allItems,
|
|
253
260
|
status: null,
|
|
254
261
|
};
|
|
255
262
|
|
|
@@ -342,7 +349,7 @@ export async function runTUI(allSkills, allBundles, installFn, installedSet = ne
|
|
|
342
349
|
}
|
|
343
350
|
|
|
344
351
|
if (key.name === 'tab') {
|
|
345
|
-
const tabs = ['all', 'skills', 'bundles'];
|
|
352
|
+
const tabs = ['all', 'skills', 'bundles', 'recent'];
|
|
346
353
|
state.tab = tabs[(tabs.indexOf(state.tab) + 1) % tabs.length];
|
|
347
354
|
state.cursor = 0;
|
|
348
355
|
state.scroll = 0;
|