@vertesia/tools-sdk 0.80.0-dev.20251121 → 0.81.0
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/README.md +122 -0
- package/lib/cjs/InteractionCollection.js +118 -0
- package/lib/cjs/InteractionCollection.js.map +1 -1
- package/lib/cjs/SkillCollection.js +318 -0
- package/lib/cjs/SkillCollection.js.map +1 -0
- package/lib/cjs/ToolCollection.js +98 -0
- package/lib/cjs/ToolCollection.js.map +1 -1
- package/lib/cjs/copy-assets.js +84 -0
- package/lib/cjs/copy-assets.js.map +1 -0
- package/lib/cjs/index.js +6 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/server.js +327 -0
- package/lib/cjs/server.js.map +1 -0
- package/lib/cjs/site/styles.js +621 -0
- package/lib/cjs/site/styles.js.map +1 -0
- package/lib/cjs/site/templates.js +932 -0
- package/lib/cjs/site/templates.js.map +1 -0
- package/lib/esm/InteractionCollection.js +83 -0
- package/lib/esm/InteractionCollection.js.map +1 -1
- package/lib/esm/SkillCollection.js +311 -0
- package/lib/esm/SkillCollection.js.map +1 -0
- package/lib/esm/ToolCollection.js +64 -0
- package/lib/esm/ToolCollection.js.map +1 -1
- package/lib/esm/copy-assets.js +81 -0
- package/lib/esm/copy-assets.js.map +1 -0
- package/lib/esm/index.js +4 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/server.js +323 -0
- package/lib/esm/server.js.map +1 -0
- package/lib/esm/site/styles.js +618 -0
- package/lib/esm/site/styles.js.map +1 -0
- package/lib/esm/site/templates.js +920 -0
- package/lib/esm/site/templates.js.map +1 -0
- package/lib/types/InteractionCollection.d.ts +29 -0
- package/lib/types/InteractionCollection.d.ts.map +1 -1
- package/lib/types/SkillCollection.d.ts +111 -0
- package/lib/types/SkillCollection.d.ts.map +1 -0
- package/lib/types/ToolCollection.d.ts +18 -0
- package/lib/types/ToolCollection.d.ts.map +1 -1
- package/lib/types/copy-assets.d.ts +14 -0
- package/lib/types/copy-assets.d.ts.map +1 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/server.d.ts +72 -0
- package/lib/types/server.d.ts.map +1 -0
- package/lib/types/site/styles.d.ts +5 -0
- package/lib/types/site/styles.d.ts.map +1 -0
- package/lib/types/site/templates.d.ts +54 -0
- package/lib/types/site/templates.d.ts.map +1 -0
- package/lib/types/types.d.ts +152 -0
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +18 -5
- package/src/InteractionCollection.ts +90 -0
- package/src/SkillCollection.ts +389 -0
- package/src/ToolCollection.ts +68 -0
- package/src/copy-assets.ts +104 -0
- package/src/index.ts +4 -0
- package/src/server.ts +444 -0
- package/src/site/styles.ts +617 -0
- package/src/site/templates.ts +956 -0
- package/src/types.ts +162 -0
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.collectionCard = collectionCard;
|
|
4
|
+
exports.toolCard = toolCard;
|
|
5
|
+
exports.mcpProviderCard = mcpProviderCard;
|
|
6
|
+
exports.toolDetailCard = toolDetailCard;
|
|
7
|
+
exports.skillCard = skillCard;
|
|
8
|
+
exports.skillDetailCard = skillDetailCard;
|
|
9
|
+
exports.indexPage = indexPage;
|
|
10
|
+
exports.toolCollectionPage = toolCollectionPage;
|
|
11
|
+
exports.skillCollectionPage = skillCollectionPage;
|
|
12
|
+
exports.interactionCollectionPage = interactionCollectionPage;
|
|
13
|
+
const styles_js_1 = require("./styles.js");
|
|
14
|
+
/**
|
|
15
|
+
* Default icon SVG for collections without a custom icon
|
|
16
|
+
*/
|
|
17
|
+
const defaultIcon = /*html*/ `
|
|
18
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
19
|
+
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
|
|
20
|
+
</svg>`;
|
|
21
|
+
const skillIcon = /*html*/ `
|
|
22
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
23
|
+
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
|
|
24
|
+
</svg>`;
|
|
25
|
+
/**
|
|
26
|
+
* Extended styles for detail pages
|
|
27
|
+
*/
|
|
28
|
+
const detailStyles = /*css*/ `
|
|
29
|
+
${styles_js_1.baseStyles}
|
|
30
|
+
|
|
31
|
+
.nav {
|
|
32
|
+
margin-bottom: 1.5rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.nav a {
|
|
36
|
+
color: #6b7280;
|
|
37
|
+
text-decoration: none;
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: 0.5rem;
|
|
41
|
+
font-size: 0.875rem;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.nav a:hover {
|
|
45
|
+
color: #2563eb;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.nav svg {
|
|
49
|
+
width: 16px;
|
|
50
|
+
height: 16px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.detail-card {
|
|
54
|
+
background: white;
|
|
55
|
+
border-radius: 12px;
|
|
56
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
57
|
+
margin-bottom: 1.5rem;
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.detail-header {
|
|
62
|
+
padding: 1.5rem;
|
|
63
|
+
border-bottom: 1px solid #e5e7eb;
|
|
64
|
+
display: flex;
|
|
65
|
+
justify-content: space-between;
|
|
66
|
+
align-items: flex-start;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.detail-title {
|
|
70
|
+
font-size: 1.25rem;
|
|
71
|
+
font-weight: 600;
|
|
72
|
+
color: #111827;
|
|
73
|
+
margin: 0 0 0.25rem 0;
|
|
74
|
+
font-family: ui-monospace, monospace;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.detail-desc {
|
|
78
|
+
color: #6b7280;
|
|
79
|
+
font-size: 0.95rem;
|
|
80
|
+
margin: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.detail-badges {
|
|
84
|
+
display: flex;
|
|
85
|
+
gap: 0.5rem;
|
|
86
|
+
flex-wrap: wrap;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.detail-body {
|
|
90
|
+
padding: 1.5rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.detail-section {
|
|
94
|
+
margin-bottom: 1.5rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.detail-section:last-child {
|
|
98
|
+
margin-bottom: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.detail-section-title {
|
|
102
|
+
font-size: 0.75rem;
|
|
103
|
+
font-weight: 600;
|
|
104
|
+
text-transform: uppercase;
|
|
105
|
+
letter-spacing: 0.05em;
|
|
106
|
+
color: #9ca3af;
|
|
107
|
+
margin: 0 0 0.75rem 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.schema-block {
|
|
111
|
+
background: #1f2937;
|
|
112
|
+
color: #e5e7eb;
|
|
113
|
+
padding: 1rem;
|
|
114
|
+
border-radius: 8px;
|
|
115
|
+
font-family: ui-monospace, monospace;
|
|
116
|
+
font-size: 0.8rem;
|
|
117
|
+
overflow-x: auto;
|
|
118
|
+
white-space: pre;
|
|
119
|
+
line-height: 1.5;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.schema-block .key { color: #93c5fd; }
|
|
123
|
+
.schema-block .string { color: #86efac; }
|
|
124
|
+
.schema-block .number { color: #fcd34d; }
|
|
125
|
+
.schema-block .boolean { color: #f9a8d4; }
|
|
126
|
+
.schema-block .null { color: #9ca3af; }
|
|
127
|
+
|
|
128
|
+
.info-grid {
|
|
129
|
+
display: grid;
|
|
130
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
131
|
+
gap: 1rem;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.info-item {
|
|
135
|
+
background: #f9fafb;
|
|
136
|
+
padding: 1rem;
|
|
137
|
+
border-radius: 8px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.info-label {
|
|
141
|
+
font-size: 0.75rem;
|
|
142
|
+
font-weight: 600;
|
|
143
|
+
text-transform: uppercase;
|
|
144
|
+
letter-spacing: 0.05em;
|
|
145
|
+
color: #9ca3af;
|
|
146
|
+
margin-bottom: 0.25rem;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.info-value {
|
|
150
|
+
font-size: 0.95rem;
|
|
151
|
+
color: #111827;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.info-value code {
|
|
155
|
+
background: #e5e7eb;
|
|
156
|
+
padding: 0.125rem 0.375rem;
|
|
157
|
+
border-radius: 4px;
|
|
158
|
+
font-family: ui-monospace, monospace;
|
|
159
|
+
font-size: 0.85rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.package-list {
|
|
163
|
+
display: flex;
|
|
164
|
+
flex-wrap: wrap;
|
|
165
|
+
gap: 0.5rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.package-tag {
|
|
169
|
+
background: #dbeafe;
|
|
170
|
+
color: #1e40af;
|
|
171
|
+
padding: 0.25rem 0.75rem;
|
|
172
|
+
border-radius: 9999px;
|
|
173
|
+
font-size: 0.8rem;
|
|
174
|
+
font-family: ui-monospace, monospace;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.script-list {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 0.5rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.script-item {
|
|
184
|
+
display: flex;
|
|
185
|
+
align-items: center;
|
|
186
|
+
gap: 0.75rem;
|
|
187
|
+
padding: 0.75rem 1rem;
|
|
188
|
+
background: #f9fafb;
|
|
189
|
+
border-radius: 8px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.script-icon {
|
|
193
|
+
width: 20px;
|
|
194
|
+
height: 20px;
|
|
195
|
+
color: #6b7280;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.script-name {
|
|
199
|
+
font-family: ui-monospace, monospace;
|
|
200
|
+
font-size: 0.9rem;
|
|
201
|
+
color: #111827;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.keyword-list {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-wrap: wrap;
|
|
207
|
+
gap: 0.5rem;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.keyword-tag {
|
|
211
|
+
background: #fef3c7;
|
|
212
|
+
color: #92400e;
|
|
213
|
+
padding: 0.25rem 0.75rem;
|
|
214
|
+
border-radius: 9999px;
|
|
215
|
+
font-size: 0.8rem;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.instructions-preview {
|
|
219
|
+
background: #f9fafb;
|
|
220
|
+
border: 1px solid #e5e7eb;
|
|
221
|
+
border-radius: 8px;
|
|
222
|
+
padding: 1rem;
|
|
223
|
+
max-height: 300px;
|
|
224
|
+
overflow-y: auto;
|
|
225
|
+
font-size: 0.875rem;
|
|
226
|
+
line-height: 1.6;
|
|
227
|
+
color: #374151;
|
|
228
|
+
white-space: pre-wrap;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.endpoint-box {
|
|
232
|
+
display: flex;
|
|
233
|
+
align-items: center;
|
|
234
|
+
gap: 0.75rem;
|
|
235
|
+
background: #f3f4f6;
|
|
236
|
+
padding: 0.75rem 1rem;
|
|
237
|
+
border-radius: 8px;
|
|
238
|
+
margin-top: 0.5rem;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.endpoint-box code {
|
|
242
|
+
flex: 1;
|
|
243
|
+
font-family: ui-monospace, monospace;
|
|
244
|
+
font-size: 0.875rem;
|
|
245
|
+
color: #1f2937;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.copy-btn {
|
|
249
|
+
background: #e5e7eb;
|
|
250
|
+
border: none;
|
|
251
|
+
padding: 0.5rem;
|
|
252
|
+
border-radius: 6px;
|
|
253
|
+
cursor: pointer;
|
|
254
|
+
color: #6b7280;
|
|
255
|
+
transition: all 0.15s;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.copy-btn:hover {
|
|
259
|
+
background: #d1d5db;
|
|
260
|
+
color: #374151;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.copy-btn svg {
|
|
264
|
+
width: 16px;
|
|
265
|
+
height: 16px;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.empty-state {
|
|
269
|
+
text-align: center;
|
|
270
|
+
padding: 3rem;
|
|
271
|
+
color: #9ca3af;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.tool-type-badge {
|
|
275
|
+
background: #6366f1;
|
|
276
|
+
color: white;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.skill-type-badge {
|
|
280
|
+
background: #10b981;
|
|
281
|
+
color: white;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@media (prefers-color-scheme: dark) {
|
|
285
|
+
.nav a {
|
|
286
|
+
color: #9ca3af;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.nav a:hover {
|
|
290
|
+
color: #60a5fa;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.detail-card {
|
|
294
|
+
background: rgba(15, 23, 42, 0.96);
|
|
295
|
+
box-shadow:
|
|
296
|
+
0 18px 40px rgba(15, 23, 42, 0.9),
|
|
297
|
+
0 0 0 1px rgba(15, 23, 42, 0.9);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.detail-header {
|
|
301
|
+
border-bottom-color: rgba(55, 65, 81, 0.9);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.detail-title {
|
|
305
|
+
color: #e5e7eb;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.detail-desc {
|
|
309
|
+
color: #9ca3af;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.detail-section-title {
|
|
313
|
+
color: #9ca3af;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.info-item {
|
|
317
|
+
background: rgba(15, 23, 42, 0.9);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.info-value {
|
|
321
|
+
color: #e5e7eb;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.info-value code {
|
|
325
|
+
background: rgba(31, 41, 55, 0.9);
|
|
326
|
+
color: #e5e7eb;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.script-item {
|
|
330
|
+
background: rgba(15, 23, 42, 0.9);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.script-name {
|
|
334
|
+
color: #e5e7eb;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.keyword-tag {
|
|
338
|
+
background: rgba(250, 204, 21, 0.12);
|
|
339
|
+
color: #facc15;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.instructions-preview {
|
|
343
|
+
background: rgba(15, 23, 42, 0.9);
|
|
344
|
+
border-color: rgba(55, 65, 81, 0.9);
|
|
345
|
+
color: #e5e7eb;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.endpoint-box {
|
|
349
|
+
background: rgba(31, 41, 55, 0.95);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.endpoint-box code {
|
|
353
|
+
color: #e5e7eb;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.copy-btn {
|
|
357
|
+
background: rgba(55, 65, 81, 0.95);
|
|
358
|
+
color: #e5e7eb;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.copy-btn:hover {
|
|
362
|
+
background: rgba(75, 85, 99, 0.98);
|
|
363
|
+
color: #f9fafb;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.empty-state {
|
|
367
|
+
color: #9ca3af;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
`;
|
|
371
|
+
/**
|
|
372
|
+
* Syntax highlight JSON
|
|
373
|
+
*/
|
|
374
|
+
function highlightJson(obj) {
|
|
375
|
+
const json = JSON.stringify(obj, null, 2);
|
|
376
|
+
return json
|
|
377
|
+
.replace(/"([^"]+)":/g, '<span class="key">"$1"</span>:')
|
|
378
|
+
.replace(/: "([^"]*)"([,\n])/g, ': <span class="string">"$1"</span>$2')
|
|
379
|
+
.replace(/: (\d+)([,\n])/g, ': <span class="number">$1</span>$2')
|
|
380
|
+
.replace(/: (true|false)([,\n])/g, ': <span class="boolean">$1</span>$2')
|
|
381
|
+
.replace(/: (null)([,\n])/g, ': <span class="null">$1</span>$2');
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Back navigation arrow
|
|
385
|
+
*/
|
|
386
|
+
const backArrow = /*html*/ `
|
|
387
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
388
|
+
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
389
|
+
</svg>`;
|
|
390
|
+
/**
|
|
391
|
+
* Copy icon
|
|
392
|
+
*/
|
|
393
|
+
const copyIcon = /*html*/ `
|
|
394
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
395
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
|
396
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
397
|
+
</svg>`;
|
|
398
|
+
/**
|
|
399
|
+
* File icon
|
|
400
|
+
*/
|
|
401
|
+
const fileIcon = /*html*/ `
|
|
402
|
+
<svg class="script-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
403
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
404
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
405
|
+
</svg>`;
|
|
406
|
+
/**
|
|
407
|
+
* Render a collection card for the index page
|
|
408
|
+
*/
|
|
409
|
+
function collectionCard(collection, pathPrefix, meta) {
|
|
410
|
+
return /*html*/ `
|
|
411
|
+
<a class="card" href="/${pathPrefix}/${collection.name}" data-collection-type="${pathPrefix}" data-collection-name="${collection.name}">
|
|
412
|
+
<div class="card-icon">${collection.icon || defaultIcon}</div>
|
|
413
|
+
<div class="card-title">${collection.title || collection.name}</div>
|
|
414
|
+
<div class="card-desc">${collection.description || ''}</div>
|
|
415
|
+
${meta ? `<div class="card-meta">${meta}</div>` : ''}
|
|
416
|
+
</a>`;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Render a tool card (simple version for lists)
|
|
420
|
+
*/
|
|
421
|
+
function toolCard(tool) {
|
|
422
|
+
return /*html*/ `
|
|
423
|
+
<div class="item-card">
|
|
424
|
+
<div class="item-name">${tool.name}</div>
|
|
425
|
+
<div class="item-desc">${tool.description || ''}</div>
|
|
426
|
+
${tool.input_schema ? /*html*/ `
|
|
427
|
+
<div class="item-schema">${JSON.stringify(tool.input_schema, null, 2)}</div>
|
|
428
|
+
` : ''}
|
|
429
|
+
</div>`;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Render an MCP provider card
|
|
433
|
+
*/
|
|
434
|
+
function mcpProviderCard(provider) {
|
|
435
|
+
return /*html*/ `
|
|
436
|
+
<a class="card" href="/api/mcp/${provider.name}">
|
|
437
|
+
<div class="card-title">${provider.name}</div>
|
|
438
|
+
<div class="card-desc">${provider.description || ''}</div>
|
|
439
|
+
</a>`;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Render a detailed tool card
|
|
443
|
+
*/
|
|
444
|
+
function toolDetailCard(tool, collectionName) {
|
|
445
|
+
const schema = tool.input_schema;
|
|
446
|
+
const properties = schema?.properties;
|
|
447
|
+
const required = schema?.required;
|
|
448
|
+
return /*html*/ `
|
|
449
|
+
<div class="detail-card">
|
|
450
|
+
<div class="detail-header">
|
|
451
|
+
<div>
|
|
452
|
+
<h3 class="detail-title">${tool.name}</h3>
|
|
453
|
+
<p class="detail-desc">${tool.description || 'No description'}</p>
|
|
454
|
+
</div>
|
|
455
|
+
<div class="detail-badges">
|
|
456
|
+
<span class="badge tool-type-badge">Tool</span>
|
|
457
|
+
</div>
|
|
458
|
+
</div>
|
|
459
|
+
<div class="detail-body">
|
|
460
|
+
<div class="detail-section">
|
|
461
|
+
<h4 class="detail-section-title">Endpoint</h4>
|
|
462
|
+
<div class="endpoint-box">
|
|
463
|
+
<code>POST /api/tools/${collectionName}</code>
|
|
464
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText('/api/tools/${collectionName}')" title="Copy">
|
|
465
|
+
${copyIcon}
|
|
466
|
+
</button>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
|
|
470
|
+
${schema ? /*html*/ `
|
|
471
|
+
<div class="detail-section">
|
|
472
|
+
<h4 class="detail-section-title">Input Schema</h4>
|
|
473
|
+
${properties ? /*html*/ `
|
|
474
|
+
<div class="info-grid" style="margin-bottom: 1rem;">
|
|
475
|
+
${Object.entries(properties).map(([key, value]) => {
|
|
476
|
+
const prop = value;
|
|
477
|
+
const isRequired = required?.includes(key);
|
|
478
|
+
return /*html*/ `
|
|
479
|
+
<div class="info-item">
|
|
480
|
+
<div class="info-label">${key}${isRequired ? ' *' : ''}</div>
|
|
481
|
+
<div class="info-value">
|
|
482
|
+
<code>${prop.type || 'any'}</code>
|
|
483
|
+
${prop.description ? `<br><span style="color: #6b7280; font-size: 0.85rem;">${prop.description}</span>` : ''}
|
|
484
|
+
</div>
|
|
485
|
+
</div>`;
|
|
486
|
+
}).join('')}
|
|
487
|
+
</div>
|
|
488
|
+
` : ''}
|
|
489
|
+
<details>
|
|
490
|
+
<summary style="cursor: pointer; color: #6b7280; font-size: 0.85rem;">View full schema</summary>
|
|
491
|
+
<div class="schema-block" style="margin-top: 0.75rem;">${highlightJson(schema)}</div>
|
|
492
|
+
</details>
|
|
493
|
+
</div>
|
|
494
|
+
` : /*html*/ `
|
|
495
|
+
<div class="detail-section">
|
|
496
|
+
<div class="empty-state">No input schema defined</div>
|
|
497
|
+
</div>
|
|
498
|
+
`}
|
|
499
|
+
</div>
|
|
500
|
+
</div>`;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Render a skill card (simple version for lists)
|
|
504
|
+
*/
|
|
505
|
+
function skillCard(skill) {
|
|
506
|
+
return /*html*/ `
|
|
507
|
+
<div class="item-card skill">
|
|
508
|
+
<div class="item-name">${skill.name}</div>
|
|
509
|
+
<div class="item-desc">${skill.description || ''}</div>
|
|
510
|
+
<div class="item-meta">
|
|
511
|
+
<span class="badge ${skill.execution?.language || ''}">${skill.content_type === 'jst' ? 'Dynamic' : 'Static'}</span>
|
|
512
|
+
${skill.execution?.language ? `<span class="badge ${skill.execution.language}">${skill.execution.language}</span>` : ''}
|
|
513
|
+
${skill.scripts?.length ? `<span class="badge">${skill.scripts.length} script${skill.scripts.length > 1 ? 's' : ''}</span>` : ''}
|
|
514
|
+
</div>
|
|
515
|
+
</div>`;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Render a detailed skill card
|
|
519
|
+
*/
|
|
520
|
+
function skillDetailCard(skill) {
|
|
521
|
+
const hasKeywords = skill.context_triggers?.keywords?.length;
|
|
522
|
+
const hasPackages = skill.execution?.packages?.length;
|
|
523
|
+
const hasScripts = skill.scripts?.length;
|
|
524
|
+
return /*html*/ `
|
|
525
|
+
<div class="detail-card">
|
|
526
|
+
<div class="detail-header">
|
|
527
|
+
<div>
|
|
528
|
+
<h3 class="detail-title">${skill.name}</h3>
|
|
529
|
+
<p class="detail-desc">${skill.description || 'No description'}</p>
|
|
530
|
+
</div>
|
|
531
|
+
<div class="detail-badges">
|
|
532
|
+
<span class="badge skill-type-badge">Skill</span>
|
|
533
|
+
${skill.execution?.language ? `<span class="badge ${skill.execution.language}">${skill.execution.language}</span>` : ''}
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
<div class="detail-body">
|
|
537
|
+
<div class="info-grid">
|
|
538
|
+
<div class="info-item">
|
|
539
|
+
<div class="info-label">Content Type</div>
|
|
540
|
+
<div class="info-value">${skill.content_type === 'jst' ? 'Dynamic (JST Template)' : 'Static (Markdown)'}</div>
|
|
541
|
+
</div>
|
|
542
|
+
${skill.execution?.language ? /*html*/ `
|
|
543
|
+
<div class="info-item">
|
|
544
|
+
<div class="info-label">Language</div>
|
|
545
|
+
<div class="info-value"><code>${skill.execution.language}</code></div>
|
|
546
|
+
</div>
|
|
547
|
+
` : ''}
|
|
548
|
+
</div>
|
|
549
|
+
|
|
550
|
+
${hasKeywords ? /*html*/ `
|
|
551
|
+
<div class="detail-section">
|
|
552
|
+
<h4 class="detail-section-title">Trigger Keywords</h4>
|
|
553
|
+
<div class="keyword-list">
|
|
554
|
+
${skill.context_triggers?.keywords?.map(kw => `<span class="keyword-tag">${kw}</span>`).join('')}
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
` : ''}
|
|
558
|
+
|
|
559
|
+
${hasPackages ? /*html*/ `
|
|
560
|
+
<div class="detail-section">
|
|
561
|
+
<h4 class="detail-section-title">Required Packages</h4>
|
|
562
|
+
<div class="package-list">
|
|
563
|
+
${skill.execution?.packages?.map(pkg => `<span class="package-tag">${pkg}</span>`).join('')}
|
|
564
|
+
</div>
|
|
565
|
+
</div>
|
|
566
|
+
` : ''}
|
|
567
|
+
|
|
568
|
+
${hasScripts ? /*html*/ `
|
|
569
|
+
<div class="detail-section">
|
|
570
|
+
<h4 class="detail-section-title">Bundled Scripts</h4>
|
|
571
|
+
<div class="script-list">
|
|
572
|
+
${skill.scripts?.map(script => /*html*/ `
|
|
573
|
+
<div class="script-item">
|
|
574
|
+
${fileIcon}
|
|
575
|
+
<span class="script-name">${script.name}</span>
|
|
576
|
+
</div>
|
|
577
|
+
`).join('')}
|
|
578
|
+
</div>
|
|
579
|
+
</div>
|
|
580
|
+
` : ''}
|
|
581
|
+
|
|
582
|
+
<div class="detail-section">
|
|
583
|
+
<h4 class="detail-section-title">Instructions Preview</h4>
|
|
584
|
+
<div class="instructions-preview">${escapeHtml(skill.instructions.slice(0, 1000))}${skill.instructions.length > 1000 ? '...' : ''}</div>
|
|
585
|
+
</div>
|
|
586
|
+
</div>
|
|
587
|
+
</div>`;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Escape HTML for safe rendering
|
|
591
|
+
*/
|
|
592
|
+
function escapeHtml(str) {
|
|
593
|
+
return str
|
|
594
|
+
.replace(/&/g, '&')
|
|
595
|
+
.replace(/</g, '<')
|
|
596
|
+
.replace(/>/g, '>')
|
|
597
|
+
.replace(/"/g, '"')
|
|
598
|
+
.replace(/'/g, ''');
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Derive simple initials from a title for use in the hero avatar.
|
|
602
|
+
*/
|
|
603
|
+
function getInitials(title) {
|
|
604
|
+
const words = title.trim().split(/\s+/).filter(Boolean);
|
|
605
|
+
if (!words.length)
|
|
606
|
+
return "TS";
|
|
607
|
+
const initials = words
|
|
608
|
+
.slice(0, 2)
|
|
609
|
+
.map((word) => word.charAt(0).toUpperCase())
|
|
610
|
+
.join("");
|
|
611
|
+
return initials || "TS";
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Render the main index page
|
|
615
|
+
*
|
|
616
|
+
* Note: The fourth argument is backward compatible:
|
|
617
|
+
* - If a string is passed, it is treated as the title.
|
|
618
|
+
* - If an array is passed, it is treated as MCP providers and the fifth argument (if any) is the title.
|
|
619
|
+
*/
|
|
620
|
+
function indexPage(tools, skills, interactions, mcpProvidersOrTitle, titleParam) {
|
|
621
|
+
let mcpProviders = [];
|
|
622
|
+
let title = "Tools Server";
|
|
623
|
+
if (Array.isArray(mcpProvidersOrTitle)) {
|
|
624
|
+
mcpProviders = mcpProvidersOrTitle;
|
|
625
|
+
if (typeof titleParam === "string" && titleParam.length > 0) {
|
|
626
|
+
title = titleParam;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
else if (typeof mcpProvidersOrTitle === "string" && mcpProvidersOrTitle.length > 0) {
|
|
630
|
+
title = mcpProvidersOrTitle;
|
|
631
|
+
}
|
|
632
|
+
else if (typeof titleParam === "string" && titleParam.length > 0) {
|
|
633
|
+
title = titleParam;
|
|
634
|
+
}
|
|
635
|
+
return /*html*/ `
|
|
636
|
+
<!DOCTYPE html>
|
|
637
|
+
<html lang="en">
|
|
638
|
+
<head>
|
|
639
|
+
<meta charset="UTF-8">
|
|
640
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
641
|
+
<title>${title}</title>
|
|
642
|
+
<style>${styles_js_1.baseStyles}</style>
|
|
643
|
+
</head>
|
|
644
|
+
<body>
|
|
645
|
+
<div class="page">
|
|
646
|
+
<header class="hero">
|
|
647
|
+
<div class="hero-main">
|
|
648
|
+
<div class="hero-logo">
|
|
649
|
+
<span class="hero-logo-initial">${escapeHtml(getInitials(title))}</span>
|
|
650
|
+
</div>
|
|
651
|
+
<div class="hero-meta">
|
|
652
|
+
<p class="hero-eyebrow">Tools Server</p>
|
|
653
|
+
<h1 class="hero-title">${title}</h1>
|
|
654
|
+
<p class="hero-tagline">
|
|
655
|
+
Discover the tools, skills, and interactions exposed by this server.
|
|
656
|
+
</p>
|
|
657
|
+
<div class="hero-summary">
|
|
658
|
+
${tools.length ? /*html*/ `<span><dot></dot> ${tools.length} tool collection${tools.length !== 1 ? 's' : ''}</span>` : ''}
|
|
659
|
+
${skills.length ? /*html*/ `<span><dot></dot> ${skills.length} skill collection${skills.length !== 1 ? 's' : ''}</span>` : ''}
|
|
660
|
+
${interactions.length ? /*html*/ `<span><dot></dot> ${interactions.length} interaction collection${interactions.length !== 1 ? 's' : ''}</span>` : ''}
|
|
661
|
+
${mcpProviders.length ? /*html*/ `<span><dot></dot> ${mcpProviders.length} MCP provider${mcpProviders.length !== 1 ? 's' : ''}</span>` : ''}
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
</div>
|
|
665
|
+
<aside class="hero-panel">
|
|
666
|
+
<div class="hero-panel-label">Base endpoint</div>
|
|
667
|
+
<div class="hero-panel-endpoint"><code>/api</code></div>
|
|
668
|
+
<p class="hero-panel-hint">
|
|
669
|
+
Use <strong>POST /api/tools/<collection></strong> or
|
|
670
|
+
<strong>POST /api/skills/<collection></strong> to call these from your apps or agents.
|
|
671
|
+
</p>
|
|
672
|
+
</aside>
|
|
673
|
+
</header>
|
|
674
|
+
|
|
675
|
+
<div class="search-bar">
|
|
676
|
+
<input
|
|
677
|
+
type="search"
|
|
678
|
+
id="collection-search"
|
|
679
|
+
class="search-input"
|
|
680
|
+
placeholder="Search tools, skills, interactions..."
|
|
681
|
+
aria-label="Search collections"
|
|
682
|
+
autocomplete="off"
|
|
683
|
+
/>
|
|
684
|
+
<p class="search-hint">
|
|
685
|
+
Filter collections by name or description. Search runs locally in your browser.
|
|
686
|
+
</p>
|
|
687
|
+
<p id="search-empty" class="search-empty" style="display: none;">
|
|
688
|
+
No collections match this search.
|
|
689
|
+
</p>
|
|
690
|
+
</div>
|
|
691
|
+
|
|
692
|
+
${tools.length > 0 ? /*html*/ `
|
|
693
|
+
<section data-section="tools">
|
|
694
|
+
<div class="section-header">
|
|
695
|
+
<h2>Tool Collections</h2>
|
|
696
|
+
<p class="section-subtitle">Remote tools available to agents via Vertesia.</p>
|
|
697
|
+
</div>
|
|
698
|
+
<div class="card-grid">
|
|
699
|
+
${tools.map(t => collectionCard(t, 'tools')).join('')}
|
|
700
|
+
</div>
|
|
701
|
+
</section>
|
|
702
|
+
` : ''}
|
|
703
|
+
|
|
704
|
+
${skills.length > 0 ? /*html*/ `
|
|
705
|
+
<section data-section="skills">
|
|
706
|
+
<hr>
|
|
707
|
+
<div class="section-header">
|
|
708
|
+
<h2>Skill Collections</h2>
|
|
709
|
+
<p class="section-subtitle">Reusable instructions and scripts packaged as tools.</p>
|
|
710
|
+
</div>
|
|
711
|
+
<div class="card-grid">
|
|
712
|
+
${skills.map(s => {
|
|
713
|
+
const count = Array.from(s).length;
|
|
714
|
+
return collectionCard(s, 'skills', `${count} skill${count !== 1 ? 's' : ''}`);
|
|
715
|
+
}).join('')}
|
|
716
|
+
</div>
|
|
717
|
+
</section>
|
|
718
|
+
` : ''}
|
|
719
|
+
|
|
720
|
+
${interactions.length > 0 ? /*html*/ `
|
|
721
|
+
<section data-section="interactions">
|
|
722
|
+
<hr>
|
|
723
|
+
<div class="section-header">
|
|
724
|
+
<h2>Interaction Collections</h2>
|
|
725
|
+
<p class="section-subtitle">Conversation blueprints surfaced in the Vertesia UI.</p>
|
|
726
|
+
</div>
|
|
727
|
+
<div class="card-grid">
|
|
728
|
+
${interactions.map(i => collectionCard(i, 'interactions')).join('')}
|
|
729
|
+
</div>
|
|
730
|
+
</section>
|
|
731
|
+
` : ''}
|
|
732
|
+
|
|
733
|
+
${mcpProviders.length > 0 ? /*html*/ `
|
|
734
|
+
<section data-section="mcp">
|
|
735
|
+
<hr>
|
|
736
|
+
<div class="section-header">
|
|
737
|
+
<h2>MCP Providers</h2>
|
|
738
|
+
<p class="section-subtitle">Remote MCP servers available through this tools server.</p>
|
|
739
|
+
</div>
|
|
740
|
+
<div class="card-grid">
|
|
741
|
+
${mcpProviders.map(p => mcpProviderCard(p)).join('')}
|
|
742
|
+
</div>
|
|
743
|
+
</section>
|
|
744
|
+
` : ''}
|
|
745
|
+
</div>
|
|
746
|
+
<script>
|
|
747
|
+
(function () {
|
|
748
|
+
var input = document.getElementById('collection-search');
|
|
749
|
+
if (!input) return;
|
|
750
|
+
|
|
751
|
+
var cards = Array.prototype.slice.call(document.querySelectorAll('.card'));
|
|
752
|
+
if (!cards.length) return;
|
|
753
|
+
|
|
754
|
+
var sections = Array.prototype.slice.call(document.querySelectorAll('[data-section]'));
|
|
755
|
+
var emptyState = document.getElementById('search-empty');
|
|
756
|
+
|
|
757
|
+
function normalize(value) {
|
|
758
|
+
return (value || '').toString().toLowerCase();
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function update(query) {
|
|
762
|
+
var q = normalize(query).trim();
|
|
763
|
+
var anyVisible = false;
|
|
764
|
+
|
|
765
|
+
cards.forEach(function (card) {
|
|
766
|
+
var text = normalize(card.textContent);
|
|
767
|
+
var match = !q || text.indexOf(q) !== -1;
|
|
768
|
+
card.style.display = match ? '' : 'none';
|
|
769
|
+
if (match) anyVisible = true;
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
sections.forEach(function (section) {
|
|
773
|
+
var visibleCards = section.querySelectorAll('.card');
|
|
774
|
+
var hasVisible = false;
|
|
775
|
+
for (var i = 0; i < visibleCards.length; i++) {
|
|
776
|
+
var style = window.getComputedStyle(visibleCards[i]);
|
|
777
|
+
if (style.display !== 'none') {
|
|
778
|
+
hasVisible = true;
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
section.style.display = hasVisible ? '' : 'none';
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
if (emptyState) {
|
|
786
|
+
emptyState.style.display = q && !anyVisible ? '' : 'none';
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
input.addEventListener('input', function () {
|
|
791
|
+
update(input.value);
|
|
792
|
+
});
|
|
793
|
+
}());
|
|
794
|
+
</script>
|
|
795
|
+
</body>
|
|
796
|
+
</html>`;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Render a tool collection detail page
|
|
800
|
+
*/
|
|
801
|
+
function toolCollectionPage(collection) {
|
|
802
|
+
const toolsArray = Array.from(collection);
|
|
803
|
+
return /*html*/ `
|
|
804
|
+
<!DOCTYPE html>
|
|
805
|
+
<html lang="en">
|
|
806
|
+
<head>
|
|
807
|
+
<meta charset="UTF-8">
|
|
808
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
809
|
+
<title>${collection.title || collection.name} - Tools</title>
|
|
810
|
+
<style>${detailStyles}</style>
|
|
811
|
+
</head>
|
|
812
|
+
<body>
|
|
813
|
+
<nav class="nav">
|
|
814
|
+
<a href="/">${backArrow} Back to all collections</a>
|
|
815
|
+
</nav>
|
|
816
|
+
|
|
817
|
+
<div class="header">
|
|
818
|
+
<div class="header-icon">${collection.icon || defaultIcon}</div>
|
|
819
|
+
<div>
|
|
820
|
+
<h1>${collection.title || collection.name}</h1>
|
|
821
|
+
<p style="color: #6b7280; margin: 0.25rem 0 0 0;">${collection.description || ''}</p>
|
|
822
|
+
<div class="endpoint-box">
|
|
823
|
+
<code>/api/tools/${collection.name}</code>
|
|
824
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '/api/tools/${collection.name}')" title="Copy endpoint URL">
|
|
825
|
+
${copyIcon}
|
|
826
|
+
</button>
|
|
827
|
+
</div>
|
|
828
|
+
</div>
|
|
829
|
+
</div>
|
|
830
|
+
|
|
831
|
+
<h2>${toolsArray.length} Tool${toolsArray.length !== 1 ? 's' : ''}</h2>
|
|
832
|
+
|
|
833
|
+
${toolsArray.length > 0 ?
|
|
834
|
+
toolsArray.map(tool => toolDetailCard(tool, collection.name)).join('') :
|
|
835
|
+
'<div class="empty-state">No tools in this collection</div>'}
|
|
836
|
+
</body>
|
|
837
|
+
</html>`;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Render a skill collection detail page
|
|
841
|
+
*/
|
|
842
|
+
function skillCollectionPage(collection) {
|
|
843
|
+
const skillsArray = Array.from(collection);
|
|
844
|
+
return /*html*/ `
|
|
845
|
+
<!DOCTYPE html>
|
|
846
|
+
<html lang="en">
|
|
847
|
+
<head>
|
|
848
|
+
<meta charset="UTF-8">
|
|
849
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
850
|
+
<title>${collection.title || collection.name} - Skills</title>
|
|
851
|
+
<style>${detailStyles}</style>
|
|
852
|
+
</head>
|
|
853
|
+
<body>
|
|
854
|
+
<nav class="nav">
|
|
855
|
+
<a href="/">${backArrow} Back to all collections</a>
|
|
856
|
+
</nav>
|
|
857
|
+
|
|
858
|
+
<div class="header">
|
|
859
|
+
<div class="header-icon">${collection.icon || skillIcon}</div>
|
|
860
|
+
<div>
|
|
861
|
+
<h1>${collection.title || collection.name}</h1>
|
|
862
|
+
<p style="color: #6b7280; margin: 0.25rem 0 0 0;">${collection.description || ''}</p>
|
|
863
|
+
<div class="endpoint-box">
|
|
864
|
+
<code>/api/skills/${collection.name}</code>
|
|
865
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '/api/skills/${collection.name}')" title="Copy endpoint URL">
|
|
866
|
+
${copyIcon}
|
|
867
|
+
</button>
|
|
868
|
+
</div>
|
|
869
|
+
</div>
|
|
870
|
+
</div>
|
|
871
|
+
|
|
872
|
+
<h2>${skillsArray.length} Skill${skillsArray.length !== 1 ? 's' : ''}</h2>
|
|
873
|
+
|
|
874
|
+
${skillsArray.length > 0 ?
|
|
875
|
+
skillsArray.map(skill => skillDetailCard(skill)).join('') :
|
|
876
|
+
'<div class="empty-state">No skills in this collection</div>'}
|
|
877
|
+
</body>
|
|
878
|
+
</html>`;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Render an interaction collection detail page
|
|
882
|
+
*/
|
|
883
|
+
function interactionCollectionPage(collection) {
|
|
884
|
+
return /*html*/ `
|
|
885
|
+
<!DOCTYPE html>
|
|
886
|
+
<html lang="en">
|
|
887
|
+
<head>
|
|
888
|
+
<meta charset="UTF-8">
|
|
889
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
890
|
+
<title>${collection.title || collection.name} - Interactions</title>
|
|
891
|
+
<style>${detailStyles}</style>
|
|
892
|
+
</head>
|
|
893
|
+
<body>
|
|
894
|
+
<nav class="nav">
|
|
895
|
+
<a href="/">${backArrow} Back to all collections</a>
|
|
896
|
+
</nav>
|
|
897
|
+
|
|
898
|
+
<div class="header">
|
|
899
|
+
<div class="header-icon">${collection.icon || defaultIcon}</div>
|
|
900
|
+
<div>
|
|
901
|
+
<h1>${collection.title || collection.name}</h1>
|
|
902
|
+
<p style="color: #6b7280; margin: 0.25rem 0 0 0;">${collection.description || ''}</p>
|
|
903
|
+
<div class="endpoint-box">
|
|
904
|
+
<code>/api/interactions/${collection.name}</code>
|
|
905
|
+
<button class="copy-btn" onclick="navigator.clipboard.writeText(window.location.origin + '/api/interactions/${collection.name}')" title="Copy endpoint URL">
|
|
906
|
+
${copyIcon}
|
|
907
|
+
</button>
|
|
908
|
+
</div>
|
|
909
|
+
</div>
|
|
910
|
+
</div>
|
|
911
|
+
|
|
912
|
+
<h2>${collection.interactions.length} Interaction${collection.interactions.length !== 1 ? 's' : ''}</h2>
|
|
913
|
+
|
|
914
|
+
<div class="item-list">
|
|
915
|
+
${collection.interactions.map(inter => /*html*/ `
|
|
916
|
+
<div class="detail-card">
|
|
917
|
+
<div class="detail-header">
|
|
918
|
+
<div>
|
|
919
|
+
<h3 class="detail-title">${inter.name}</h3>
|
|
920
|
+
<p class="detail-desc">${inter.description || 'No description'}</p>
|
|
921
|
+
</div>
|
|
922
|
+
<div class="detail-badges">
|
|
923
|
+
${inter.tags?.map(tag => `<span class="badge">${tag}</span>`).join('') || ''}
|
|
924
|
+
</div>
|
|
925
|
+
</div>
|
|
926
|
+
</div>
|
|
927
|
+
`).join('')}
|
|
928
|
+
</div>
|
|
929
|
+
</body>
|
|
930
|
+
</html>`;
|
|
931
|
+
}
|
|
932
|
+
//# sourceMappingURL=templates.js.map
|