promptgraph-mcp 2.2.1 → 2.2.3

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 (3) hide show
  1. package/index.js +18 -18
  2. package/package.json +1 -1
  3. package/tui.js +13 -14
package/index.js CHANGED
@@ -196,31 +196,31 @@ if (args[0] === 'marketplace') {
196
196
  const installedSet = new Set();
197
197
  try {
198
198
  const cfg = _lcMkt();
199
- for (const s of cfg.sources) {
200
- if (s.source.startsWith('github:')) installedSet.add(s.source.replace('github:', ''));
201
- if (s.source === 'marketplace') installedSet.add('marketplace');
202
- }
203
199
  const db = _getDbMkt();
204
- for (const row of db.prepare('SELECT id FROM skills').all()) installedSet.add(row.id);
205
- // Also add bundle IDs by matching repo names
200
+
201
+ // Collect installed skill IDs from DB
202
+ const dbSkillIds = new Set(db.prepare('SELECT id FROM skills').all().map(r => r.id));
203
+
204
+ // Build set of cloned repo names from config sources (exact: github:owner-repo)
205
+ const githubSources = new Set(
206
+ cfg.sources.filter(s => s.source.startsWith('github:')).map(s => s.source.replace('github:', '').toLowerCase())
207
+ );
208
+
206
209
  for (const b of (Array.isArray(bundles) ? bundles : [])) {
207
210
  if (b.repo_url) {
208
- const repoName = b.repo_url.split('/').join('-');
209
- if ([...installedSet].some(s => s.toLowerCase().includes(b.id.split('-').pop()))) {
210
- installedSet.add(b.id);
211
- }
212
- }
213
- }
214
- // match github sources to bundle ids
215
- for (const s of cfg.sources) {
216
- if (!s.source.startsWith('github:')) continue;
217
- const srcName = s.source.replace('github:', '').toLowerCase();
218
- for (const b of (Array.isArray(bundles) ? bundles : [])) {
219
- if (srcName.toLowerCase().includes(b.id.toLowerCase()) || b.id.toLowerCase().includes(srcName.split('-')[0])) {
211
+ // repo_url = "owner/repo" → cloned as "owner-repo" in github: source
212
+ const clonedName = b.repo_url.replace('/', '-').toLowerCase();
213
+ if (githubSources.has(clonedName)) installedSet.add(b.id);
214
+ } else if (Array.isArray(b.skills)) {
215
+ // skill-list bundle: installed if ALL skills are in DB
216
+ if (b.skills.length > 0 && b.skills.every(sid => dbSkillIds.has(sid))) {
220
217
  installedSet.add(b.id);
221
218
  }
222
219
  }
223
220
  }
221
+
222
+ // Individual skills
223
+ for (const id of dbSkillIds) installedSet.add(id);
224
224
  } catch {}
225
225
 
226
226
  const { runTUI } = await import('./tui.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "bin": {
package/tui.js CHANGED
@@ -75,7 +75,7 @@ function filterItems(items, query, tab) {
75
75
 
76
76
  function render(state, installedSet = new Set()) {
77
77
  const { cols, rows } = termSize();
78
- const HEADER_ROWS = 5;
78
+ const HEADER_ROWS = 4;
79
79
  const FOOTER_ROWS = 3;
80
80
  const LIST_ROWS = rows - HEADER_ROWS - FOOTER_ROWS;
81
81
  const NAME_W = Math.max(20, Math.floor(cols * 0.28));
@@ -85,7 +85,7 @@ function render(state, installedSet = new Set()) {
85
85
  const skills = items.filter(i => i.type === 'skill').length;
86
86
  const bundles = items.filter(i => i.type === 'bundle').length;
87
87
 
88
- write(HOME);
88
+ write('\x1b[H\x1b[J'); // go home + clear to end (no flicker vs full CLEAR)
89
89
 
90
90
  // ── header ─────────────────────────────────────────────────────────────────
91
91
  // Row 1: title bar
@@ -113,14 +113,13 @@ function render(state, installedSet = new Set()) {
113
113
  : dim(query ? query : 'type / to search, Tab to switch view');
114
114
  write(searchLabel + searchVal + CLEAR_EOL + '\n');
115
115
 
116
- // Row 4: status / separator
116
+ // Row 4: separator (with optional status inline)
117
117
  if (status) {
118
- const msg = status.ok ? green(' ' + status.msg) : red(' ' + status.msg);
119
- write(msg + CLEAR_EOL + '\n');
118
+ const msg = status.ok ? green(' ' + status.msg) : red(' ' + status.msg);
119
+ write(dim('─'.repeat(4)) + msg + CLEAR_EOL + '\n');
120
120
  } else {
121
121
  write(dim('─'.repeat(cols)) + CLEAR_EOL + '\n');
122
122
  }
123
- write(dim('─'.repeat(cols)) + CLEAR_EOL + '\n');
124
123
 
125
124
  // ── list ───────────────────────────────────────────────────────────────────
126
125
  let lastCat = null;
@@ -143,17 +142,19 @@ function render(state, installedSet = new Set()) {
143
142
  }
144
143
 
145
144
  // item row
146
- const isInstalled = item.type === 'bundle'
147
- ? installedSet.has(item.id) || installedSet.has(item.id.toLowerCase())
148
- : installedSet.has(item.id) || installedSet.has(item.code);
145
+ const isInstalled = installedSet.has(item.id) || (item.code && installedSet.has(item.code));
149
146
  const arrow = selected ? cyan('▶') : ' ';
150
147
  const type = item.type === 'bundle' ? blue('⊞') : dim('·');
151
148
  const badge = isInstalled ? green('✓') : ' ';
152
149
  const nameStr = truncate(item.name, NAME_W);
153
150
  const namePad = nameStr.padEnd(NAME_W);
154
151
  const nameCol = selected ? white.bold(namePad) : white(namePad);
155
- const extra = item.type === 'bundle'
156
- ? (item.skillCount ? blue((item.skillCount + ' sk').padEnd(8)) : blue('GitHub '))
152
+ const extra = item.type === 'bundle'
153
+ ? item.skillCount
154
+ ? blue((item.skillCount + ' sk').padEnd(8))
155
+ : item.repo_url
156
+ ? blue('GitHub ')
157
+ : dim(((item.skills?.length || 0) + ' sk').padEnd(8))
157
158
  : dim((item.code || '').padEnd(8));
158
159
  const desc = dim(truncate(item.description, Math.max(10, DESC_W)));
159
160
 
@@ -171,9 +172,7 @@ function render(state, installedSet = new Set()) {
171
172
  write(dim('─'.repeat(cols)) + CLEAR_EOL + '\n');
172
173
  const sel = items[cursor];
173
174
  if (sel && !searching) {
174
- const isInst = sel.type === 'bundle'
175
- ? installedSet.has(sel.id) || installedSet.has(sel.id.toLowerCase())
176
- : installedSet.has(sel.id) || installedSet.has(sel.code);
175
+ const isInst = installedSet.has(sel.id) || (sel.code && installedSet.has(sel.code));
177
176
  const installCmd = sel.type === 'bundle' ? `bundle install ${sel.id}` : `install ${sel.code || sel.id}`;
178
177
  const instLabel = isInst ? green(' ✓ installed') + dim(' ') : dim(' Enter') + chalk.white(' install') + dim(' ');
179
178
  write(instLabel + dim('Tab') + ' switch ' + dim('/') + ' search ' + dim('q') + ' quit' + CLEAR_EOL + '\n');