@kolbo/mcp 1.86.0 → 1.86.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/src/apps/theme.js CHANGED
@@ -201,6 +201,14 @@ html.k-peek-fs .k-peek img, html.k-peek-fs .k-peek video { max-height: calc(100v
201
201
  position: relative; border-radius: 10px; overflow: hidden;
202
202
  background: var(--surface-2); border: 1px solid var(--border);
203
203
  min-height: 120px; max-height: 300px;
204
+ /* width:100% is load-bearing, not cosmetic. Without a definite width the
205
+ aspect-ratio transfers the OTHER way: a 16/9 cell in a 196px auto-fill
206
+ column wants 110px of height, min-height:120px clamps it up, and the ratio
207
+ then back-computes the WIDTH as 120*16/9 = 213px. The item overflows its
208
+ 196px track and lands on top of the next tile — which is exactly what a
209
+ 3-up video grid looked like. Pinning the width makes the ratio size the
210
+ height only, and min-height just letterboxes a slightly tall cell. */
211
+ width: 100%;
204
212
  }
205
213
  .k-skel.video { aspect-ratio: 16 / 9; }
206
214
  .k-skel.square { aspect-ratio: 1; }
@@ -368,6 +376,11 @@ html.k-fullscreen .k-actions { flex: none; padding-top: 8px; }
368
376
  .k-audio-row:hover { background: var(--surface-2); }
369
377
  .k-audio-art { width: 40px; height: 40px; border-radius: 8px; object-fit: cover; flex: none;
370
378
  background: var(--brand-soft); }
379
+ /* Stand-in when a voice/track has no artwork, or has one the host refuses to
380
+ load — a blank tile and the browser's broken-image glyph both read as "this
381
+ row is broken" rather than "this one has no picture". */
382
+ .k-audio-art-fallback { display: flex; align-items: center; justify-content: center;
383
+ color: var(--brand); font-size: 18px; }
371
384
  .k-audio-meta { flex: 1; min-width: 0; }
372
385
  .k-audio-title { font-size: 12.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
373
386
  .k-audio-sub { font-size: 11px; color: var(--text-faint);
@@ -76,13 +76,13 @@ var TOOL_TITLES = {
76
76
  get_generation_status: 'Generations'
77
77
  };
78
78
  var OPEN_ROUTES = {
79
- generate_image: { path: '/image-tools', tool: 'text-to-image' },
80
- generate_image_edit: { path: '/image-tools', tool: 'image-editing' },
81
- edit_image: { path: '/image-tools', tool: 'image-editing' },
82
- generate_video: { path: '/video-tools', tool: 'text-to-video' },
83
- generate_video_from_image: { path: '/video-tools', tool: 'image-to-video' },
84
- generate_elements: { path: '/video-tools', tool: 'image-to-video', mode: 'elements' },
85
- generate_first_last_frame: { path: '/video-tools', tool: 'image-to-video', mode: 'first-last' },
79
+ generate_image: { path: '/image-tools', tool: 'create-image' },
80
+ generate_image_edit: { path: '/image-tools', tool: 'create-image' },
81
+ edit_image: { path: '/image-tools', tool: 'canvas' },
82
+ generate_video: { path: '/video-tools', tool: 'create-video' },
83
+ generate_video_from_image: { path: '/video-tools', tool: 'create-video' },
84
+ generate_elements: { path: '/video-tools', tool: 'create-video', mode: 'elements' },
85
+ generate_first_last_frame: { path: '/video-tools', tool: 'create-video', mode: 'first-last' },
86
86
  generate_video_from_video: { path: '/video-tools', tool: 'video-to-video' },
87
87
  generate_lipsync: { path: '/video-tools', tool: 'lipsync' },
88
88
  generate_music: { path: '/audio-tools', tool: 'music-generator' },
@@ -1037,13 +1037,18 @@ function renderBatchGrid(sc) {
1037
1037
  function renderStatusGrid(sc) {
1038
1038
  var items = sc.items;
1039
1039
  if (!items.length) return renderError('No results');
1040
- el('stage').innerHTML = '<div class="k-gen-grid n' + Math.min(items.length, 4) + '">' +
1040
+ // Classify by extension, same as every other reference/thumb in this file —
1041
+ // the tool only knows a url came back, not what kind it is. Done up front
1042
+ // because the COLUMN COUNT depends on it: this grid used to hardcode
1043
+ // Math.min(items.length, 4) and so put videos 3-4 up, where gridCols caps
1044
+ // them at 2 everywhere else.
1045
+ items.forEach(function (it) {
1046
+ if (it.state === 'completed' && it.url) it.kind = refKind(it.url, 'image');
1047
+ });
1048
+ el('stage').innerHTML = '<div class="k-gen-grid n' + gridCols(items.length, items[0].kind) + '">' +
1041
1049
  items.map(function (it, i) {
1042
1050
  var cap = it.title ? '<span class="k-skel-cap" title="' + esc(it.title) + '">' + esc(it.title) + '</span>' : '';
1043
1051
  if (it.state === 'completed' && it.url) {
1044
- // Classify by extension, same as every other reference/thumb in this
1045
- // file — the tool only knows a url came back, not what kind it is.
1046
- it.kind = refKind(it.url, 'image');
1047
1052
  var shape = it.kind === 'video' ? 'video' : 'square';
1048
1053
  return '<div class="k-skel done ' + shape + '" data-focus="' + i + '"' +
1049
1054
  (it.title ? ' title="' + esc(it.title) + '"' : '') + '>' +
@@ -102,8 +102,21 @@ function cellHTML(item, i) {
102
102
  function audioRowHTML(item) {
103
103
  var idx = state.items.indexOf(item);
104
104
  var src = item.preview_audio || item.url;
105
+ // Same onerror contract as cellHTML, and for the same reason: a thumbnail the
106
+ // host cannot fetch (CSP, 404, expired) otherwise renders the browser's
107
+ // broken-image glyph. Voices are the ONLY items that come down this path, so
108
+ // this row is where a blocked thumbnail is actually visible — cells have
109
+ // degraded gracefully since forever and hid the problem everywhere else.
110
+ // this.outerHTML, NOT this.parentNode.innerHTML: here the <img> IS the art and
111
+ // its parent is the whole row, so the cell version would erase the title,
112
+ // subtitle, Use button and player along with it.
113
+ var artFallback = '<div class="k-audio-art k-audio-art-fallback">' + kindIcon('audio') + '</div>';
105
114
  return '<div class="k-audio-row k-generated-audio" data-i="' + idx + '">' +
106
- (item.thumbnail ? '<img class="k-audio-art k-peek-hit" src="' + esc(item.thumbnail) + '"' + peekAttrs(item.thumbnail, 'image', item.title) + '>' : '<div class="k-audio-art"></div>') +
115
+ (item.thumbnail
116
+ ? '<img class="k-audio-art k-peek-hit" src="' + esc(item.thumbnail) + '" alt=""'
117
+ + peekAttrs(item.thumbnail, 'image', item.title)
118
+ + ' onerror="this.outerHTML=this.getAttribute(\\'data-fb\\')" data-fb="' + esc(artFallback) + '">'
119
+ : artFallback) +
107
120
  '<div class="k-audio-meta"><div class="k-audio-title">' + esc(item.title || '') + '</div>' +
108
121
  '<div class="k-audio-sub">' + esc(item.subtitle || '') + '</div></div>' +
109
122
  '<button class="k-btn" data-use="' + idx + '">Use</button>' +