@kolbo/mcp 1.31.5 → 1.31.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolbo/mcp",
3
- "version": "1.31.5",
3
+ "version": "1.31.6",
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": {
@@ -94,12 +94,18 @@ const BRIDGE_JS = `
94
94
  readyFns.forEach(function (f) { try { f(hostContext); } catch (e) {} });
95
95
  }).catch(function () { /* host without apps support — widget stays static */ });
96
96
 
97
+ var fsMode = false; // fullscreen: the HOST owns layout — size reports there
98
+ // made the inline iframe balloon over the chat composer.
97
99
  function notifySize() {
100
+ if (fsMode) return;
98
101
  // Measure the widget card itself — documentElement.scrollHeight over-reports
99
102
  // in some hosts and leaves a huge empty iframe below the card.
100
103
  var card = document.querySelector('.k-card');
101
104
  var rect = card ? card.getBoundingClientRect() : null;
102
105
  var height = rect ? Math.ceil(rect.bottom + 8) : document.documentElement.scrollHeight;
106
+ // Never ask the host for more than a viewport of inline height — a card
107
+ // taller than the screen overlaps Claude's prompt area.
108
+ height = Math.min(height, Math.max(window.innerHeight || 900, 500));
103
109
  notify('ui/notifications/size-changed', {
104
110
  width: document.documentElement.scrollWidth, height: height
105
111
  });
@@ -151,6 +157,12 @@ const BRIDGE_JS = `
151
157
  return request('ui/request-display-mode', { mode: mode });
152
158
  },
153
159
  notifySize: notifySize,
160
+ // Toggle fullscreen mode: suppresses size reports while the host owns the
161
+ // layout, and re-syncs the inline size on exit.
162
+ setFullscreen: function (on) {
163
+ fsMode = !!on;
164
+ if (!on) queueSize(60);
165
+ },
154
166
  hostContext: function () { return hostContext; }
155
167
  };
156
168
  })();
package/src/apps/theme.js CHANGED
@@ -175,7 +175,8 @@ body {
175
175
  header + prompt + chips + viewer + thumbs + actions + footer must all fit,
176
176
  or claude.ai adds an inner scrollbar. Click the image to expand in-Claude. */
177
177
  .k-viewer { margin-bottom: 10px; }
178
- .k-viewer img, .k-viewer video { display: block; width: 100%; max-height: 340px; object-fit: contain;
178
+ .k-viewer img, .k-viewer video { display: block; width: 100%;
179
+ max-height: min(340px, 55vh); object-fit: contain;
179
180
  border-radius: 12px; background: #000; border: 1px solid var(--border); cursor: zoom-in; }
180
181
  .k-viewer video { cursor: default; }
181
182
 
@@ -185,7 +186,10 @@ html.k-fullscreen .k-card { height: 100%; display: flex; flex-direction: column;
185
186
  html.k-fullscreen .k-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
186
187
  html.k-fullscreen .k-viewer { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; }
187
188
  html.k-fullscreen .k-viewer img, html.k-fullscreen .k-viewer video {
188
- max-height: 100%; max-width: 100%; width: auto; margin: 0 auto; cursor: zoom-out; }
189
+ /* hard viewport cap the image must NEVER exceed the screen or cover the
190
+ host's chrome, whatever the host's iframe sizing does */
191
+ max-height: min(100%, calc(100dvh - 130px)); max-width: 100%;
192
+ width: auto; margin: 0 auto; cursor: zoom-out; object-fit: contain; }
189
193
  html.k-fullscreen .k-thumbs .k-thumb { width: 64px; height: 64px; }
190
194
  .k-expand-hint { display: none; }
191
195
  .k-thumbs { display: flex; gap: 6px; margin: 10px 0 2px; }
@@ -258,23 +258,43 @@ function wireDlButtons(root) {
258
258
  });
259
259
  }
260
260
 
261
+ // CD scenes render as the SAME viewer+thumbnail carousel as image batches —
262
+ // a stacked column of full-size scenes buried the card (and the chat).
263
+ function sceneItems(sc) {
264
+ var items = [];
265
+ (sc.scenes || []).forEach(function (scene) {
266
+ var label = 'Scene ' + scene.scene_number + (scene.title ? ' — ' + scene.title : '');
267
+ (scene.image_urls || []).forEach(function (u) { items.push({ url: u, type: 'image', label: label }); });
268
+ (scene.video_urls || []).forEach(function (u) { items.push({ url: u, type: 'video', label: label }); });
269
+ });
270
+ return items;
271
+ }
272
+
261
273
  function renderScenes(sc) {
262
- el('stage').innerHTML = sc.scenes.map(function (scene) {
263
- var media = (scene.video_urls || []).map(function (u) {
264
- return '<div class="k-media"><video src="' + esc(u) + '" controls playsinline></video>' + dlBtnHTML(u) + '</div>';
265
- }).join('') + (scene.image_urls || []).map(function (u) {
266
- return '<div class="k-media" data-focus="' + esc(u) + '"><img src="' + esc(u) + '" alt="">' + dlBtnHTML(u) + '</div>';
267
- }).join('');
268
- return '<div style="margin-bottom:14px"><div style="font-size:12px;font-weight:600;color:var(--text-muted);margin-bottom:8px">Scene ' +
269
- esc(scene.scene_number) + (scene.title ? ' ' + esc(scene.title) : '') + '</div>' +
270
- '<div class="k-gen-grid n2">' + media + '</div></div>';
271
- }).join('');
274
+ var items = sceneItems(sc);
275
+ if (!items.length) return renderError('No completed scenes received');
276
+ selected = Math.min(selected, items.length - 1);
277
+ var it = items[selected];
278
+ var mediaHtml = it.type === 'video'
279
+ ? '<video id="scene-main" src="' + esc(it.url) + '" controls playsinline></video>'
280
+ : '<img id="scene-main" src="' + esc(it.url) + '" alt="" style="cursor:zoom-in">';
281
+ var thumbs = '<div class="k-thumbs">' + items.map(function (t, i) {
282
+ var inner = t.type === 'video'
283
+ ? '<span style="display:flex;align-items:center;justify-content:center;width:100%;height:100%;background:rgba(255,255,255,0.06);font-size:14px">▶</span>'
284
+ : '<img src="' + esc(t.url) + '" alt="" loading="lazy">';
285
+ return '<div class="k-thumb' + (i === selected ? ' active' : '') + '" data-i="' + i + '" title="' + esc(t.label) + '">' + inner + '</div>';
286
+ }).join('') + '</div>';
287
+ el('stage').innerHTML =
288
+ '<div class="k-viewer">' + mediaHtml + dlBtnHTML(it.url) + '</div>' +
289
+ '<div style="font-size:11px;color:var(--text-faint);margin:2px 2px 0">' + esc(it.label) + '</div>' +
290
+ thumbs;
272
291
  wireDlButtons(el('stage'));
273
- // Click a scene image → fullscreen focus on THAT image (videos keep their
274
- // native controls; clicking them shouldn't hijack playback).
275
- Array.prototype.forEach.call(el('stage').querySelectorAll('.k-media[data-focus]'), function (m) {
276
- m.style.cursor = 'zoom-in';
277
- m.onclick = function () { focusMedia(m.getAttribute('data-focus')); };
292
+ if (it.type === 'image') {
293
+ var main = el('scene-main');
294
+ if (main) main.onclick = function () { focusMedia(it.url); };
295
+ }
296
+ Array.prototype.forEach.call(el('stage').querySelectorAll('.k-thumb'), function (t) {
297
+ t.onclick = function () { selected = +t.getAttribute('data-i'); renderScenes(sc); window.kolbo.notifySize(); };
278
298
  });
279
299
  renderActions(sc);
280
300
  }
@@ -331,6 +351,7 @@ function toggleFullscreen() {
331
351
  }
332
352
  function applyFullscreen(on, exitHandler) {
333
353
  document.documentElement.classList.toggle('k-fullscreen', on);
354
+ if (window.kolbo.setFullscreen) window.kolbo.setFullscreen(on);
334
355
  var c = el('phase-chip');
335
356
  if (on) {
336
357
  c.style.display = '';