@kolbo/mcp 1.30.3 → 1.30.4

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.3",
3
+ "version": "1.30.4",
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/index.js CHANGED
@@ -125,6 +125,23 @@ function uiResult(uri, text, structured) {
125
125
  const ICON_TTL_MS = 10 * 60 * 1000;
126
126
  const infoCache = new Map(); // apiBase → { at, byKey: Map<lowername, {icon, eta}> }
127
127
 
128
+ /**
129
+ * Resolve a Model.avatar value to an absolute URL. Avatars are bare filenames
130
+ * (sometimes with spaces) living in the BACKEND's public assets folder —
131
+ * `<api origin>/assets/<file>`. Do NOT use app.kolbo.ai for this: it's the SPA,
132
+ * whose catch-all returns 200 text/html for any missing file, which renders as
133
+ * a broken image in widgets.
134
+ */
135
+ function resolveAvatarUrl(avatar, apiBase) {
136
+ if (!avatar) return null;
137
+ if (/^https?:\/\//i.test(avatar)) return avatar;
138
+ let origin = 'https://api.kolbo.ai';
139
+ try {
140
+ origin = new URL(apiBase || 'https://api.kolbo.ai/api').origin;
141
+ } catch (_) { /* keep default */ }
142
+ return `${origin}/assets/${encodeURIComponent(avatar)}`;
143
+ }
144
+
128
145
  async function modelInfoMap(client) {
129
146
  const cacheKey = client.apiBase || 'default';
130
147
  const hit = infoCache.get(cacheKey);
@@ -135,13 +152,7 @@ async function modelInfoMap(client) {
135
152
  const models = res?.models || res?.data?.models || [];
136
153
  for (const m of models) {
137
154
  if (!m) continue;
138
- // The API usually resolves avatars to absolute URLs; bare filenames (older
139
- // deployments / internal calls) resolve against the app's public icon dir.
140
- const icon = m.avatar
141
- ? (/^https?:\/\//i.test(m.avatar)
142
- ? m.avatar
143
- : `https://app.kolbo.ai/models_icons/${encodeURIComponent(m.avatar)}`)
144
- : null;
155
+ const icon = resolveAvatarUrl(m.avatar, client.apiBase);
145
156
  // Real p75 wall-clock estimate mined from production creditUsages —
146
157
  // the same source the in-app countdowns use. No estimate → no ETA shown.
147
158
  const eta = Number(m.estimatedDurationSeconds || m.estimated_duration_seconds) || null;
@@ -232,5 +243,6 @@ module.exports = {
232
243
  modelIcon,
233
244
  modelInfo,
234
245
  modelInfoMap,
246
+ resolveAvatarUrl,
235
247
  widgetHtml, // exported for smoke tests
236
248
  };
@@ -92,7 +92,7 @@ function renderChips(sc) {
92
92
  if (s.voice) h += chip('🎤 ' + esc(s.voice));
93
93
  if (s.mode) h += chip(esc(s.mode));
94
94
  if (sc.count > 1) h += chip('×' + sc.count);
95
- if (sc.reference_image) h += '<img class="k-ref-thumb" src="' + esc(sc.reference_image) + '" alt="" title="Reference image" onerror="this.style.display=\'none\'">';
95
+ if (sc.reference_image) h += '<img class="k-ref-thumb" src="' + esc(sc.reference_image) + '" alt="" title="Reference image" onerror="this.style.display=\\'none\\'">';
96
96
  el('chips').innerHTML = h;
97
97
  }
98
98
  function chip(inner) { return '<span class="k-chip">' + inner + '</span>'; }