promptgraph-mcp 2.9.10 → 2.9.12

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 CHANGED
@@ -87,10 +87,18 @@ pg setup opencode
87
87
  **Option 2 — manual.** Add to `~/.config/opencode/opencode.json`:
88
88
  ```json
89
89
  {
90
- "plugin": ["promptgraph-mcp/plugin"]
90
+ "mcp": {
91
+ "promptgraph": {
92
+ "type": "local",
93
+ "command": ["cmd", "/c", "npx", "promptgraph-mcp"],
94
+ "enabled": true
95
+ }
96
+ }
91
97
  }
92
98
  ```
93
99
 
100
+ > **Linux/macOS:** use `"command": ["npx", "promptgraph-mcp"]` (without `cmd /c`).
101
+
94
102
  ### Other clients
95
103
 
96
104
  | Client | Command |
package/commands/init.js CHANGED
@@ -13,7 +13,7 @@ const PLATFORM_CONFIGS = {
13
13
  },
14
14
  'opencode': {
15
15
  label: 'OpenCode — opencode.json',
16
- snippet: { plugin: ['promptgraph-mcp/plugin'] },
16
+ snippet: { mcp: { promptgraph: { type: 'local', command: ['cmd', '/c', 'npx', 'promptgraph-mcp'], enabled: true } } },
17
17
  },
18
18
  'cursor': {
19
19
  label: 'Cursor — ~/.cursor/mcp.json',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.9.10",
3
+ "version": "2.9.12",
4
4
  "files": [
5
5
  "*.js",
6
6
  "commands/",
package/platform.js CHANGED
@@ -6,7 +6,9 @@ import { spawnSync } from 'child_process';
6
6
  const HOME = os.homedir();
7
7
 
8
8
  const STD_ENTRY = { command: 'npx', args: ['promptgraph-mcp'] };
9
- const OC_ENTRY = { type: 'local', command: ['npx', 'promptgraph-mcp'], enabled: true };
9
+ const OC_ENTRY = process.platform === 'win32'
10
+ ? { type: 'local', command: ['cmd', '/c', 'npx', 'promptgraph-mcp'], enabled: true }
11
+ : { type: 'local', command: ['npx', 'promptgraph-mcp'], enabled: true };
10
12
 
11
13
  // Shared helper: write standard mcpServers entry (Claude Code, Cursor, Windsurf, Codex format)
12
14
  function addStdMcp(configPath) {
@@ -26,14 +28,15 @@ function addClineMcp(configPath) {
26
28
  writeJson(configPath, json);
27
29
  }
28
30
 
29
- // OpenCode uses plugin array
31
+ // OpenCode uses mcp.promptgraph object
30
32
  function addOpenCodeMcp(configPath) {
31
33
  const json = readJson(configPath) || {};
32
- json.plugin = json.plugin || [];
33
- const entry = 'promptgraph-mcp/plugin';
34
- if (!json.plugin.includes(entry)) json.plugin.push(entry);
35
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
36
- writeJson(configPath, json);
34
+ json.mcp = json.mcp || {};
35
+ if (!json.mcp.promptgraph) {
36
+ json.mcp.promptgraph = OC_ENTRY;
37
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
38
+ writeJson(configPath, json);
39
+ }
37
40
  }
38
41
 
39
42
  export const PLATFORMS = {
@@ -100,7 +103,7 @@ function isOpenCodeInstalled() {
100
103
  function isClaudeCodeInstalled() { return isBinaryInstalled('claude'); }
101
104
 
102
105
  function getOpenCodeConfig() {
103
- if (process.platform === 'win32') return path.join(HOME, 'AppData', 'Roaming', 'opencode', 'opencode.json');
106
+ if (process.platform === 'win32') return path.join(HOME, '.config', 'opencode', 'opencode.json');
104
107
  if (process.platform === 'darwin') return path.join(HOME, 'Library', 'Application Support', 'opencode', 'opencode.json');
105
108
  return path.join(HOME, '.config', 'opencode', 'opencode.json');
106
109
  }
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 !== 'bundles' ? chalk.white(`${skills} skills`) + dim(' ') : '') +
107
- (tab !== 'skills' ? chalk.blue(`${bundles} bundles`) : '') +
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 (only when ungrouped / mixed)
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') + ' switch ' + dim('/') + ' search ' + dim('q') + ' quit' + CLEAR_EOL + '\n');
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;