@kolbo/mcp 1.71.1 → 1.71.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 +1 -1
- package/skill/GENERATED.md +1 -1
- package/src/apps/html.js +52 -0
- package/src/apps/index.js +8 -0
- package/src/apps/widgets/generation.js +6 -1
- package/src/apps/widgets/list.js +24 -11
- package/src/tools/agents.js +14 -19
- package/src/tools/docs.js +13 -18
- package/src/tools/media.js +13 -17
- package/src/tools/projects.js +52 -68
- package/src/tools/visual_dna.js +12 -16
package/package.json
CHANGED
package/skill/GENERATED.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AUTO-GENERATED — do not edit
|
|
2
2
|
|
|
3
|
-
This tree is mirrored from kolbo-code@
|
|
3
|
+
This tree is mirrored from kolbo-code@ff2a2e2, the single source of truth.
|
|
4
4
|
Canonical source: packages/opencode/skills/kolbo/
|
|
5
5
|
Distribution: .github/workflows/sync-skill-to-plugin.yml
|
|
6
6
|
|
package/src/apps/html.js
CHANGED
|
@@ -109,11 +109,63 @@ function monogram(name) {
|
|
|
109
109
|
function structured(res) {
|
|
110
110
|
if (!res) return null;
|
|
111
111
|
if (res.structuredContent) return res.structuredContent;
|
|
112
|
+
if (res.result) return structured(res.result);
|
|
112
113
|
try {
|
|
113
114
|
var t = (res.content || []).filter(function (c) { return c.type === 'text'; })[0];
|
|
114
115
|
return t ? JSON.parse(t.text) : null;
|
|
115
116
|
} catch (e) { return null; }
|
|
116
117
|
}
|
|
118
|
+
// Hosts that do not advertise MCP Apps (Kolbo Code) get plain JSON
|
|
119
|
+
// ({ sessions }, { generations }, { projects }, …) with no items[].
|
|
120
|
+
// Normalize those shapes so list.html and the generation fallback can
|
|
121
|
+
// leave Loading on first paint without waiting for a newer host.
|
|
122
|
+
function listPayload(sc) {
|
|
123
|
+
if (!sc || typeof sc !== 'object') return null;
|
|
124
|
+
if (sc.widget && sc.widget !== 'list') return null;
|
|
125
|
+
if (sc.phase || sc.generation_id || sc.generation_ids) return null;
|
|
126
|
+
if (Array.isArray(sc.items)) {
|
|
127
|
+
return {
|
|
128
|
+
widget: 'list',
|
|
129
|
+
title: sc.title || 'List',
|
|
130
|
+
items: sc.items,
|
|
131
|
+
total: sc.total != null ? sc.total : sc.items.length
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
var key = sc.sessions ? 'sessions' : sc.projects ? 'projects' : sc.generations ? 'generations'
|
|
135
|
+
: sc.agents ? 'agents' : sc.docs ? 'docs' : sc.folders ? 'folders' : sc.sources ? 'sources' : '';
|
|
136
|
+
var rows = key ? sc[key] : null;
|
|
137
|
+
if (!Array.isArray(rows)) return null;
|
|
138
|
+
var titles = {
|
|
139
|
+
sessions: 'Sessions', projects: 'Projects', generations: 'Generations',
|
|
140
|
+
agents: 'Agents', docs: 'Docs', folders: 'Folders', sources: 'Knowledge Base'
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
widget: 'list',
|
|
144
|
+
title: sc.title || titles[key] || 'List',
|
|
145
|
+
items: rows.map(function (row) {
|
|
146
|
+
var types = Array.isArray(row.types)
|
|
147
|
+
? row.types.filter(function (x) { return typeof x === 'string'; })
|
|
148
|
+
: String(row.type || '').split('|').filter(Boolean);
|
|
149
|
+
var id = row.session_id || row.id || row.generation_id || row.file_key;
|
|
150
|
+
var name = row.name || row.title || (row.prompt ? String(row.prompt).slice(0, 80) : '') || types[0] || 'Item';
|
|
151
|
+
return {
|
|
152
|
+
id: id,
|
|
153
|
+
title: name,
|
|
154
|
+
subtitle: [
|
|
155
|
+
types.join(', ') || row.role || row.status || row.description,
|
|
156
|
+
id,
|
|
157
|
+
row.project_id ? 'project ' + row.project_id : null,
|
|
158
|
+
row.updated_at ? String(row.updated_at).slice(0, 10) : null,
|
|
159
|
+
row.output_count ? row.output_count + ' outputs' : null
|
|
160
|
+
].filter(Boolean).join(' · '),
|
|
161
|
+
badge: types[0] || row.role || row.status,
|
|
162
|
+
open_url: row.open_url || row.share_url || null,
|
|
163
|
+
meta: row.item_count != null ? String(row.item_count) : undefined
|
|
164
|
+
};
|
|
165
|
+
}),
|
|
166
|
+
total: sc.total != null ? sc.total : (sc.count != null ? sc.count : rows.length)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
117
169
|
</script>
|
|
118
170
|
<script>${script}</script>
|
|
119
171
|
</body>
|
package/src/apps/index.js
CHANGED
|
@@ -166,6 +166,13 @@ function uiResult(uri, text, structured) {
|
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/** List tools always ship structuredContent — Kolbo Code does not advertise
|
|
170
|
+
* MCP Apps, so gating on appsEnabled() left list.html / the generation
|
|
171
|
+
* fallback stuck on Loading with only `{ sessions }` text. */
|
|
172
|
+
function listResult(text, structured) {
|
|
173
|
+
return uiResult(UI.list, text, structured);
|
|
174
|
+
}
|
|
175
|
+
|
|
169
176
|
/* ------------------------------------------------------------------ */
|
|
170
177
|
/* Model icon lookup (name/identifier → absolute avatar URL) */
|
|
171
178
|
/* ------------------------------------------------------------------ */
|
|
@@ -494,6 +501,7 @@ module.exports = {
|
|
|
494
501
|
attachToolWidgetMeta,
|
|
495
502
|
uiMeta,
|
|
496
503
|
uiResult,
|
|
504
|
+
listResult,
|
|
497
505
|
appsEnabled,
|
|
498
506
|
modelIcon,
|
|
499
507
|
modelInfo,
|
|
@@ -889,6 +889,8 @@ function completedFromPlain(sc) {
|
|
|
889
889
|
/* ---------- wire host events ---------- */
|
|
890
890
|
window.kolbo.onToolResult(function (result) {
|
|
891
891
|
var sc = result.structuredContent || structured(result);
|
|
892
|
+
var list = listPayload(sc);
|
|
893
|
+
if (list) return renderList(list);
|
|
892
894
|
if (sc && (sc.phase || sc.widget)) return boot(sc);
|
|
893
895
|
var recovered = completedFromPlain(sc);
|
|
894
896
|
if (recovered) return boot(recovered);
|
|
@@ -907,7 +909,10 @@ window.kolbo.ready(function (ctx) {
|
|
|
907
909
|
var info = ctx && ctx.toolInfo;
|
|
908
910
|
if (!state && info) {
|
|
909
911
|
originTool = (info.tool && info.tool.name) || originTool;
|
|
910
|
-
|
|
912
|
+
var raw = info.result && (info.result.structuredContent || structured(info.result));
|
|
913
|
+
var list = listPayload(raw);
|
|
914
|
+
if (list) return renderList(list);
|
|
915
|
+
if (raw) return boot(raw);
|
|
911
916
|
bootPre(originTool, null);
|
|
912
917
|
}
|
|
913
918
|
});
|
package/src/apps/widgets/list.js
CHANGED
|
@@ -43,17 +43,30 @@ el('kolbo-link').onclick = function (e) { e.preventDefault(); window.kolbo.openL
|
|
|
43
43
|
var state = null;
|
|
44
44
|
|
|
45
45
|
function boot(sc) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
var list = listPayload(sc);
|
|
47
|
+
if (!list) return false;
|
|
48
|
+
state = list;
|
|
49
|
+
el('title').textContent = list.title || 'List';
|
|
50
|
+
var total = list.total != null ? list.total : list.items.length;
|
|
50
51
|
el('count-chip').style.display = '';
|
|
51
52
|
el('count-chip').textContent = total + (total === 1 ? ' item' : ' items');
|
|
52
|
-
if (!
|
|
53
|
-
|
|
53
|
+
if (!list.items.length) {
|
|
54
|
+
el('stage').classList.add('k-empty');
|
|
55
|
+
el('stage').innerHTML = 'Nothing here yet';
|
|
56
|
+
window.kolbo.notifySize();
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
el('stage').innerHTML = list.items.slice(0, 40).map(itemHTML).join('');
|
|
54
60
|
el('stage').classList.remove('k-empty');
|
|
55
61
|
wire();
|
|
56
62
|
window.kolbo.notifySize();
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function apply(result) {
|
|
67
|
+
if (!result) return false;
|
|
68
|
+
var inner = result.result || result;
|
|
69
|
+
return boot(inner.structuredContent || structured(inner) || inner);
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
function itemHTML(item, i) {
|
|
@@ -86,11 +99,11 @@ function wire() {
|
|
|
86
99
|
}
|
|
87
100
|
|
|
88
101
|
window.kolbo.onToolResult(function (result) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
apply(result);
|
|
103
|
+
});
|
|
104
|
+
window.kolbo.ready(function (ctx) {
|
|
105
|
+
var info = ctx && ctx.toolInfo;
|
|
106
|
+
if (info && info.result) apply(info.result);
|
|
94
107
|
});
|
|
95
108
|
`;
|
|
96
109
|
|
package/src/tools/agents.js
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
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 {
|
|
7
|
+
const { listResult } = require('../apps');
|
|
8
8
|
|
|
9
|
-
function registerAgentTools(server, client
|
|
10
|
-
const ui = () => appsEnabled(server, options);
|
|
9
|
+
function registerAgentTools(server, client) {
|
|
11
10
|
// ─── list_agents ───────────────────────────────────────────
|
|
12
11
|
server.tool(
|
|
13
12
|
'list_agents',
|
|
@@ -22,22 +21,18 @@ function registerAgentTools(server, client, options = {}) {
|
|
|
22
21
|
count: result.count || agents.length
|
|
23
22
|
}, null, 2);
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return { content: [{ type: 'text', text }] };
|
|
24
|
+
return listResult(text, {
|
|
25
|
+
widget: 'list',
|
|
26
|
+
title: 'Your Agents',
|
|
27
|
+
items: agents.map(a => ({
|
|
28
|
+
id: a.id,
|
|
29
|
+
title: (a.emoji ? a.emoji + ' ' : '') + a.name,
|
|
30
|
+
subtitle: a.description,
|
|
31
|
+
badge: a.is_global ? 'preset' : null,
|
|
32
|
+
use_hint: 'Use my "{TITLE}" agent (agent_id: {ID}) for this conversation.'
|
|
33
|
+
})),
|
|
34
|
+
total: agents.length
|
|
35
|
+
});
|
|
41
36
|
}
|
|
42
37
|
);
|
|
43
38
|
|
package/src/tools/docs.js
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
const { z } = require('zod');
|
|
7
7
|
const { projectIdField } = require('./_shared');
|
|
8
|
-
const {
|
|
8
|
+
const { listResult } = require('../apps');
|
|
9
9
|
|
|
10
10
|
const CONTENT_GUIDE = 'HTML body content. Use clean semantic HTML the in-app editor understands: <h1>-<h3>, <p>, <ul>/<ol>/<li>, <table>, <blockquote>, <strong>/<em>, <a>. No <script>/<style>/<iframe> (stripped server-side). Write the FULL document yourself — this is where you author the doc.';
|
|
11
11
|
|
|
12
|
-
function registerDocTools(server, client
|
|
13
|
-
const ui = () => appsEnabled(server, options);
|
|
12
|
+
function registerDocTools(server, client) {
|
|
14
13
|
// ─── create_doc ────────────────────────────────────────────
|
|
15
14
|
server.tool(
|
|
16
15
|
'create_doc',
|
|
@@ -55,21 +54,17 @@ function registerDocTools(server, client, options = {}) {
|
|
|
55
54
|
const docs = result.docs || [];
|
|
56
55
|
const text = JSON.stringify({ docs, pagination: result.pagination || null }, null, 2);
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return { content: [{ type: 'text', text }] };
|
|
57
|
+
return listResult(text, {
|
|
58
|
+
widget: 'list',
|
|
59
|
+
title: 'Your AI Docs',
|
|
60
|
+
items: docs.map(d => ({
|
|
61
|
+
id: d.id,
|
|
62
|
+
title: d.title,
|
|
63
|
+
subtitle: (d.updated_at ? String(d.updated_at).slice(0, 10) : '') + (d.is_shared ? ' · shared' : ''),
|
|
64
|
+
open_url: d.share_url || null
|
|
65
|
+
})),
|
|
66
|
+
total: docs.length
|
|
67
|
+
});
|
|
73
68
|
}
|
|
74
69
|
);
|
|
75
70
|
|
package/src/tools/media.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const { z } = require('zod');
|
|
7
7
|
const FormData = require('form-data');
|
|
8
8
|
const { resolveToBuffer, DEFAULT_MAX_FILE_MB, compactList } = require('./_shared');
|
|
9
|
-
const { UI, uiResult, appsEnabled } = require('../apps');
|
|
9
|
+
const { UI, uiResult, listResult, appsEnabled } = require('../apps');
|
|
10
10
|
|
|
11
11
|
// How many tiles the media grid renders. A rendering limit only — the text
|
|
12
12
|
// payload always carries the full page, and `total` reports the real library
|
|
@@ -343,22 +343,18 @@ function registerMediaTools(server, client, options = {}) {
|
|
|
343
343
|
const folders = result.folders || [];
|
|
344
344
|
const text = JSON.stringify({ folders, count: result.count || 0 }, null, 2);
|
|
345
345
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return { content: [{ type: 'text', text }] };
|
|
346
|
+
return listResult(text, {
|
|
347
|
+
widget: 'list',
|
|
348
|
+
title: 'Media Folders',
|
|
349
|
+
items: folders.map(f => ({
|
|
350
|
+
id: f.id,
|
|
351
|
+
title: f.name,
|
|
352
|
+
subtitle: f.description,
|
|
353
|
+
meta: (f.item_count || 0) + (f.item_count === 1 ? ' item' : ' items'),
|
|
354
|
+
use_hint: 'List media in my "{TITLE}" folder (folder_id: {ID}).'
|
|
355
|
+
})),
|
|
356
|
+
total: folders.length
|
|
357
|
+
});
|
|
362
358
|
}
|
|
363
359
|
);
|
|
364
360
|
|
package/src/tools/projects.js
CHANGED
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
const { z } = require('zod');
|
|
7
7
|
const { buildProjectUrl } = require('./_shared');
|
|
8
|
-
const {
|
|
8
|
+
const { listResult } = require('../apps');
|
|
9
9
|
|
|
10
|
-
function registerProjectTools(server, client
|
|
11
|
-
const ui = () => appsEnabled(server, options);
|
|
10
|
+
function registerProjectTools(server, client) {
|
|
12
11
|
// ─── list_projects ─────────────────────────────────────────
|
|
13
12
|
server.tool(
|
|
14
13
|
'list_projects',
|
|
@@ -42,22 +41,18 @@ function registerProjectTools(server, client, options = {}) {
|
|
|
42
41
|
_hint: 'Pass the chosen `id` as `project_id` on any generate_* tool to drop the generation into that project. Omit project_id to use the project flagged is_default:true. `open_url` opens that project\'s media in the web app (share it with the user). If `pagination.has_more` is true there are more projects — narrow with `search` rather than paging through everything.'
|
|
43
42
|
}, null, 2);
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return { content: [{ type: 'text', text }] };
|
|
44
|
+
return listResult(text, {
|
|
45
|
+
widget: 'list',
|
|
46
|
+
title: 'Your Projects',
|
|
47
|
+
items: projects.map(p => ({
|
|
48
|
+
id: p.id,
|
|
49
|
+
title: p.name,
|
|
50
|
+
subtitle: p.role + (p.is_default ? ' · default' : '') + (p.is_archived ? ' · archived' : ''),
|
|
51
|
+
open_url: p.open_url,
|
|
52
|
+
use_hint: 'Use my "{TITLE}" project (project_id: {ID}) for what I do next.'
|
|
53
|
+
})),
|
|
54
|
+
total: projects.length
|
|
55
|
+
});
|
|
61
56
|
}
|
|
62
57
|
);
|
|
63
58
|
|
|
@@ -135,20 +130,17 @@ function registerProjectTools(server, client, options = {}) {
|
|
|
135
130
|
generations,
|
|
136
131
|
_hint: 'This is an inventory, not a live generation. Pass the `id` values to `move_generations_to_session` (into an existing session) or `split_session` (into a new one). `in_flight: true` means it is still running and cannot be moved yet.'
|
|
137
132
|
}, null, 2);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
return { content: [{ type: 'text', text }] };
|
|
133
|
+
return listResult(text, {
|
|
134
|
+
widget: 'list',
|
|
135
|
+
title: (result.session && result.session.name) || 'Session generations',
|
|
136
|
+
items: generations.map((g) => ({
|
|
137
|
+
id: g.id,
|
|
138
|
+
title: (g.prompt && String(g.prompt).slice(0, 80)) || g.id,
|
|
139
|
+
subtitle: [g.status, g.output_count ? g.output_count + ' outputs' : null].filter(Boolean).join(' · '),
|
|
140
|
+
badge: g.in_flight ? 'running' : g.status
|
|
141
|
+
})),
|
|
142
|
+
total: generations.length
|
|
143
|
+
});
|
|
152
144
|
}
|
|
153
145
|
);
|
|
154
146
|
|
|
@@ -316,26 +308,22 @@ function registerProjectTools(server, client, options = {}) {
|
|
|
316
308
|
_hint: 'Each row has project_id — pass it on every later generate/chat/upload in this conversation. Empty leftover sessions after a move: delete_session.'
|
|
317
309
|
}, null, 2);
|
|
318
310
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return { content: [{ type: 'text', text }] };
|
|
311
|
+
return listResult(text, {
|
|
312
|
+
widget: 'list',
|
|
313
|
+
title: 'Sessions' + (type ? ' — ' + type : '') + ' (' + sessions.length + ')',
|
|
314
|
+
items: sessions.map(s => ({
|
|
315
|
+
id: s.session_id,
|
|
316
|
+
title: s.name || s.types[0] || s.type || 'Session',
|
|
317
|
+
subtitle: [
|
|
318
|
+
s.session_id,
|
|
319
|
+
(s.types || []).join(', '),
|
|
320
|
+
s.project_id ? 'project ' + s.project_id : null,
|
|
321
|
+
s.updated_at ? String(s.updated_at).slice(0, 10) : null
|
|
322
|
+
].filter(Boolean).join(' · '),
|
|
323
|
+
badge: (s.types && s.types[0]) || undefined
|
|
324
|
+
})),
|
|
325
|
+
total: sessions.length
|
|
326
|
+
});
|
|
339
327
|
}
|
|
340
328
|
);
|
|
341
329
|
|
|
@@ -416,21 +404,17 @@ function registerProjectTools(server, client, options = {}) {
|
|
|
416
404
|
const sources = result.sources || [];
|
|
417
405
|
const text = JSON.stringify({ sources, count: result.count || 0 }, null, 2);
|
|
418
406
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return { content: [{ type: 'text', text }] };
|
|
407
|
+
return listResult(text, {
|
|
408
|
+
widget: 'list',
|
|
409
|
+
title: 'Project Knowledge Base',
|
|
410
|
+
items: sources.map(s => ({
|
|
411
|
+
id: s.file_key,
|
|
412
|
+
title: s.title || s.type,
|
|
413
|
+
subtitle: s.type + ' · ' + s.status,
|
|
414
|
+
open_url: s.url || null
|
|
415
|
+
})),
|
|
416
|
+
total: sources.length
|
|
417
|
+
});
|
|
434
418
|
}
|
|
435
419
|
);
|
|
436
420
|
|
package/src/tools/visual_dna.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const { z } = require('zod');
|
|
7
7
|
const FormData = require('form-data');
|
|
8
8
|
const { resolveToBuffer: sharedResolveToBuffer, VISUAL_DNA_MAX_BYTES, projectScopeReadField, compactList } = require('./_shared');
|
|
9
|
-
const { UI, uiResult, appsEnabled } = require('../apps');
|
|
9
|
+
const { UI, uiResult, listResult, appsEnabled } = require('../apps');
|
|
10
10
|
|
|
11
11
|
// Visual DNA caps reference media at 25MB per file (stricter than the
|
|
12
12
|
// default _shared.resolveToBuffer cap — DNA profiles only need enough
|
|
@@ -227,21 +227,17 @@ function registerVisualDnaTools(server, client, options = {}) {
|
|
|
227
227
|
const folders = result.folders || [];
|
|
228
228
|
const text = JSON.stringify({ folders, count: result.count || 0 }, null, 2);
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return { content: [{ type: 'text', text }] };
|
|
230
|
+
return listResult(text, {
|
|
231
|
+
widget: 'list',
|
|
232
|
+
title: 'Visual DNA Folders',
|
|
233
|
+
items: folders.map(f => ({
|
|
234
|
+
id: f.id,
|
|
235
|
+
title: f.name,
|
|
236
|
+
meta: f.item_count != null ? (f.item_count + (f.item_count === 1 ? ' DNA' : ' DNAs')) : null,
|
|
237
|
+
use_hint: 'List Visual DNAs in my "{TITLE}" folder (folder_id: {ID}).'
|
|
238
|
+
})),
|
|
239
|
+
total: folders.length
|
|
240
|
+
});
|
|
245
241
|
}
|
|
246
242
|
);
|
|
247
243
|
|