@kolbo/mcp 1.82.1 → 1.82.3
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
|
@@ -280,8 +280,12 @@ function renderChips(sc) {
|
|
|
280
280
|
var s = sc.settings || {};
|
|
281
281
|
var kind = displayKind(sc);
|
|
282
282
|
if (kind) h += chip(iconFor(kind) + ' ' + kind);
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
// Shot count when we know it, otherwise just say multishot is on — the
|
|
284
|
+
// provider picks the count in that case, and showing nothing made an
|
|
285
|
+
// enabled toggle look like it had not applied.
|
|
286
|
+
var shotLabel = s.shots > 1 ? (s.shots + ' shots') : (s.multi_shot ? 'multishot' : '');
|
|
287
|
+
if (s.duration) h += chip(ICONS.clock + ' ' + fmtDur(s.duration) + (shotLabel ? ' · ' + shotLabel : ''));
|
|
288
|
+
else if (shotLabel) h += chip(shotLabel);
|
|
285
289
|
if (s.resolution) h += chip(esc(s.resolution));
|
|
286
290
|
if (s.aspect_ratio) h += chip(esc(s.aspect_ratio));
|
|
287
291
|
if (s.quality) h += chip(esc(s.quality) + ' quality');
|
|
@@ -441,6 +445,47 @@ function iconFor(kind) {
|
|
|
441
445
|
/* ---------- generating ---------- */
|
|
442
446
|
function isBatch(sc) { return !!(sc && sc.generation_ids && sc.generation_ids.length > 1); }
|
|
443
447
|
|
|
448
|
+
// Columns for a batch grid. Video caps at 2 per row: a 16:9 cell in a 4-up
|
|
449
|
+
// grid lands around 200px inside a chat card, which is too small to judge a
|
|
450
|
+
// shot and far too small to scrub once <video controls> appears. Images stay
|
|
451
|
+
// 4-up — they read fine as contact-sheet tiles.
|
|
452
|
+
function gridCols(count, kind) {
|
|
453
|
+
return Math.min(count, kind === 'video' ? 2 : 4);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Batch prompts routinely share a long identical preamble (a locked global
|
|
457
|
+
// look, style rules, duration). Clamping from the left then renders EVERY
|
|
458
|
+
// caption as the same string — four cells all reading "Total: 8s [GLOBAL LOOK
|
|
459
|
+
// - LOCKED]…" identify nothing. Drop the shared prefix so the caption shows
|
|
460
|
+
// the part that actually differs. Full text stays in the tooltip.
|
|
461
|
+
function batchCaptions(prompts) {
|
|
462
|
+
var list = (prompts || []).map(function (p) { return String(p == null ? '' : p); });
|
|
463
|
+
if (list.length < 2) return list;
|
|
464
|
+
var first = list[0], n = first.length;
|
|
465
|
+
for (var i = 1; i < list.length && n > 0; i++) {
|
|
466
|
+
var j = 0;
|
|
467
|
+
while (j < n && j < list[i].length && list[i].charAt(j) === first.charAt(j)) j++;
|
|
468
|
+
n = j;
|
|
469
|
+
}
|
|
470
|
+
// Short shared runs are just coincidence ("A ", "The "), not a preamble.
|
|
471
|
+
if (n < 12) return list;
|
|
472
|
+
// Back up to a word boundary so a label never starts mid-word.
|
|
473
|
+
var cut = n;
|
|
474
|
+
while (cut > 0 && !/\s/.test(first.charAt(cut - 1))) cut--;
|
|
475
|
+
if (!cut) cut = n;
|
|
476
|
+
return list.map(function (p) {
|
|
477
|
+
var rest = p.slice(cut).trim();
|
|
478
|
+
// A prompt identical to the prefix has nothing distinct to show — keep it
|
|
479
|
+
// whole rather than rendering an empty chip.
|
|
480
|
+
return rest ? '… ' + rest : p;
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
function capAt(sc, i) {
|
|
484
|
+
if (!sc || !sc.prompts || !sc.prompts[i]) return '';
|
|
485
|
+
if (!sc._caps) sc._caps = batchCaptions(sc.prompts);
|
|
486
|
+
return sc._caps[i] || sc.prompts[i];
|
|
487
|
+
}
|
|
488
|
+
|
|
444
489
|
function renderGenerating(sc) {
|
|
445
490
|
setPhaseChip('Generating', true);
|
|
446
491
|
var n = Math.min(sc.count || 1, isBatch(sc) ? 8 : 4);
|
|
@@ -449,11 +494,11 @@ function renderGenerating(sc) {
|
|
|
449
494
|
var cells = '';
|
|
450
495
|
for (var i = 0; i < n; i++) {
|
|
451
496
|
var cap = (sc.prompts && sc.prompts[i])
|
|
452
|
-
? '<span class="k-skel-cap" title="' + esc(sc.prompts[i]) + '">' + esc(sc
|
|
497
|
+
? '<span class="k-skel-cap" title="' + esc(sc.prompts[i]) + '">' + esc(capAt(sc, i)) + '</span>' : '';
|
|
453
498
|
cells += '<div class="k-skel ' + shape + '" data-cell="' + i + '">' + cap + '</div>';
|
|
454
499
|
}
|
|
455
500
|
// Grid class caps at n4 — the auto-fill rule handles any larger batch count.
|
|
456
|
-
el('stage').innerHTML = '<div class="k-gen-grid n' +
|
|
501
|
+
el('stage').innerHTML = '<div class="k-gen-grid n' + gridCols(n, kind) + '">' + cells + '</div>';
|
|
457
502
|
renderStopButton(sc);
|
|
458
503
|
schedulePoll(sc);
|
|
459
504
|
}
|
|
@@ -709,7 +754,7 @@ function handleBatchStatus(sc, st) {
|
|
|
709
754
|
}
|
|
710
755
|
scenes.push({
|
|
711
756
|
scene_number: i + 1,
|
|
712
|
-
title: (sc
|
|
757
|
+
title: capAt(sc, i),
|
|
713
758
|
image_urls: sc.kind === 'video' ? [] : urls,
|
|
714
759
|
video_urls: sc.kind === 'video' ? urls : []
|
|
715
760
|
});
|
|
@@ -743,7 +788,7 @@ function fillBatchCell(sc, i, g) {
|
|
|
743
788
|
cell.setAttribute('data-done', '1');
|
|
744
789
|
cell.classList.add('done');
|
|
745
790
|
var cap = (sc.prompts && sc.prompts[i])
|
|
746
|
-
? '<span class="k-skel-cap" title="' + esc(sc.prompts[i]) + '">' + esc(sc
|
|
791
|
+
? '<span class="k-skel-cap" title="' + esc(sc.prompts[i]) + '">' + esc(capAt(sc, i)) + '</span>' : '';
|
|
747
792
|
if (sc.prompts && sc.prompts[i]) cell.title = sc.prompts[i];
|
|
748
793
|
// The controls attribute is not optional here: this cell is a FINISHED result
|
|
749
794
|
// the user is meant to watch, and without it the tile was a muted poster with
|
|
@@ -939,7 +984,7 @@ function renderBatchGrid(sc) {
|
|
|
939
984
|
var items = sceneItems(sc);
|
|
940
985
|
if (!items.length) return renderError('No completed results received');
|
|
941
986
|
var shape = items[0].type === 'video' ? 'video' : 'square';
|
|
942
|
-
el('stage').innerHTML = '<div class="k-gen-grid n' +
|
|
987
|
+
el('stage').innerHTML = '<div class="k-gen-grid n' + gridCols(items.length, items[0].type) + '">' +
|
|
943
988
|
items.map(function (it, i) {
|
|
944
989
|
return '<div class="k-skel done ' + shape + '" data-focus="' + i + '"' +
|
|
945
990
|
(it.label ? ' title="' + esc(it.label) + '"' : '') + '>' +
|
package/src/tools/generate.js
CHANGED
|
@@ -186,6 +186,9 @@ const videoSettings = (a = {}) => ({
|
|
|
186
186
|
// echoed back on start, then to per-shot × shots.
|
|
187
187
|
duration: a.duration ?? a.reported_duration ?? (a.shot_duration && a.shots ? a.shot_duration * a.shots : undefined),
|
|
188
188
|
...(a.shots > 1 ? { shots: a.shots } : {}),
|
|
189
|
+
// Multishot with no explicit count: the provider decides how many, so there
|
|
190
|
+
// is no number to show — but the card still has to say the toggle applied.
|
|
191
|
+
...(a.multi_shot ? { multi_shot: true } : {}),
|
|
189
192
|
resolution: a.resolution,
|
|
190
193
|
aspect_ratio: a.aspect_ratio,
|
|
191
194
|
...(a.mode ? { mode: a.mode } : {}),
|
|
@@ -1374,7 +1377,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1374
1377
|
settings: videoSettings({
|
|
1375
1378
|
duration,
|
|
1376
1379
|
reported_duration: startResponse?.duration ?? startResponse?.result?.duration,
|
|
1377
|
-
|
|
1380
|
+
// `multi_shots` is a boolean (z.boolean()); the old
|
|
1381
|
+
// `Array.isArray(multi_shots) ? multi_shots.length : undefined`
|
|
1382
|
+
// branch could never be true, so enabling multishot WITHOUT an
|
|
1383
|
+
// explicit count left shots undefined and the card silently showed
|
|
1384
|
+
// no multishot indicator at all. Carry the flag so the chip can
|
|
1385
|
+
// render even when the shot count is the provider's to decide.
|
|
1386
|
+
shots: multi_shot_count,
|
|
1387
|
+
multi_shot: multi_shots === true || undefined,
|
|
1378
1388
|
resolution, aspect_ratio, enhance_prompt, visual_dna_ids, preset_id,
|
|
1379
1389
|
}),
|
|
1380
1390
|
// Already bucketed and deduped above, so a URL handed to `files`
|
|
@@ -1396,7 +1406,14 @@ function registerGenerateTools(server, client, options = {}) {
|
|
|
1396
1406
|
settings: videoSettings({
|
|
1397
1407
|
duration,
|
|
1398
1408
|
reported_duration: result.result?.duration,
|
|
1399
|
-
|
|
1409
|
+
// `multi_shots` is a boolean (z.boolean()); the old
|
|
1410
|
+
// `Array.isArray(multi_shots) ? multi_shots.length : undefined`
|
|
1411
|
+
// branch could never be true, so enabling multishot WITHOUT an
|
|
1412
|
+
// explicit count left shots undefined and the card silently showed
|
|
1413
|
+
// no multishot indicator at all. Carry the flag so the chip can
|
|
1414
|
+
// render even when the shot count is the provider's to decide.
|
|
1415
|
+
shots: multi_shot_count,
|
|
1416
|
+
multi_shot: multi_shots === true || undefined,
|
|
1400
1417
|
resolution, aspect_ratio, enhance_prompt, visual_dna_ids, preset_id,
|
|
1401
1418
|
}),
|
|
1402
1419
|
reference_images: [...urlsOf('image'), ...(keyframes || []).map((keyframe) => keyframe.image_url)],
|
package/src/tools/visual_dna.js
CHANGED
|
@@ -102,7 +102,7 @@ function registerVisualDnaTools(server, client, options = {}) {
|
|
|
102
102
|
{
|
|
103
103
|
scope: z.enum(['all', 'personal', 'global', 'organization']).optional().describe('Default: "personal" — the user\'s own DNAs (plus a shared project\'s when project_id is set). "global" = the ~1000 system cast/preset DNAs, for browsing when the user needs a character and has none of their own. "organization" = org-shared. "all" = everything, rarely wanted.'),
|
|
104
104
|
search: z.string().optional().describe('Search by name, tags, or description (case-insensitive). Matches at WORD STARTS, so "man" finds "Man"/"Manager" but not "woman" or "romantic". Name matches are ranked first.'),
|
|
105
|
-
collection: z.string().optional().describe('Filter global presets by collection: cast, influencers, props, locations, styles,
|
|
105
|
+
collection: z.string().optional().describe('Filter global presets by collection: cast, influencers, props, locations, styles, street'),
|
|
106
106
|
tags: z.string().optional().describe('Comma-separated tags to filter by (OR logic)'),
|
|
107
107
|
page: z.number().optional().describe('Page number, 1-indexed. Default: 1. Needed to reach the global cast beyond the first page.'),
|
|
108
108
|
limit: z.number().optional().describe('Results per page, max 100. Default: 50'),
|