@vertesia/tools-sdk 1.0.0-dev.20260203.130115Z → 1.0.0-dev.20260225.024852Z

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