@kolbo/mcp 1.30.7 → 1.30.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolbo/mcp",
3
- "version": "1.30.7",
3
+ "version": "1.30.9",
4
4
  "description": "Kolbo AI MCP Server - Generate images, videos, music, speech, and sound effects from Claude Code",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/apps/html.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { BRIDGE_JS } = require('./bridge');
4
- const { KOLBO_CSS, KOLBO_LOGO_SVG } = require('./theme');
4
+ const { KOLBO_CSS, KOLBO_LOGO_SVG, KOLBO_LOGO_IMG } = require('./theme');
5
5
 
6
6
  /**
7
7
  * Assemble a self-contained widget page. No build step — each widget module
@@ -25,7 +25,8 @@ ${body}
25
25
  <script>${BRIDGE_JS}</script>
26
26
  <script>
27
27
  // ---- shared widget runtime ----
28
- var KOLBO_LOGO = ${JSON.stringify(KOLBO_LOGO_SVG)};
28
+ var KOLBO_LOGO_FALLBACK = ${JSON.stringify(KOLBO_LOGO_SVG)};
29
+ var KOLBO_LOGO = ${JSON.stringify(KOLBO_LOGO_IMG)};
29
30
  function esc(s) {
30
31
  return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
31
32
  return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
package/src/apps/index.js CHANGED
@@ -140,19 +140,19 @@ const infoCache = new Map(); // apiBase → { at, byKey: Map<lowername, {icon, e
140
140
 
141
141
  /**
142
142
  * Resolve a Model.avatar value to an absolute URL. Avatars are bare filenames
143
- * (sometimes with spaces) living in the BACKEND's public assets folder
144
- * `<api origin>/assets/<file>`. Do NOT use app.kolbo.ai for this: it's the SPA,
145
- * whose catch-all returns 200 text/html for any missing file, which renders as
146
- * a broken image in widgets.
143
+ * (sometimes with spaces). They're mirrored from kolbo-api/assets to the
144
+ * public DO Spaces CDN by kolbo-api scripts/infra/upload-model-icons-cdn.js
145
+ * the CDN is the ONLY host that reliably loads inside claude.ai's sandboxed
146
+ * widget iframes (api.kolbo.ai sits behind Cloudflare bot rules that block
147
+ * sandbox image requests; app.kolbo.ai is the SPA whose catch-all returns
148
+ * 200 text/html for missing files).
147
149
  */
148
- function resolveAvatarUrl(avatar, apiBase) {
150
+ const ICON_CDN_BASE = 'https://kolbo-general-media.fra1.cdn.digitaloceanspaces.com/models_icons';
151
+
152
+ function resolveAvatarUrl(avatar) {
149
153
  if (!avatar) return null;
150
154
  if (/^https?:\/\//i.test(avatar)) return avatar;
151
- let origin = 'https://api.kolbo.ai';
152
- try {
153
- origin = new URL(apiBase || 'https://api.kolbo.ai/api').origin;
154
- } catch (_) { /* keep default */ }
155
- return `${origin}/assets/${encodeURIComponent(avatar)}`;
155
+ return `${ICON_CDN_BASE}/${encodeURIComponent(avatar)}`;
156
156
  }
157
157
 
158
158
  async function modelInfoMap(client) {
package/src/apps/theme.js CHANGED
@@ -115,7 +115,7 @@ body {
115
115
  .k-skel {
116
116
  position: relative; border-radius: 10px; overflow: hidden;
117
117
  background: var(--surface-2); border: 1px solid var(--border);
118
- min-height: 120px;
118
+ min-height: 120px; max-height: 300px;
119
119
  }
120
120
  .k-skel.video { aspect-ratio: 16 / 9; }
121
121
  .k-skel.square { aspect-ratio: 1; }
@@ -157,9 +157,13 @@ body {
157
157
  .k-media img, .k-media video { display: block; width: 100%; height: 100%; object-fit: cover; }
158
158
  .k-media.selected { outline: 2px solid var(--brand); outline-offset: 1px; }
159
159
 
160
+ /* Keep the whole completed card under the host's iframe height cap (~800px):
161
+ header + prompt + chips + viewer + thumbs + actions + footer must all fit,
162
+ or claude.ai adds an inner scrollbar. Click the image to open it full-size. */
160
163
  .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); }
164
+ .k-viewer img, .k-viewer video { display: block; width: 100%; max-height: 340px; object-fit: contain;
165
+ border-radius: 12px; background: #000; border: 1px solid var(--border); cursor: zoom-in; }
166
+ .k-viewer video { cursor: default; }
163
167
  .k-thumbs { display: flex; gap: 6px; margin: 10px 0 2px; }
164
168
  .k-thumbs .k-thumb { width: 48px; height: 48px; border-radius: 8px; overflow: hidden; cursor: pointer;
165
169
  border: 2px solid transparent; opacity: 0.75; transition: all 150ms var(--smooth); flex: none; }
@@ -241,7 +245,11 @@ body {
241
245
  .k-credits { margin-left: auto; font-family: 'JetBrains Mono', monospace; }
242
246
  `;
243
247
 
244
- /** Kolbo mark (simplified inline SVG, brand blue). */
248
+ /**
249
+ * Kolbo mark — the real app icon from the CDN (the host CSP allows it), with
250
+ * the simplified inline SVG only as the onerror fallback.
251
+ */
245
252
  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>`;
253
+ const KOLBO_LOGO_IMG = `<img src="https://kolbo-general-media.fra1.cdn.digitaloceanspaces.com/models_icons/kolbo-ai.png" alt="Kolbo" style="width:18px;height:18px;border-radius:5px;display:block" onerror="this.outerHTML=KOLBO_LOGO_FALLBACK">`;
246
254
 
247
- module.exports = { KOLBO_CSS, KOLBO_LOGO_SVG };
255
+ module.exports = { KOLBO_CSS, KOLBO_LOGO_SVG, KOLBO_LOGO_IMG };
@@ -173,6 +173,11 @@ function renderImages(sc, urls) {
173
173
  // instead of a broken empty viewer.
174
174
  var viewer = '<div class="k-viewer"><img id="main-img" src="' + esc(urls[selected]) + '" alt="" onerror="window.__imgFail && window.__imgFail()"></div>';
175
175
  window.__imgFail = function () { renderLinks(urls); window.kolbo.notifySize(); };
176
+ // Constrained viewer → click opens the original full-size.
177
+ setTimeout(function () {
178
+ var img = el('main-img');
179
+ if (img) img.onclick = function () { window.kolbo.openLink(state.urls[selected]); };
180
+ }, 0);
176
181
  var thumbs = '';
177
182
  if (urls.length > 1) {
178
183
  thumbs = '<div class="k-thumbs">' + urls.map(function (u, i) {
@@ -4,7 +4,7 @@
4
4
  * new OPTIONAL args only. Full rules: ../index.js top-of-file and CLAUDE.md. */
5
5
 
6
6
  const { z } = require('zod');
7
- const { UI, uiResult, appsEnabled } = require('../apps');
7
+ const { UI, uiResult, appsEnabled, resolveAvatarUrl } = require('../apps');
8
8
 
9
9
  // type name → human group label for the catalog widget
10
10
  const TYPE_GROUPS = {
@@ -73,9 +73,7 @@ function buildCatalogStructured(models, type) {
73
73
  if (g.models.length >= 6) continue; // curated cap — full list lives in the text payload
74
74
  g.models.push({
75
75
  name: m.name,
76
- icon: m.avatar
77
- ? (/^https?:\/\//i.test(m.avatar) ? m.avatar : `https://app.kolbo.ai/models_icons/${m.avatar}`)
78
- : null,
76
+ icon: resolveAvatarUrl(m.avatar),
79
77
  description: String(m.smartSelect_StrengthsSummary || m.summary || m.description || '').slice(0, 90),
80
78
  chips: modelChips(m),
81
79
  use_hint: `Generate with the "${m.name}" model — ask me what I want to create first.`,