promptgraph-mcp 2.1.5 → 2.1.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/tui.js +50 -30
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.1.5",
3
+ "version": "2.1.6",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "bin": {
package/tui.js CHANGED
@@ -75,65 +75,85 @@ function filterItems(items, query, tab) {
75
75
 
76
76
  function render(state) {
77
77
  const { cols, rows } = termSize();
78
- const HEADER_ROWS = 4;
78
+ const HEADER_ROWS = 5;
79
79
  const FOOTER_ROWS = 3;
80
80
  const LIST_ROWS = rows - HEADER_ROWS - FOOTER_ROWS;
81
+ const NAME_W = Math.max(20, Math.floor(cols * 0.28));
82
+ const DESC_W = cols - NAME_W - 28;
81
83
 
82
84
  const { items, cursor, scroll, query, searching, tab, status } = state;
85
+ const skills = items.filter(i => i.type === 'skill').length;
86
+ const bundles = items.filter(i => i.type === 'bundle').length;
83
87
 
84
88
  write(HOME);
85
89
 
86
90
  // ── header ─────────────────────────────────────────────────────────────────
87
- const title = purple.bold(' ◆ PromptGraph Marketplace ');
88
- const tabs = ['all', 'skills', 'bundles'].map(t =>
89
- t === tab ? cyan.bold(`[${t}]`) : dim(`[${t}]`)
90
- ).join(' ');
91
- write(truncate(title + ' '.repeat(4) + tabs, cols) + CLEAR_EOL + '\n');
92
-
93
- // search bar
94
- const searchLabel = searching ? green('/ ') : dim('/ ');
95
- const searchVal = searching ? white(query) + (Math.floor(Date.now()/500)%2 ? '' : ' ') : dim(query || 'type / to search');
96
- write(' ' + searchLabel + truncate(searchVal, cols - 4) + CLEAR_EOL + '\n');
97
-
98
- const countLabel = dim(` ${items.length} items`);
99
- const hint = dim(status ? (status.ok ? green(' ' + status.msg) : red('' + status.msg)) : '');
100
- write(countLabel + hint + CLEAR_EOL + '\n');
91
+ // Row 1: title bar
92
+ const titleText = ' PromptGraph Marketplace';
93
+ const tabParts = ['all', 'skills', 'bundles'].map(t =>
94
+ t === tab
95
+ ? `\x1b[48;2;124;58;237m\x1b[97m ${t.toUpperCase()} \x1b[0m`
96
+ : dim(` ${t} `)
97
+ ).join('');
98
+ const titleLine = purple.bold(titleText) + ' ' + tabParts;
99
+ write(titleLine + CLEAR_EOL + '\n');
100
+
101
+ // Row 2: counts
102
+ const countLine = dim(' ') +
103
+ (tab !== 'bundles' ? chalk.white(`${skills} skills`) + dim(' ') : '') +
104
+ (tab !== 'skills' ? chalk.blue(`${bundles} bundles`) : '') +
105
+ (query ? dim(' · filter: ') + cyan(query) : '');
106
+ write(countLine + CLEAR_EOL + '\n');
107
+
108
+ // Row 3: search bar
109
+ const searchLabel = searching ? green(' / ') : dim(' / ');
110
+ const cursor_blink = Math.floor(Date.now() / 500) % 2 ? '▌' : ' ';
111
+ const searchVal = searching
112
+ ? white(query || '') + cursor_blink
113
+ : dim(query ? query : 'type / to search, Tab to switch view');
114
+ write(searchLabel + searchVal + CLEAR_EOL + '\n');
115
+
116
+ // Row 4: status / separator
117
+ if (status) {
118
+ const msg = status.ok ? green(' ✓ ' + status.msg) : red(' ✗ ' + status.msg);
119
+ write(msg + CLEAR_EOL + '\n');
120
+ } else {
121
+ write(dim('─'.repeat(cols)) + CLEAR_EOL + '\n');
122
+ }
101
123
  write(dim('─'.repeat(cols)) + CLEAR_EOL + '\n');
102
124
 
103
125
  // ── list ───────────────────────────────────────────────────────────────────
104
126
  let lastCat = null;
105
- let lineIdx = 0;
106
127
  let rendered = 0;
107
128
 
108
129
  for (let i = scroll; i < items.length && rendered < LIST_ROWS; i++) {
109
130
  const item = items[i];
110
131
  const selected = i === cursor;
111
- const bg = selected ? '\x1b[48;2;60;40;120m' : '';
112
- const reset = selected ? '\x1b[0m' : '';
132
+ const bg = selected ? '\x1b[48;2;55;35;110m' : '';
133
+ const reset = '\x1b[0m';
113
134
 
114
- // category header
135
+ // category header (only when ungrouped / mixed)
115
136
  if (item.category !== lastCat) {
116
137
  if (rendered >= LIST_ROWS) break;
117
138
  const icon = CAT_ICON[item.category] || '📦';
118
- write(bg + ' ' + purple(icon + ' ' + item.category) + reset + CLEAR_EOL + '\n');
139
+ write((selected ? bg : '') + ' ' + purple.bold(icon + ' ' + item.category) + reset + CLEAR_EOL + '\n');
119
140
  lastCat = item.category;
120
141
  rendered++;
142
+ if (rendered >= LIST_ROWS) break;
121
143
  }
122
144
 
123
- if (rendered >= LIST_ROWS) break;
124
-
125
145
  // item row
126
- const sel = selected ? cyan('▶') : ' ';
146
+ const arrow = selected ? cyan('▶') : ' ';
127
147
  const type = item.type === 'bundle' ? blue('⊞') : dim('·');
128
- const name = selected ? white.bold(item.name) : white(item.name);
129
- const stars = item.stars > 0 ? yellow('★' + item.stars) : dim('★0');
148
+ const nameStr = truncate(item.name, NAME_W);
149
+ const namePad = nameStr.padEnd(NAME_W);
150
+ const nameCol = selected ? white.bold(namePad) : white(namePad);
130
151
  const extra = item.type === 'bundle'
131
- ? (item.skillCount ? blue(item.skillCount + ' skills') : blue('GitHub'))
132
- : (item.code ? dim(item.code) : '');
133
- const desc = dim(truncate(item.description, cols - 42));
152
+ ? (item.skillCount ? blue((item.skillCount + ' sk').padEnd(8)) : blue('GitHub '))
153
+ : dim((item.code || '').padEnd(8));
154
+ const desc = dim(truncate(item.description, Math.max(10, DESC_W)));
134
155
 
135
- const left = ` ${sel} ${type} ${truncate(item.name, 28).padEnd(28)} ${stars} ${extra.padEnd(12)}`;
136
- write(bg + truncate(left, cols - desc.length - 2) + ' ' + desc + reset + CLEAR_EOL + '\n');
156
+ write(bg + ` ${arrow} ${type} ${nameCol} ${extra} ${desc}` + reset + CLEAR_EOL + '\n');
137
157
  rendered++;
138
158
  }
139
159