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.
- package/package.json +1 -1
- package/tui.js +50 -30
package/package.json
CHANGED
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 =
|
|
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
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
112
|
-
const reset =
|
|
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
|
|
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
|
|
146
|
+
const arrow = selected ? cyan('▶') : ' ';
|
|
127
147
|
const type = item.type === 'bundle' ? blue('⊞') : dim('·');
|
|
128
|
-
const
|
|
129
|
-
const
|
|
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 + '
|
|
132
|
-
:
|
|
133
|
-
const desc
|
|
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
|
-
|
|
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
|
|