@kolbo/mcp 1.28.0 → 1.30.0

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.
@@ -0,0 +1,247 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Kolbo Liquid Glass design system for MCP App widgets.
5
+ * Tokens extracted from kolbo-map (tailwind.config + index.css + liquid-glass.css):
6
+ * dark bg #0F0F0F, card #262626/90 + blur, brand #3b82f6, text #F5F5F2, Inter,
7
+ * specular top-edge highlight, spring easing cubic-bezier(.34,1.56,.64,1),
8
+ * skeleton-sweep shimmer, liquid-press buttons.
9
+ */
10
+
11
+ const KOLBO_CSS = `
12
+ :root {
13
+ --bg: #0f0f0f;
14
+ --card: rgba(38, 38, 38, 0.90);
15
+ --card-solid: #262626;
16
+ --surface: rgba(255, 255, 255, 0.03);
17
+ --surface-2: rgba(255, 255, 255, 0.06);
18
+ --border: rgba(255, 255, 255, 0.08);
19
+ --border-strong: rgba(255, 255, 255, 0.14);
20
+ --text: #f5f5f2;
21
+ --text-muted: rgba(245, 245, 242, 0.62);
22
+ --text-faint: rgba(245, 245, 242, 0.40);
23
+ --brand: #3b82f6;
24
+ --brand-soft: rgba(59, 130, 246, 0.16);
25
+ --success: #22c55e;
26
+ --error: #ef4444;
27
+ --warning: #f59e0b;
28
+ --radius-card: 16px;
29
+ --radius-btn: 8px;
30
+ --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
31
+ --smooth: cubic-bezier(0.25, 0.46, 0.45, 0.94);
32
+ --specular: inset 0 1px 0 rgba(255, 255, 255, 0.18);
33
+ color-scheme: dark;
34
+ }
35
+ [data-theme="light"] {
36
+ --bg: #f5f5f2;
37
+ --card: rgba(255, 255, 255, 0.85);
38
+ --card-solid: #ffffff;
39
+ --surface: rgba(0, 0, 0, 0.02);
40
+ --surface-2: rgba(0, 0, 0, 0.04);
41
+ --border: rgba(0, 0, 0, 0.08);
42
+ --border-strong: rgba(0, 0, 0, 0.14);
43
+ --text: #0a0a0c;
44
+ --text-muted: rgba(10, 10, 12, 0.62);
45
+ --text-faint: rgba(10, 10, 12, 0.40);
46
+ --brand-soft: rgba(59, 130, 246, 0.10);
47
+ --specular: inset 0 1px 0 rgba(255, 255, 255, 0.65);
48
+ color-scheme: light;
49
+ }
50
+ * { box-sizing: border-box; margin: 0; padding: 0; }
51
+ html, body { background: transparent; }
52
+ body {
53
+ font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
54
+ color: var(--text);
55
+ font-size: 14px;
56
+ line-height: 1.5;
57
+ -webkit-font-smoothing: antialiased;
58
+ }
59
+
60
+ /* ---- Card shell ---- */
61
+ .k-card {
62
+ background: var(--card);
63
+ backdrop-filter: blur(20px) saturate(180%);
64
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
65
+ border: 1px solid var(--border);
66
+ border-radius: var(--radius-card);
67
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25), var(--specular);
68
+ overflow: hidden;
69
+ animation: k-in 400ms var(--spring);
70
+ }
71
+ @keyframes k-in { from { opacity: 0; transform: translateY(6px) scale(0.985); } to { opacity: 1; transform: none; } }
72
+
73
+ .k-head {
74
+ display: flex; align-items: center; gap: 10px;
75
+ padding: 12px 16px;
76
+ border-bottom: 1px solid var(--border);
77
+ }
78
+ .k-logo { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 13px; letter-spacing: -0.01em; }
79
+ .k-logo svg { display: block; }
80
+ .k-head .k-title { color: var(--text-muted); font-size: 12.5px; font-weight: 500; }
81
+ .k-head .k-spacer { flex: 1; }
82
+
83
+ .k-body { padding: 14px 16px; }
84
+ .k-prompt { color: var(--text-muted); font-size: 12.5px; margin-bottom: 10px; word-break: break-word;
85
+ display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
86
+
87
+ /* ---- Chips ---- */
88
+ .k-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 12px; }
89
+ .k-chip {
90
+ display: inline-flex; align-items: center; gap: 5px;
91
+ padding: 3px 9px; border-radius: 999px;
92
+ background: var(--surface-2); border: 1px solid var(--border);
93
+ box-shadow: var(--specular);
94
+ font-size: 11px; font-weight: 500; color: var(--text-muted);
95
+ white-space: nowrap;
96
+ font-family: 'JetBrains Mono', ui-monospace, monospace;
97
+ letter-spacing: 0.01em;
98
+ animation: k-chip-in 200ms var(--spring);
99
+ }
100
+ @keyframes k-chip-in { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }
101
+ .k-chip.brand { background: var(--brand-soft); border-color: rgba(59, 130, 246, 0.3); color: var(--brand); }
102
+ .k-chip img { width: 14px; height: 14px; border-radius: 4px; object-fit: cover; }
103
+ .k-chip .k-mono-icon {
104
+ width: 14px; height: 14px; border-radius: 4px; background: var(--brand);
105
+ color: #fff; font-size: 9px; font-weight: 700; display: inline-flex;
106
+ align-items: center; justify-content: center; font-family: 'Inter', sans-serif;
107
+ }
108
+ .k-ref-thumb { width: 26px; height: 26px; border-radius: 6px; object-fit: cover; border: 1px solid var(--border-strong); }
109
+
110
+ /* ---- Generating state ---- */
111
+ .k-gen-grid { display: grid; gap: 8px; }
112
+ .k-gen-grid.n1 { grid-template-columns: 1fr; }
113
+ .k-gen-grid.n2 { grid-template-columns: 1fr 1fr; }
114
+ .k-gen-grid.n3, .k-gen-grid.n4 { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
115
+ .k-skel {
116
+ position: relative; border-radius: 10px; overflow: hidden;
117
+ background: var(--surface-2); border: 1px solid var(--border);
118
+ min-height: 120px;
119
+ }
120
+ .k-skel.video { aspect-ratio: 16 / 9; }
121
+ .k-skel.square { aspect-ratio: 1; }
122
+ .k-skel.portrait { aspect-ratio: 3 / 4; }
123
+ .k-skel::after {
124
+ content: ''; position: absolute; inset: 0;
125
+ background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.06) 40%, rgba(255,255,255,0.10) 50%, rgba(255,255,255,0.06) 60%, transparent 100%);
126
+ background-size: 200% 100%;
127
+ animation: k-sweep 1.6s ease-in-out infinite;
128
+ }
129
+ @keyframes k-sweep { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
130
+ .k-gen-badge {
131
+ position: absolute; top: 10px; left: 10px; z-index: 2;
132
+ display: inline-flex; align-items: center; gap: 6px;
133
+ padding: 4px 10px; border-radius: 999px;
134
+ background: rgba(0, 0, 0, 0.65); backdrop-filter: blur(6px);
135
+ border: 1px solid rgba(255, 255, 255, 0.14);
136
+ font-size: 11px; font-weight: 600; color: #fff;
137
+ }
138
+ .k-spin {
139
+ width: 12px; height: 12px; border-radius: 50%;
140
+ border: 2px solid rgba(255,255,255,0.25); border-top-color: var(--brand);
141
+ animation: k-rot 0.8s linear infinite;
142
+ }
143
+ @keyframes k-rot { to { transform: rotate(360deg); } }
144
+
145
+ .k-progress { position: relative; height: 3px; border-radius: 2px; overflow: hidden;
146
+ background: var(--surface-2); margin-top: 12px; }
147
+ .k-progress > i { position: absolute; inset: 0 auto 0 0; width: 0%; border-radius: 2px;
148
+ background: linear-gradient(90deg, var(--brand), #60a5fa);
149
+ transition: width 600ms var(--smooth); }
150
+ .k-status-line { display: flex; align-items: center; justify-content: space-between;
151
+ margin-top: 8px; font-size: 11px; color: var(--text-faint); }
152
+
153
+ /* ---- Results ---- */
154
+ .k-media { position: relative; border-radius: 10px; overflow: hidden; border: 1px solid var(--border);
155
+ background: #000; cursor: pointer; transition: transform 300ms var(--spring), box-shadow 300ms var(--smooth); }
156
+ .k-media:hover { transform: scale(1.015); box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45); }
157
+ .k-media img, .k-media video { display: block; width: 100%; height: 100%; object-fit: cover; }
158
+ .k-media.selected { outline: 2px solid var(--brand); outline-offset: 1px; }
159
+
160
+ .k-viewer { margin-bottom: 10px; }
161
+ .k-viewer img, .k-viewer video { display: block; width: 100%; max-height: 480px; object-fit: contain;
162
+ border-radius: 12px; background: #000; border: 1px solid var(--border); }
163
+ .k-thumbs { display: flex; gap: 6px; margin: 10px 0 2px; }
164
+ .k-thumbs .k-thumb { width: 48px; height: 48px; border-radius: 8px; overflow: hidden; cursor: pointer;
165
+ border: 2px solid transparent; opacity: 0.75; transition: all 150ms var(--smooth); flex: none; }
166
+ .k-thumbs .k-thumb:hover { opacity: 1; }
167
+ .k-thumbs .k-thumb.active { border-color: var(--brand); opacity: 1; }
168
+ .k-thumbs .k-thumb img { width: 100%; height: 100%; object-fit: cover; }
169
+
170
+ /* ---- Buttons ---- */
171
+ .k-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding-top: 12px; }
172
+ .k-btn {
173
+ display: inline-flex; align-items: center; gap: 6px;
174
+ padding: 7px 14px; border-radius: var(--radius-btn);
175
+ border: 1px solid var(--border); background: var(--surface-2);
176
+ box-shadow: var(--specular);
177
+ color: var(--text); font-size: 12px; font-weight: 600; font-family: inherit;
178
+ cursor: pointer; transition: all 150ms var(--smooth);
179
+ text-decoration: none; user-select: none;
180
+ }
181
+ .k-btn:hover { background: var(--border-strong); }
182
+ .k-btn:active { transform: scale(0.97); }
183
+ .k-btn.primary { background: var(--brand); border-color: var(--brand); color: #fff;
184
+ box-shadow: 0 2px 12px rgba(59, 130, 246, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.25); }
185
+ .k-btn.primary:hover { background: #2f74e8; }
186
+ .k-btn.ghost { background: transparent; box-shadow: none; border-color: transparent; color: var(--text-muted); }
187
+ .k-btn.ghost:hover { color: var(--text); background: var(--surface-2); }
188
+ .k-btn svg { width: 13px; height: 13px; }
189
+ .k-btn:disabled { opacity: 0.5; cursor: default; }
190
+
191
+ /* ---- Inline prompt input (Animate / Edit flows) ---- */
192
+ .k-prompt-row { display: none; gap: 8px; margin-top: 10px; }
193
+ .k-prompt-row.open { display: flex; animation: k-in 250ms var(--spring); }
194
+ .k-input {
195
+ flex: 1; padding: 8px 12px; border-radius: var(--radius-btn);
196
+ border: 1px solid var(--border-strong); background: var(--surface);
197
+ color: var(--text); font-size: 12.5px; font-family: inherit; outline: none;
198
+ }
199
+ .k-input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-soft); }
200
+ .k-input::placeholder { color: var(--text-faint); }
201
+
202
+ /* ---- Grid widget (media / stock / presets) ---- */
203
+ .k-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
204
+ .k-cell { position: relative; border-radius: 10px; overflow: hidden; border: 1px solid var(--border);
205
+ background: var(--surface); cursor: pointer; transition: transform 250ms var(--spring); }
206
+ .k-cell:hover { transform: translateY(-2px) scale(1.01); }
207
+ .k-cell .k-cell-media { aspect-ratio: 1; background: #000; }
208
+ .k-cell .k-cell-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
209
+ .k-cell .k-cell-label { padding: 6px 8px; font-size: 11px; color: var(--text-muted);
210
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
211
+ .k-cell .k-cell-sub { padding: 0 8px 7px; font-size: 10px; color: var(--text-faint);
212
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
213
+
214
+ /* ---- Audio rows ---- */
215
+ .k-audio-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px;
216
+ border-radius: 10px; border: 1px solid var(--border); background: var(--surface);
217
+ margin-bottom: 6px; transition: background 150ms var(--smooth); }
218
+ .k-audio-row:hover { background: var(--surface-2); }
219
+ .k-audio-art { width: 40px; height: 40px; border-radius: 8px; object-fit: cover; flex: none;
220
+ background: var(--brand-soft); }
221
+ .k-audio-meta { flex: 1; min-width: 0; }
222
+ .k-audio-title { font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
223
+ .k-audio-sub { font-size: 11px; color: var(--text-faint); }
224
+ .k-play {
225
+ width: 32px; height: 32px; border-radius: 50%; flex: none; border: 1px solid rgba(255,255,255,0.18);
226
+ background: rgba(0,0,0,0.5); color: #fff; cursor: pointer;
227
+ display: inline-flex; align-items: center; justify-content: center;
228
+ transition: all 150ms var(--smooth);
229
+ }
230
+ .k-play:hover { background: var(--brand); border-color: var(--brand); }
231
+
232
+ /* ---- Misc ---- */
233
+ .k-error { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-radius: 10px;
234
+ background: rgba(239, 68, 68, 0.08); border: 1px solid rgba(239, 68, 68, 0.25);
235
+ color: #fca5a5; font-size: 12.5px; }
236
+ .k-empty { padding: 22px; text-align: center; color: var(--text-faint); font-size: 12.5px; }
237
+ .k-footer { display: flex; align-items: center; gap: 6px; padding: 8px 16px 12px;
238
+ font-size: 10.5px; color: var(--text-faint); }
239
+ .k-footer a { color: var(--text-faint); text-decoration: none; }
240
+ .k-footer a:hover { color: var(--brand); }
241
+ .k-credits { margin-left: auto; font-family: 'JetBrains Mono', monospace; }
242
+ `;
243
+
244
+ /** Kolbo mark (simplified inline SVG, brand blue). */
245
+ const KOLBO_LOGO_SVG = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="24" height="24" rx="6" fill="#3b82f6"/><path d="M7 5.5v13M7 12l6.5-6.5M7 12l7 6.5" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
246
+
247
+ module.exports = { KOLBO_CSS, KOLBO_LOGO_SVG };
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ const { widgetPage } = require('../html');
4
+
5
+ /**
6
+ * Model catalog widget — list_models.
7
+ *
8
+ * structuredContent: {
9
+ * widget: 'catalog', title,
10
+ * groups: [{ name: 'Video Generation', models: [{ name, icon, description,
11
+ * chips: ['5–12s', '4K', 'audio'], use_hint }] }]
12
+ * }
13
+ */
14
+
15
+ const BODY = `
16
+ <div class="k-card">
17
+ <div class="k-head">
18
+ <span class="k-logo" id="logo"></span>
19
+ <span class="k-title" id="title"></span>
20
+ <span class="k-spacer"></span>
21
+ <span class="k-chip" id="count-chip" style="display:none"></span>
22
+ </div>
23
+ <div class="k-body" id="stage"><div class="k-empty">Loading…</div></div>
24
+ <div class="k-footer"><span>Powered by <a href="#" id="kolbo-link">Kolbo.AI</a></span></div>
25
+ </div>
26
+ `;
27
+
28
+ const SCRIPT = `
29
+ el('logo').innerHTML = KOLBO_LOGO + '<span>Kolbo</span>';
30
+ el('kolbo-link').onclick = function (e) { e.preventDefault(); window.kolbo.openLink('https://app.kolbo.ai'); };
31
+ var state = null;
32
+
33
+ function boot(sc) {
34
+ if (!sc || !sc.groups) return;
35
+ state = sc;
36
+ el('title').textContent = sc.title || 'AI Models';
37
+ var total = sc.groups.reduce(function (n, g) { return n + g.models.length; }, 0);
38
+ el('count-chip').style.display = '';
39
+ el('count-chip').textContent = total + ' models';
40
+ el('stage').innerHTML = sc.groups.map(function (g, gi) {
41
+ return '<div style="margin-bottom:14px">' +
42
+ '<div style="font-size:12px;font-weight:600;color:var(--text-muted);margin-bottom:8px">' + esc(g.name) + '</div>' +
43
+ g.models.map(function (m, mi) {
44
+ return '<div class="k-audio-row" data-g="' + gi + '" data-m="' + mi + '" style="cursor:pointer">' +
45
+ (m.icon ? '<img class="k-audio-art" style="width:32px;height:32px" src="' + esc(m.icon) + '" onerror="this.outerHTML=monogram(\\'' + esc(m.name).replace(/'/g, '') + '\\')">'
46
+ : '<span style="flex:none">' + monogram(m.name) + '</span>') +
47
+ '<div class="k-audio-meta"><div class="k-audio-title">' + esc(m.name) + '</div>' +
48
+ (m.description ? '<div class="k-audio-sub">' + esc(m.description) + '</div>' : '') + '</div>' +
49
+ '<div style="display:flex;gap:4px;flex:none">' + (m.chips || []).slice(0, 3).map(function (c) {
50
+ return '<span class="k-chip">' + esc(c) + '</span>';
51
+ }).join('') + '</div></div>';
52
+ }).join('') + '</div>';
53
+ }).join('');
54
+ Array.prototype.forEach.call(document.querySelectorAll('[data-g]'), function (row) {
55
+ row.onclick = function () {
56
+ var m = state.groups[+row.getAttribute('data-g')].models[+row.getAttribute('data-m')];
57
+ window.kolbo.sendMessage(m.use_hint || ('Generate something with the "' + m.name + '" model — ask me what I want to make.'));
58
+ };
59
+ });
60
+ window.kolbo.notifySize();
61
+ }
62
+
63
+ window.kolbo.onToolResult(function (result) {
64
+ var sc = result.structuredContent || structured(result);
65
+ if (sc) boot(sc);
66
+ });
67
+ `;
68
+
69
+ function catalogWidgetHtml() {
70
+ return widgetPage({ title: 'Kolbo Models', body: BODY, script: SCRIPT });
71
+ }
72
+
73
+ module.exports = { catalogWidgetHtml };