@vertesia/tools-admin-ui 1.3.0 → 1.4.0-dev.20260615.042549Z

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 (77) hide show
  1. package/LICENSE +198 -10
  2. package/lib/AdminApp.d.ts +1 -1
  3. package/lib/AdminApp.d.ts.map +1 -1
  4. package/lib/components/AdminTopBar.d.ts +1 -1
  5. package/lib/components/AdminTopBar.d.ts.map +1 -1
  6. package/lib/components/CollectionCard.d.ts +1 -1
  7. package/lib/components/CollectionCard.d.ts.map +1 -1
  8. package/lib/components/DetailPage.d.ts +1 -1
  9. package/lib/components/DetailPage.d.ts.map +1 -1
  10. package/lib/components/EndpointPanel.d.ts +1 -1
  11. package/lib/components/EndpointPanel.d.ts.map +1 -1
  12. package/lib/components/HeroSection.d.ts +1 -1
  13. package/lib/components/HeroSection.d.ts.map +1 -1
  14. package/lib/components/ResourceCard.d.ts +1 -1
  15. package/lib/components/ResourceCard.d.ts.map +1 -1
  16. package/lib/components/ResourceSection.d.ts +1 -1
  17. package/lib/components/ResourceSection.d.ts.map +1 -1
  18. package/lib/components/SearchBar.d.ts +1 -1
  19. package/lib/components/SearchBar.d.ts.map +1 -1
  20. package/lib/components/SummaryBadge.d.ts +1 -1
  21. package/lib/components/SummaryBadge.d.ts.map +1 -1
  22. package/lib/hooks.d.ts +2 -2
  23. package/lib/hooks.d.ts.map +1 -1
  24. package/lib/index.d.ts +4 -4
  25. package/lib/index.d.ts.map +1 -1
  26. package/lib/pages/ActivityCollection.d.ts +1 -1
  27. package/lib/pages/ActivityCollection.d.ts.map +1 -1
  28. package/lib/pages/HomePage.d.ts +1 -1
  29. package/lib/pages/HomePage.d.ts.map +1 -1
  30. package/lib/pages/InteractionCollection.d.ts +1 -1
  31. package/lib/pages/InteractionCollection.d.ts.map +1 -1
  32. package/lib/pages/InteractionDetail.d.ts +1 -1
  33. package/lib/pages/InteractionDetail.d.ts.map +1 -1
  34. package/lib/pages/SkillCollection.d.ts +1 -1
  35. package/lib/pages/SkillCollection.d.ts.map +1 -1
  36. package/lib/pages/SkillDetail.d.ts +1 -1
  37. package/lib/pages/SkillDetail.d.ts.map +1 -1
  38. package/lib/pages/TemplateCollection.d.ts +1 -1
  39. package/lib/pages/TemplateCollection.d.ts.map +1 -1
  40. package/lib/pages/TemplateDetail.d.ts +1 -1
  41. package/lib/pages/TemplateDetail.d.ts.map +1 -1
  42. package/lib/pages/ToolCollection.d.ts +1 -1
  43. package/lib/pages/ToolCollection.d.ts.map +1 -1
  44. package/lib/pages/TypeCollection.d.ts +1 -1
  45. package/lib/pages/TypeCollection.d.ts.map +1 -1
  46. package/lib/pages/TypeDetail.d.ts +1 -1
  47. package/lib/pages/TypeDetail.d.ts.map +1 -1
  48. package/lib/tools-admin-ui.js +1484 -969
  49. package/lib/tools-admin-ui.js.map +1 -1
  50. package/lib/types.d.ts.map +1 -1
  51. package/package.json +16 -14
  52. package/src/AdminApp.tsx +14 -15
  53. package/src/components/AdminTopBar.tsx +7 -7
  54. package/src/components/CollectionCard.tsx +3 -1
  55. package/src/components/DetailPage.tsx +10 -4
  56. package/src/components/EndpointPanel.tsx +2 -9
  57. package/src/components/HeroSection.tsx +12 -3
  58. package/src/components/ResourceCard.tsx +8 -6
  59. package/src/components/ResourceSection.tsx +1 -1
  60. package/src/components/SearchBar.tsx +1 -5
  61. package/src/components/SummaryBadge.tsx +2 -1
  62. package/src/dev/env.ts +8 -8
  63. package/src/dev/main.tsx +20 -15
  64. package/src/hooks.ts +19 -12
  65. package/src/index.ts +4 -4
  66. package/src/pages/ActivityCollection.tsx +30 -12
  67. package/src/pages/HomePage.tsx +65 -57
  68. package/src/pages/InteractionCollection.tsx +26 -11
  69. package/src/pages/InteractionDetail.tsx +28 -13
  70. package/src/pages/SkillCollection.tsx +38 -18
  71. package/src/pages/SkillDetail.tsx +37 -13
  72. package/src/pages/TemplateCollection.tsx +28 -17
  73. package/src/pages/TemplateDetail.tsx +13 -7
  74. package/src/pages/ToolCollection.tsx +21 -10
  75. package/src/pages/TypeCollection.tsx +26 -17
  76. package/src/pages/TypeDetail.tsx +12 -6
  77. package/src/types.ts +16 -35
@@ -1,1037 +1,1552 @@
1
- import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
- import { ModeToggle, Avatar, Button, useFetch, Badge, Spinner, Card, CardContent, DotBadge, Separator, Input } from "@vertesia/ui/core";
3
- import { NavLink, useParams, NestedRouterProvider, RouteComponent } from "@vertesia/ui/router";
4
- import { createContext, useContext, useState, useMemo } from "react";
1
+ import { Avatar, Badge, Button, Card, CardContent, DotBadge, Input, ModeToggle, Separator, Spinner, useFetch } from "@vertesia/ui/core";
2
+ import { NavLink, NestedRouterProvider, RouteComponent, useParams } from "@vertesia/ui/router";
3
+ import { createContext, useContext, useMemo, useState } from "react";
5
4
  import { useUserSession } from "@vertesia/ui/session";
6
- import { LogOut, ArrowLeft, Check, Copy, LayoutDashboard, Download } from "lucide-react";
7
- const AdminContext = createContext(void 0);
5
+ import { ArrowLeft, Check, Copy, Download, LayoutDashboard, LogOut } from "lucide-react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/AdminContext.ts
8
+ var AdminContext = createContext(void 0);
8
9
  function useAdminContext() {
9
- const ctx = useContext(AdminContext);
10
- if (!ctx) throw new Error("useAdminContext must be used within AdminApp");
11
- return ctx;
10
+ const ctx = useContext(AdminContext);
11
+ if (!ctx) throw new Error("useAdminContext must be used within AdminApp");
12
+ return ctx;
12
13
  }
14
+ //#endregion
15
+ //#region src/components/AdminTopBar.tsx
13
16
  function AdminTopBar({ title }) {
14
- const { user, logout } = useUserSession();
15
- return /* @__PURE__ */ jsxs("header", { className: "sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background px-6", children: [
16
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
17
- /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-lg bg-primary text-xs font-semibold uppercase tracking-wider text-primary-foreground", children: title.split(/\s+/).map((w) => w[0]).filter(Boolean).slice(0, 2).join("") }),
18
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-foreground", children: title })
19
- ] }),
20
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
21
- /* @__PURE__ */ jsx(ModeToggle, { label: false }),
22
- user && /* @__PURE__ */ jsxs(Fragment, { children: [
23
- /* @__PURE__ */ jsx(Avatar, { size: "sm", name: user.name, color: "bg-primary" }),
24
- /* @__PURE__ */ jsx(
25
- Button,
26
- {
27
- variant: "outline",
28
- size: "sm",
29
- onClick: () => logout(),
30
- alt: "Sign out",
31
- children: /* @__PURE__ */ jsx(LogOut, { className: "size-4" })
32
- }
33
- )
34
- ] })
35
- ] })
36
- ] });
17
+ const { user, logout } = useUserSession();
18
+ return /* @__PURE__ */ jsxs("header", {
19
+ className: "sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background px-6",
20
+ children: [/* @__PURE__ */ jsxs("div", {
21
+ className: "flex items-center gap-3",
22
+ children: [/* @__PURE__ */ jsx("div", {
23
+ className: "flex size-8 items-center justify-center rounded-lg bg-primary text-xs font-semibold uppercase tracking-wider text-primary-foreground",
24
+ children: title.split(/\s+/).map((w) => w[0]).filter(Boolean).slice(0, 2).join("")
25
+ }), /* @__PURE__ */ jsx("span", {
26
+ className: "text-sm font-semibold text-foreground",
27
+ children: title
28
+ })]
29
+ }), /* @__PURE__ */ jsxs("div", {
30
+ className: "flex items-center gap-3",
31
+ children: [/* @__PURE__ */ jsx(ModeToggle, { label: false }), user && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Avatar, {
32
+ size: "sm",
33
+ name: user.name,
34
+ color: "bg-primary"
35
+ }), /* @__PURE__ */ jsx(Button, {
36
+ variant: "outline",
37
+ size: "sm",
38
+ onClick: () => logout(),
39
+ alt: "Sign out",
40
+ children: /* @__PURE__ */ jsx(LogOut, { className: "size-4" })
41
+ })] })]
42
+ })]
43
+ });
37
44
  }
45
+ //#endregion
46
+ //#region src/types.ts
47
+ /**
48
+ * Formats a kebab/snake-case name into a title.
49
+ */
38
50
  function formatTitle(name) {
39
- return name.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
51
+ return name.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
40
52
  }
53
+ /**
54
+ * Counts items per collection by matching each item to a collection name.
55
+ * If there is only one collection, all items belong to it.
56
+ */
41
57
  function countPerCollection(items, collections, extractCollection) {
42
- const counts = /* @__PURE__ */ new Map();
43
- for (const col of collections) counts.set(col.name, 0);
44
- if (collections.length === 1) {
45
- counts.set(collections[0].name, items.length);
46
- return counts;
47
- }
48
- for (const item of items) {
49
- const colName = extractCollection(item);
50
- if (colName && counts.has(colName)) {
51
- counts.set(colName, (counts.get(colName) || 0) + 1);
52
- }
53
- }
54
- return counts;
58
+ const counts = /* @__PURE__ */ new Map();
59
+ for (const col of collections) counts.set(col.name, 0);
60
+ if (collections.length === 1) {
61
+ counts.set(collections[0].name, items.length);
62
+ return counts;
63
+ }
64
+ for (const item of items) {
65
+ const colName = extractCollection(item);
66
+ if (colName && counts.has(colName)) counts.set(colName, (counts.get(colName) || 0) + 1);
67
+ }
68
+ return counts;
55
69
  }
70
+ /**
71
+ * Builds collections and a flat resource list from the 5 endpoint responses + MCP endpoints.
72
+ */
56
73
  function buildResourceData(interactionsResp, toolsResp, skillsResp, activitiesResp, typesResp, templatesResp, mcpEndpoints) {
57
- const collections = [];
58
- const resources = [];
59
- const interCounts = countPerCollection(
60
- interactionsResp.interactions,
61
- interactionsResp.collections,
62
- (i) => i.id.split(":")[0]
63
- );
64
- for (const col of interactionsResp.collections) {
65
- collections.push({
66
- name: col.name,
67
- title: col.title || formatTitle(col.name),
68
- description: col.description || "",
69
- type: "interaction",
70
- count: interCounts.get(col.name) || 0
71
- });
72
- }
73
- for (const inter of interactionsResp.interactions) {
74
- resources.push({
75
- id: inter.id,
76
- name: inter.name,
77
- title: inter.title || formatTitle(inter.name),
78
- description: inter.description || "",
79
- type: "interaction",
80
- tags: inter.tags
81
- });
82
- }
83
- const toolCounts = countPerCollection(
84
- toolsResp.tools,
85
- toolsResp.collections,
86
- (t) => t.url?.split("/").pop()
87
- );
88
- for (const col of toolsResp.collections) {
89
- collections.push({
90
- name: col.name,
91
- title: col.title || formatTitle(col.name),
92
- description: col.description || "",
93
- type: "tool",
94
- count: toolCounts.get(col.name) || 0
95
- });
96
- }
97
- for (const tool of toolsResp.tools) {
98
- resources.push({
99
- name: tool.name,
100
- title: formatTitle(tool.name),
101
- description: tool.description || "",
102
- type: "tool",
103
- url: tool.url
104
- });
105
- }
106
- const skillCounts = countPerCollection(
107
- skillsResp.tools,
108
- skillsResp.collections,
109
- (t) => t.url?.split("/").pop()
110
- );
111
- for (const col of skillsResp.collections) {
112
- collections.push({
113
- name: col.name,
114
- title: col.title || formatTitle(col.name),
115
- description: col.description || "",
116
- type: "skill",
117
- count: skillCounts.get(col.name) || 0
118
- });
119
- }
120
- for (const skill of skillsResp.tools) {
121
- resources.push({
122
- name: skill.name,
123
- title: formatTitle(skill.name),
124
- description: skill.description || "",
125
- type: "skill",
126
- url: skill.url
127
- });
128
- }
129
- const actCounts = countPerCollection(
130
- activitiesResp.activities,
131
- activitiesResp.collections,
132
- (a) => a.collection
133
- );
134
- for (const col of activitiesResp.collections) {
135
- collections.push({
136
- name: col.name,
137
- title: col.title || formatTitle(col.name),
138
- description: col.description || "",
139
- type: "activity",
140
- count: actCounts.get(col.name) || 0
141
- });
142
- }
143
- for (const act of activitiesResp.activities) {
144
- resources.push({
145
- name: act.name,
146
- title: act.title || formatTitle(act.name),
147
- description: act.description || "",
148
- type: "activity",
149
- url: act.url
150
- });
151
- }
152
- const typeCounts = countPerCollection(
153
- typesResp.types,
154
- typesResp.collections,
155
- (t) => t.id?.split(":")[0]
156
- );
157
- for (const col of typesResp.collections) {
158
- collections.push({
159
- name: col.name,
160
- title: col.title || formatTitle(col.name),
161
- description: col.description || "",
162
- type: "type",
163
- count: typeCounts.get(col.name) || 0
164
- });
165
- }
166
- for (const t of typesResp.types) {
167
- resources.push({
168
- name: t.name,
169
- title: formatTitle(t.name),
170
- description: t.description || "",
171
- type: "type",
172
- tags: t.tags
173
- });
174
- }
175
- const tmplCounts = countPerCollection(
176
- templatesResp.templates,
177
- templatesResp.collections,
178
- (t) => {
179
- const segments = t.path?.split("/");
180
- return segments && segments.length >= 4 ? segments[3] : void 0;
181
- }
182
- );
183
- for (const col of templatesResp.collections) {
184
- collections.push({
185
- name: col.name,
186
- title: col.title || formatTitle(col.name),
187
- description: col.description || "",
188
- type: "template",
189
- count: tmplCounts.get(col.name) || 0
190
- });
191
- }
192
- for (const tmpl of templatesResp.templates) {
193
- resources.push({
194
- name: tmpl.name,
195
- title: tmpl.title || formatTitle(tmpl.name),
196
- description: tmpl.description || "",
197
- type: "template",
198
- tags: tmpl.tags,
199
- url: tmpl.path
200
- });
201
- }
202
- for (const endpoint of mcpEndpoints || []) {
203
- const name = endpoint.split("/").pop() || endpoint;
204
- resources.push({
205
- name,
206
- title: formatTitle(name),
207
- description: "",
208
- type: "mcp",
209
- url: endpoint
210
- });
211
- }
212
- return { collections, resources };
74
+ const collections = [];
75
+ const resources = [];
76
+ const interCounts = countPerCollection(interactionsResp.interactions, interactionsResp.collections, (i) => i.id.split(":")[0]);
77
+ for (const col of interactionsResp.collections) collections.push({
78
+ name: col.name,
79
+ title: col.title || formatTitle(col.name),
80
+ description: col.description || "",
81
+ type: "interaction",
82
+ count: interCounts.get(col.name) || 0
83
+ });
84
+ for (const inter of interactionsResp.interactions) resources.push({
85
+ id: inter.id,
86
+ name: inter.name,
87
+ title: inter.title || formatTitle(inter.name),
88
+ description: inter.description || "",
89
+ type: "interaction",
90
+ tags: inter.tags
91
+ });
92
+ const toolCounts = countPerCollection(toolsResp.tools, toolsResp.collections, (t) => t.url?.split("/").pop());
93
+ for (const col of toolsResp.collections) collections.push({
94
+ name: col.name,
95
+ title: col.title || formatTitle(col.name),
96
+ description: col.description || "",
97
+ type: "tool",
98
+ count: toolCounts.get(col.name) || 0
99
+ });
100
+ for (const tool of toolsResp.tools) resources.push({
101
+ name: tool.name,
102
+ title: formatTitle(tool.name),
103
+ description: tool.description || "",
104
+ type: "tool",
105
+ url: tool.url
106
+ });
107
+ const skillCounts = countPerCollection(skillsResp.tools, skillsResp.collections, (t) => t.url?.split("/").pop());
108
+ for (const col of skillsResp.collections) collections.push({
109
+ name: col.name,
110
+ title: col.title || formatTitle(col.name),
111
+ description: col.description || "",
112
+ type: "skill",
113
+ count: skillCounts.get(col.name) || 0
114
+ });
115
+ for (const skill of skillsResp.tools) resources.push({
116
+ name: skill.name,
117
+ title: formatTitle(skill.name),
118
+ description: skill.description || "",
119
+ type: "skill",
120
+ url: skill.url
121
+ });
122
+ const actCounts = countPerCollection(activitiesResp.activities, activitiesResp.collections, (a) => a.collection);
123
+ for (const col of activitiesResp.collections) collections.push({
124
+ name: col.name,
125
+ title: col.title || formatTitle(col.name),
126
+ description: col.description || "",
127
+ type: "activity",
128
+ count: actCounts.get(col.name) || 0
129
+ });
130
+ for (const act of activitiesResp.activities) resources.push({
131
+ name: act.name,
132
+ title: act.title || formatTitle(act.name),
133
+ description: act.description || "",
134
+ type: "activity",
135
+ url: act.url
136
+ });
137
+ const typeCounts = countPerCollection(typesResp.types, typesResp.collections, (t) => t.id?.split(":")[0]);
138
+ for (const col of typesResp.collections) collections.push({
139
+ name: col.name,
140
+ title: col.title || formatTitle(col.name),
141
+ description: col.description || "",
142
+ type: "type",
143
+ count: typeCounts.get(col.name) || 0
144
+ });
145
+ for (const t of typesResp.types) resources.push({
146
+ name: t.name,
147
+ title: formatTitle(t.name),
148
+ description: t.description || "",
149
+ type: "type",
150
+ tags: t.tags
151
+ });
152
+ const tmplCounts = countPerCollection(templatesResp.templates, templatesResp.collections, (t) => {
153
+ const segments = t.path?.split("/");
154
+ return segments && segments.length >= 4 ? segments[3] : void 0;
155
+ });
156
+ for (const col of templatesResp.collections) collections.push({
157
+ name: col.name,
158
+ title: col.title || formatTitle(col.name),
159
+ description: col.description || "",
160
+ type: "template",
161
+ count: tmplCounts.get(col.name) || 0
162
+ });
163
+ for (const tmpl of templatesResp.templates) resources.push({
164
+ name: tmpl.name,
165
+ title: tmpl.title || formatTitle(tmpl.name),
166
+ description: tmpl.description || "",
167
+ type: "template",
168
+ tags: tmpl.tags,
169
+ url: tmpl.path
170
+ });
171
+ for (const endpoint of mcpEndpoints || []) {
172
+ const name = endpoint.split("/").pop() || endpoint;
173
+ resources.push({
174
+ name,
175
+ title: formatTitle(name),
176
+ description: "",
177
+ type: "mcp",
178
+ url: endpoint
179
+ });
180
+ }
181
+ return {
182
+ collections,
183
+ resources
184
+ };
213
185
  }
186
+ /**
187
+ * Filters resources by a search query, matching against name, title, description, type, and tags.
188
+ */
214
189
  function filterResources(items, query) {
215
- const q = query.toLowerCase().trim();
216
- if (!q) return items;
217
- return items.filter(
218
- (item) => item.name.toLowerCase().includes(q) || item.title.toLowerCase().includes(q) || item.description.toLowerCase().includes(q) || item.type.includes(q) || item.tags?.some((t) => t.toLowerCase().includes(q))
219
- );
190
+ const q = query.toLowerCase().trim();
191
+ if (!q) return items;
192
+ return items.filter((item) => item.name.toLowerCase().includes(q) || item.title.toLowerCase().includes(q) || item.description.toLowerCase().includes(q) || item.type.includes(q) || item.tags?.some((t) => t.toLowerCase().includes(q)));
220
193
  }
194
+ //#endregion
195
+ //#region src/hooks.ts
196
+ /**
197
+ * Data fetching hooks for the admin panel.
198
+ */
199
+ async function fetchJson(url) {
200
+ const response = await fetch(url);
201
+ if (!response.ok) throw new Error(`Request failed: ${response.status} ${response.statusText}`);
202
+ return response.json();
203
+ }
204
+ /**
205
+ * Fetches the tool server info (message, version, endpoints).
206
+ */
221
207
  function useServerInfo(baseUrl) {
222
- return useFetch(
223
- () => fetch(baseUrl).then((r) => r.json()),
224
- [baseUrl]
225
- );
208
+ return useFetch(() => fetchJson(baseUrl), [baseUrl]);
226
209
  }
210
+ /**
211
+ * Fetches all 5 resource endpoints in parallel and builds collections + flat resource list.
212
+ * MCP endpoints are passed separately since they come from serverInfo.
213
+ */
227
214
  function useResourceData(baseUrl, mcpEndpoints) {
228
- return useFetch(() => {
229
- const fetchJson = (path) => fetch(`${baseUrl}/${path}`).then((r) => r.json());
230
- return Promise.all([
231
- fetchJson("interactions"),
232
- fetchJson("tools"),
233
- fetchJson("skills"),
234
- fetchJson("activities"),
235
- fetchJson("types"),
236
- fetchJson("templates")
237
- ]).then(
238
- ([interactions, tools, skills, activities, types, templates]) => buildResourceData(interactions, tools, skills, activities, types, templates, mcpEndpoints)
239
- );
240
- }, [baseUrl, mcpEndpoints]);
215
+ return useFetch(() => {
216
+ const fetchResource = (path) => fetchJson(`${baseUrl}/${path}`);
217
+ return Promise.all([
218
+ fetchResource("interactions"),
219
+ fetchResource("tools"),
220
+ fetchResource("skills"),
221
+ fetchResource("activities"),
222
+ fetchResource("types"),
223
+ fetchResource("templates")
224
+ ]).then(([interactions, tools, skills, activities, types, templates]) => buildResourceData(interactions, tools, skills, activities, types, templates, mcpEndpoints));
225
+ }, [baseUrl, mcpEndpoints]);
241
226
  }
242
- const TYPE_VARIANTS = {
243
- tool: "bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300",
244
- skill: "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300",
245
- interaction: "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300",
246
- type: "bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-300",
247
- template: "bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300",
248
- activity: "bg-rose-100 text-rose-800 dark:bg-rose-500/15 dark:text-rose-300",
249
- mcp: "bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300"
227
+ //#endregion
228
+ //#region src/components/typeVariants.ts
229
+ /** Tailwind class mappings for resource type badges. */
230
+ var TYPE_VARIANTS = {
231
+ tool: "bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300",
232
+ skill: "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300",
233
+ interaction: "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300",
234
+ type: "bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-300",
235
+ template: "bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300",
236
+ activity: "bg-rose-100 text-rose-800 dark:bg-rose-500/15 dark:text-rose-300",
237
+ mcp: "bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300"
250
238
  };
251
- const ROLE_VARIANTS = {
252
- system: "bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300",
253
- user: "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300",
254
- assistant: "bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300",
255
- safety: "bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300",
256
- tool: "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300"
239
+ /** Tailwind class mappings for prompt role badges. */
240
+ var ROLE_VARIANTS = {
241
+ system: "bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300",
242
+ user: "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300",
243
+ assistant: "bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300",
244
+ safety: "bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300",
245
+ tool: "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300"
257
246
  };
247
+ //#endregion
248
+ //#region src/components/DetailPage.tsx
258
249
  function DetailPage({ type, title, description, tags, backHref = "/", children }) {
259
- return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl px-7 py-10", children: [
260
- /* @__PURE__ */ jsxs("nav", { className: "mb-5 flex items-center gap-4", children: [
261
- backHref !== "/" && /* @__PURE__ */ jsx(NavLink, { href: "/", className: "text-sm text-primary hover:opacity-75", children: "Home" }),
262
- /* @__PURE__ */ jsxs(NavLink, { href: backHref, className: "flex items-center gap-1 text-sm text-primary hover:opacity-75", children: [
263
- /* @__PURE__ */ jsx(ArrowLeft, { className: "size-3.5" }),
264
- "Back"
265
- ] })
266
- ] }),
267
- /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
268
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[type] ?? ""}`, children: type }),
269
- /* @__PURE__ */ jsx("h1", { className: "-tracking-wide text-3xl font-bold text-foreground", children: title }),
270
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm leading-relaxed text-muted-foreground", children: description }),
271
- tags && tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-1.5", children: tags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: tag }, tag)) })
272
- ] }),
273
- children
274
- ] });
250
+ return /* @__PURE__ */ jsxs("div", {
251
+ className: "mx-auto max-w-5xl px-7 py-10",
252
+ children: [
253
+ /* @__PURE__ */ jsxs("nav", {
254
+ className: "mb-5 flex items-center gap-4",
255
+ children: [backHref !== "/" && /* @__PURE__ */ jsx(NavLink, {
256
+ href: "/",
257
+ className: "text-sm text-primary hover:opacity-75",
258
+ children: "Home"
259
+ }), /* @__PURE__ */ jsxs(NavLink, {
260
+ href: backHref,
261
+ className: "flex items-center gap-1 text-sm text-primary hover:opacity-75",
262
+ children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "size-3.5" }), "Back"]
263
+ })]
264
+ }),
265
+ /* @__PURE__ */ jsxs("div", {
266
+ className: "mb-8",
267
+ children: [
268
+ /* @__PURE__ */ jsx("span", {
269
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[type] ?? ""}`,
270
+ children: type
271
+ }),
272
+ /* @__PURE__ */ jsx("h1", {
273
+ className: "-tracking-wide text-3xl font-bold text-foreground",
274
+ children: title
275
+ }),
276
+ description && /* @__PURE__ */ jsx("p", {
277
+ className: "mt-1 text-sm leading-relaxed text-muted-foreground",
278
+ children: description
279
+ }),
280
+ tags && tags.length > 0 && /* @__PURE__ */ jsx("div", {
281
+ className: "mt-3 flex flex-wrap gap-1.5",
282
+ children: tags.map((tag) => /* @__PURE__ */ jsx(Badge, {
283
+ variant: "default",
284
+ children: tag
285
+ }, tag))
286
+ })
287
+ ]
288
+ }),
289
+ children
290
+ ]
291
+ });
275
292
  }
293
+ //#endregion
294
+ //#region src/pages/ActivityCollection.tsx
276
295
  function ActivityCollection() {
277
- const collection = useParams("collection");
278
- const { baseUrl } = useAdminContext();
279
- const { data, error } = useFetch(
280
- () => fetch(`${baseUrl}/activities/${collection}`).then((r) => {
281
- if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
282
- return r.json();
283
- }),
284
- [baseUrl, collection]
285
- );
286
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
287
- "Failed to load activity collection “",
288
- collection,
289
- "”."
290
- ] });
291
- if (!data) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
292
- return /* @__PURE__ */ jsx(
293
- DetailPage,
294
- {
295
- type: "activity",
296
- title: data.title || collection,
297
- description: data.description || `${data.activities.length} activit${data.activities.length !== 1 ? "ies" : "y"} in this collection.`,
298
- children: data.activities.map((activity) => /* @__PURE__ */ jsx(Card, { className: "mb-4", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
299
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
300
- /* @__PURE__ */ jsx("span", { className: `inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.activity}`, children: "activity" }),
301
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-card-foreground", children: activity.name })
302
- ] }),
303
- /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: activity.description || "No description" }),
304
- activity.input_schema && /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
305
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Input Schema" }),
306
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(activity.input_schema, null, 2) })
307
- ] }),
308
- activity.output_schema && /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
309
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Output Schema" }),
310
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(activity.output_schema, null, 2) })
311
- ] })
312
- ] }) }, activity.name))
313
- }
314
- );
296
+ const collection = useParams("collection");
297
+ const { baseUrl } = useAdminContext();
298
+ const { data, error } = useFetch(() => fetch(`${baseUrl}/activities/${collection}`).then((r) => {
299
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
300
+ return r.json();
301
+ }), [baseUrl, collection]);
302
+ if (error) return /* @__PURE__ */ jsxs("div", {
303
+ className: "p-6 text-destructive",
304
+ children: [
305
+ "Failed to load activity collection ",
306
+ collection,
307
+ "”."
308
+ ]
309
+ });
310
+ if (!data) return /* @__PURE__ */ jsx("div", {
311
+ className: "flex h-64 items-center justify-center text-muted-foreground",
312
+ children: /* @__PURE__ */ jsx(Spinner, {})
313
+ });
314
+ return /* @__PURE__ */ jsx(DetailPage, {
315
+ type: "activity",
316
+ title: data.title || collection,
317
+ description: data.description || `${data.activities.length} activit${data.activities.length !== 1 ? "ies" : "y"} in this collection.`,
318
+ children: data.activities.map((activity) => /* @__PURE__ */ jsx(Card, {
319
+ className: "mb-4",
320
+ children: /* @__PURE__ */ jsxs(CardContent, {
321
+ className: "p-5",
322
+ children: [
323
+ /* @__PURE__ */ jsxs("div", {
324
+ className: "mb-2 flex items-center gap-2",
325
+ children: [/* @__PURE__ */ jsx("span", {
326
+ className: `inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.activity}`,
327
+ children: "activity"
328
+ }), /* @__PURE__ */ jsx("span", {
329
+ className: "font-semibold text-card-foreground",
330
+ children: activity.name
331
+ })]
332
+ }),
333
+ /* @__PURE__ */ jsx("div", {
334
+ className: "text-sm text-muted-foreground",
335
+ children: activity.description || "No description"
336
+ }),
337
+ activity.input_schema && /* @__PURE__ */ jsxs("div", {
338
+ className: "mt-3",
339
+ children: [/* @__PURE__ */ jsx("p", {
340
+ className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
341
+ children: "Input Schema"
342
+ }), /* @__PURE__ */ jsx("pre", {
343
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
344
+ children: JSON.stringify(activity.input_schema, null, 2)
345
+ })]
346
+ }),
347
+ activity.output_schema && /* @__PURE__ */ jsxs("div", {
348
+ className: "mt-3",
349
+ children: [/* @__PURE__ */ jsx("p", {
350
+ className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground",
351
+ children: "Output Schema"
352
+ }), /* @__PURE__ */ jsx("pre", {
353
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
354
+ children: JSON.stringify(activity.output_schema, null, 2)
355
+ })]
356
+ })
357
+ ]
358
+ })
359
+ }, activity.name))
360
+ });
315
361
  }
362
+ //#endregion
363
+ //#region src/components/CollectionCard.tsx
316
364
  function CollectionCard({ collection }) {
317
- const plural = collection.type === "activity" ? "activities" : `${collection.type}s`;
318
- const href = `/${plural}/${collection.name}`;
319
- return /* @__PURE__ */ jsx(NavLink, { href, className: "block no-underline", children: /* @__PURE__ */ jsx(Card, { className: "cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
320
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[collection.type] ?? ""}`, children: collection.type }),
321
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: collection.title }),
322
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: collection.description || "No description" }),
323
- /* @__PURE__ */ jsxs("div", { className: "mt-2 font-mono text-xs text-muted-foreground", children: [
324
- collection.count,
325
- " ",
326
- collection.count === 1 ? "item" : "items"
327
- ] })
328
- ] }) }) });
365
+ return /* @__PURE__ */ jsx(NavLink, {
366
+ href: `/${collection.type === "activity" ? "activities" : `${collection.type}s`}/${collection.name}`,
367
+ className: "block no-underline",
368
+ children: /* @__PURE__ */ jsx(Card, {
369
+ className: "cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md",
370
+ children: /* @__PURE__ */ jsxs(CardContent, {
371
+ className: "p-5",
372
+ children: [
373
+ /* @__PURE__ */ jsx("span", {
374
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[collection.type] ?? ""}`,
375
+ children: collection.type
376
+ }),
377
+ /* @__PURE__ */ jsx("div", {
378
+ className: "font-semibold text-card-foreground",
379
+ children: collection.title
380
+ }),
381
+ /* @__PURE__ */ jsx("div", {
382
+ className: "mt-1 text-sm text-muted-foreground",
383
+ children: collection.description || "No description"
384
+ }),
385
+ /* @__PURE__ */ jsxs("div", {
386
+ className: "mt-2 font-mono text-xs text-muted-foreground",
387
+ children: [
388
+ collection.count,
389
+ " ",
390
+ collection.count === 1 ? "item" : "items"
391
+ ]
392
+ })
393
+ ]
394
+ })
395
+ })
396
+ });
329
397
  }
398
+ //#endregion
399
+ //#region src/components/EndpointPanel.tsx
330
400
  function EndpointPanel({ label, path }) {
331
- const [copied, setCopied] = useState(false);
332
- function handleCopy() {
333
- const url = window.location.origin + path;
334
- navigator.clipboard.writeText(url);
335
- setCopied(true);
336
- setTimeout(() => setCopied(false), 1500);
337
- }
338
- return /* @__PURE__ */ jsxs("div", { className: "mb-3", children: [
339
- /* @__PURE__ */ jsx("div", { className: "mb-1 text-[0.7rem] font-medium uppercase tracking-widest text-primary", children: label }),
340
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-muted-background px-3 py-2", children: [
341
- /* @__PURE__ */ jsx("code", { className: "flex-1 font-mono text-sm text-foreground", children: path }),
342
- /* @__PURE__ */ jsx(
343
- Button,
344
- {
345
- variant: "ghost",
346
- size: "xs",
347
- onClick: handleCopy,
348
- "aria-label": "Copy full URL",
349
- children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5" }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5" })
350
- }
351
- )
352
- ] })
353
- ] });
401
+ const [copied, setCopied] = useState(false);
402
+ function handleCopy() {
403
+ const url = window.location.origin + path;
404
+ navigator.clipboard.writeText(url);
405
+ setCopied(true);
406
+ setTimeout(() => setCopied(false), 1500);
407
+ }
408
+ return /* @__PURE__ */ jsxs("div", {
409
+ className: "mb-3",
410
+ children: [/* @__PURE__ */ jsx("div", {
411
+ className: "mb-1 text-[0.7rem] font-medium uppercase tracking-widest text-primary",
412
+ children: label
413
+ }), /* @__PURE__ */ jsxs("div", {
414
+ className: "flex items-center gap-2 rounded-lg border border-border bg-muted-background px-3 py-2",
415
+ children: [/* @__PURE__ */ jsx("code", {
416
+ className: "flex-1 font-mono text-sm text-foreground",
417
+ children: path
418
+ }), /* @__PURE__ */ jsx(Button, {
419
+ variant: "ghost",
420
+ size: "xs",
421
+ onClick: handleCopy,
422
+ "aria-label": "Copy full URL",
423
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-3.5" }) : /* @__PURE__ */ jsx(Copy, { className: "size-3.5" })
424
+ })]
425
+ })]
426
+ });
354
427
  }
428
+ //#endregion
429
+ //#region src/components/SummaryBadge.tsx
355
430
  function SummaryBadge({ count, label }) {
356
- if (count === 0) return null;
357
- return /* @__PURE__ */ jsxs(DotBadge, { variant: "success", children: [
358
- count,
359
- " ",
360
- label,
361
- count !== 1 ? "s" : ""
362
- ] });
431
+ if (count === 0) return null;
432
+ return /* @__PURE__ */ jsxs(DotBadge, {
433
+ variant: "success",
434
+ children: [
435
+ count,
436
+ " ",
437
+ label,
438
+ count !== 1 ? "s" : ""
439
+ ]
440
+ });
363
441
  }
442
+ //#endregion
443
+ //#region src/components/HeroSection.tsx
364
444
  function getInitials(title) {
365
- return title.split(/\s+/).map((w) => w[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
445
+ return title.split(/\s+/).map((w) => w[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
366
446
  }
367
447
  function countByType(resources) {
368
- const counts = {};
369
- for (const r of resources) {
370
- counts[r.type] = (counts[r.type] || 0) + 1;
371
- }
372
- return counts;
448
+ const counts = {};
449
+ for (const r of resources) counts[r.type] = (counts[r.type] || 0) + 1;
450
+ return counts;
373
451
  }
374
- const badgeLabels = [
375
- { type: "tool", label: "tool" },
376
- { type: "activity", label: "activity" },
377
- { type: "skill", label: "skill" },
378
- { type: "interaction", label: "interaction" },
379
- { type: "type", label: "content type" },
380
- { type: "template", label: "template" },
381
- { type: "mcp", label: "MCP provider" }
452
+ var badgeLabels = [
453
+ {
454
+ type: "tool",
455
+ label: "tool"
456
+ },
457
+ {
458
+ type: "activity",
459
+ label: "activity"
460
+ },
461
+ {
462
+ type: "skill",
463
+ label: "skill"
464
+ },
465
+ {
466
+ type: "interaction",
467
+ label: "interaction"
468
+ },
469
+ {
470
+ type: "type",
471
+ label: "content type"
472
+ },
473
+ {
474
+ type: "template",
475
+ label: "template"
476
+ },
477
+ {
478
+ type: "mcp",
479
+ label: "MCP provider"
480
+ }
382
481
  ];
383
482
  function HeroSection({ title, version, resources }) {
384
- const counts = countByType(resources);
385
- return /* @__PURE__ */ jsx(Card, { className: "mb-10 overflow-hidden border bg-linear-to-br from-card to-muted-background", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6 p-6 md:flex-row md:items-start md:justify-between", children: [
386
- /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-3", children: [
387
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
388
- /* @__PURE__ */ jsx("div", { className: "flex size-14 items-center justify-center rounded-xl bg-linear-to-br from-sky-400 to-indigo-500 text-sm font-semibold uppercase tracking-wider text-white shadow-lg", children: getInitials(title) }),
389
- /* @__PURE__ */ jsxs("div", { children: [
390
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-widest text-muted-foreground", children: "Tools Server" }),
391
- /* @__PURE__ */ jsx("h1", { className: "-tracking-wide text-2xl font-bold text-foreground", children: title })
392
- ] })
393
- ] }),
394
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Discover the tools, skills, interactions, and content types exposed by this server." }),
395
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: badgeLabels.map(({ type, label }) => /* @__PURE__ */ jsx(SummaryBadge, { count: counts[type] || 0, label }, type)) }),
396
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-3 pt-1", children: [
397
- /* @__PURE__ */ jsxs(
398
- "a",
399
- {
400
- href: "/app/",
401
- target: "_blank",
402
- rel: "noopener noreferrer",
403
- className: "inline-flex h-8 items-center gap-2 rounded bg-primary px-3 text-xs font-medium text-white shadow-xs hover:bg-primary/90",
404
- children: [
405
- /* @__PURE__ */ jsx(LayoutDashboard, { className: "size-4" }),
406
- "UI Plugin Dev"
407
- ]
408
- }
409
- ),
410
- /* @__PURE__ */ jsxs(
411
- "a",
412
- {
413
- href: "/lib/plugin.js",
414
- className: "inline-flex h-8 items-center gap-2 rounded bg-primary/5 px-3 text-xs font-medium text-primary shadow-xs hover:bg-primary/10 dark:bg-primary/10 dark:hover:bg-primary/20",
415
- children: [
416
- /* @__PURE__ */ jsx(Download, { className: "size-4" }),
417
- "Plugin Bundle"
418
- ]
419
- }
420
- )
421
- ] })
422
- ] }),
423
- /* @__PURE__ */ jsxs("aside", { className: "min-w-55 max-w-65 shrink-0", children: [
424
- /* @__PURE__ */ jsx(EndpointPanel, { label: "Base endpoint", path: "/api" }),
425
- /* @__PURE__ */ jsx(EndpointPanel, { label: "Package endpoint", path: "/api/package" }),
426
- /* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: [
427
- "Use ",
428
- /* @__PURE__ */ jsx("strong", { className: "text-foreground", children: "POST /api/tools/<collection>" }),
429
- " or",
430
- " ",
431
- /* @__PURE__ */ jsx("strong", { className: "text-foreground", children: "POST /api/skills/<collection>" }),
432
- " to call these from your apps or agents."
433
- ] }),
434
- /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
435
- "v",
436
- version
437
- ] })
438
- ] })
439
- ] }) });
483
+ const counts = countByType(resources);
484
+ return /* @__PURE__ */ jsx(Card, {
485
+ className: "mb-10 overflow-hidden border bg-linear-to-br from-card to-muted-background",
486
+ children: /* @__PURE__ */ jsxs("div", {
487
+ className: "flex flex-col gap-6 p-6 md:flex-row md:items-start md:justify-between",
488
+ children: [/* @__PURE__ */ jsxs("div", {
489
+ className: "flex flex-1 flex-col gap-3",
490
+ children: [
491
+ /* @__PURE__ */ jsxs("div", {
492
+ className: "flex items-center gap-4",
493
+ children: [/* @__PURE__ */ jsx("div", {
494
+ className: "flex size-14 items-center justify-center rounded-xl bg-linear-to-br from-sky-400 to-indigo-500 text-sm font-semibold uppercase tracking-wider text-white shadow-lg",
495
+ children: getInitials(title)
496
+ }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
497
+ className: "text-xs font-medium uppercase tracking-widest text-muted-foreground",
498
+ children: "Tools Server"
499
+ }), /* @__PURE__ */ jsx("h1", {
500
+ className: "-tracking-wide text-2xl font-bold text-foreground",
501
+ children: title
502
+ })] })]
503
+ }),
504
+ /* @__PURE__ */ jsx("p", {
505
+ className: "text-sm text-muted-foreground",
506
+ children: "Discover the tools, skills, interactions, and content types exposed by this server."
507
+ }),
508
+ /* @__PURE__ */ jsx("div", {
509
+ className: "flex flex-wrap gap-2",
510
+ children: badgeLabels.map(({ type, label }) => /* @__PURE__ */ jsx(SummaryBadge, {
511
+ count: counts[type] || 0,
512
+ label
513
+ }, type))
514
+ }),
515
+ /* @__PURE__ */ jsxs("div", {
516
+ className: "flex flex-wrap gap-3 pt-1",
517
+ children: [/* @__PURE__ */ jsxs("a", {
518
+ href: "/app/",
519
+ target: "_blank",
520
+ rel: "noopener noreferrer",
521
+ className: "inline-flex h-8 items-center gap-2 rounded bg-primary px-3 text-xs font-medium text-white shadow-xs hover:bg-primary/90",
522
+ children: [/* @__PURE__ */ jsx(LayoutDashboard, { className: "size-4" }), "UI Plugin Dev"]
523
+ }), /* @__PURE__ */ jsxs("a", {
524
+ href: "/lib/plugin.js",
525
+ className: "inline-flex h-8 items-center gap-2 rounded bg-primary/5 px-3 text-xs font-medium text-primary shadow-xs hover:bg-primary/10 dark:bg-primary/10 dark:hover:bg-primary/20",
526
+ children: [/* @__PURE__ */ jsx(Download, { className: "size-4" }), "Plugin Bundle"]
527
+ })]
528
+ })
529
+ ]
530
+ }), /* @__PURE__ */ jsxs("aside", {
531
+ className: "min-w-55 max-w-65 shrink-0",
532
+ children: [
533
+ /* @__PURE__ */ jsx(EndpointPanel, {
534
+ label: "Base endpoint",
535
+ path: "/api"
536
+ }),
537
+ /* @__PURE__ */ jsx(EndpointPanel, {
538
+ label: "Package endpoint",
539
+ path: "/api/package"
540
+ }),
541
+ /* @__PURE__ */ jsxs("p", {
542
+ className: "mt-2 text-xs leading-relaxed text-muted-foreground",
543
+ children: [
544
+ "Use ",
545
+ /* @__PURE__ */ jsx("strong", {
546
+ className: "text-foreground",
547
+ children: "POST /api/tools/<collection>"
548
+ }),
549
+ " or",
550
+ " ",
551
+ /* @__PURE__ */ jsx("strong", {
552
+ className: "text-foreground",
553
+ children: "POST /api/skills/<collection>"
554
+ }),
555
+ " to call these from your apps or agents."
556
+ ]
557
+ }),
558
+ /* @__PURE__ */ jsxs("p", {
559
+ className: "mt-1 text-xs text-muted-foreground",
560
+ children: ["v", version]
561
+ })
562
+ ]
563
+ })]
564
+ })
565
+ });
440
566
  }
567
+ //#endregion
568
+ //#region src/components/ResourceCard.tsx
441
569
  function ResourceCard({ resource }) {
442
- return /* @__PURE__ */ jsx(Card, { className: "transition-all hover:-translate-y-0.5 hover:shadow-md", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
443
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[resource.type] ?? ""}`, children: resource.type }),
444
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: resource.title }),
445
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: resource.description || "No description" }),
446
- resource.tags && resource.tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-1", children: resource.tags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: tag }, tag)) }),
447
- resource.url && /* @__PURE__ */ jsx("div", { className: "mt-2 truncate font-mono text-xs text-muted-foreground", children: resource.url })
448
- ] }) });
570
+ return /* @__PURE__ */ jsx(Card, {
571
+ className: "transition-all hover:-translate-y-0.5 hover:shadow-md",
572
+ children: /* @__PURE__ */ jsxs(CardContent, {
573
+ className: "p-5",
574
+ children: [
575
+ /* @__PURE__ */ jsx("span", {
576
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[resource.type] ?? ""}`,
577
+ children: resource.type
578
+ }),
579
+ /* @__PURE__ */ jsx("div", {
580
+ className: "font-semibold text-card-foreground",
581
+ children: resource.title
582
+ }),
583
+ /* @__PURE__ */ jsx("div", {
584
+ className: "mt-1 text-sm text-muted-foreground",
585
+ children: resource.description || "No description"
586
+ }),
587
+ resource.tags && resource.tags.length > 0 && /* @__PURE__ */ jsx("div", {
588
+ className: "mt-2 flex flex-wrap gap-1",
589
+ children: resource.tags.map((tag) => /* @__PURE__ */ jsx(Badge, {
590
+ variant: "default",
591
+ children: tag
592
+ }, tag))
593
+ }),
594
+ resource.url && /* @__PURE__ */ jsx("div", {
595
+ className: "mt-2 truncate font-mono text-xs text-muted-foreground",
596
+ children: resource.url
597
+ })
598
+ ]
599
+ })
600
+ });
449
601
  }
602
+ //#endregion
603
+ //#region src/components/ResourceSection.tsx
450
604
  function ResourceSection({ title, subtitle, resources, showDivider }) {
451
- if (resources.length === 0) return null;
452
- return /* @__PURE__ */ jsxs("section", { children: [
453
- showDivider && /* @__PURE__ */ jsx(Separator, { className: "my-8" }),
454
- /* @__PURE__ */ jsxs("div", { children: [
455
- /* @__PURE__ */ jsxs("h2", { className: "text-xl font-semibold text-foreground", children: [
456
- title,
457
- /* @__PURE__ */ jsxs("span", { className: "ml-2 text-sm font-normal text-muted-foreground", children: [
458
- "(",
459
- resources.length,
460
- ")"
461
- ] })
462
- ] }),
463
- /* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: subtitle })
464
- ] }),
465
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: resources.map((r) => /* @__PURE__ */ jsx(ResourceCard, { resource: r }, `${r.type}:${r.name}`)) })
466
- ] });
605
+ if (resources.length === 0) return null;
606
+ return /* @__PURE__ */ jsxs("section", { children: [
607
+ showDivider && /* @__PURE__ */ jsx(Separator, { className: "my-8" }),
608
+ /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("h2", {
609
+ className: "text-xl font-semibold text-foreground",
610
+ children: [title, /* @__PURE__ */ jsxs("span", {
611
+ className: "ml-2 text-sm font-normal text-muted-foreground",
612
+ children: [
613
+ "(",
614
+ resources.length,
615
+ ")"
616
+ ]
617
+ })]
618
+ }), /* @__PURE__ */ jsx("p", {
619
+ className: "mb-4 text-sm text-muted-foreground",
620
+ children: subtitle
621
+ })] }),
622
+ /* @__PURE__ */ jsx("div", {
623
+ className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3",
624
+ children: resources.map((r) => /* @__PURE__ */ jsx(ResourceCard, { resource: r }, `${r.type}:${r.name}`))
625
+ })
626
+ ] });
467
627
  }
628
+ //#endregion
629
+ //#region src/components/SearchBar.tsx
468
630
  function SearchBar({ value, onChange, placeholder, resultCount, totalCount }) {
469
- const hasQuery = value.trim().length > 0;
470
- const noResults = hasQuery && resultCount === 0;
471
- return /* @__PURE__ */ jsxs("div", { className: "mb-7", children: [
472
- /* @__PURE__ */ jsx(
473
- Input,
474
- {
475
- type: "search",
476
- value,
477
- onChange,
478
- placeholder: placeholder || "Search collections...",
479
- className: "max-w-sm rounded-full",
480
- autoComplete: "off"
481
- }
482
- ),
483
- hasQuery && !noResults && /* @__PURE__ */ jsxs("p", { className: "mt-1.5 text-xs text-muted-foreground", children: [
484
- "Showing ",
485
- resultCount,
486
- " of ",
487
- totalCount,
488
- " resources"
489
- ] }),
490
- noResults && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-destructive", children: "No resources match this search." })
491
- ] });
631
+ const hasQuery = value.trim().length > 0;
632
+ const noResults = hasQuery && resultCount === 0;
633
+ return /* @__PURE__ */ jsxs("div", {
634
+ className: "mb-7",
635
+ children: [
636
+ /* @__PURE__ */ jsx(Input, {
637
+ type: "search",
638
+ value,
639
+ onChange,
640
+ placeholder: placeholder || "Search collections...",
641
+ className: "max-w-sm rounded-full",
642
+ autoComplete: "off"
643
+ }),
644
+ hasQuery && !noResults && /* @__PURE__ */ jsxs("p", {
645
+ className: "mt-1.5 text-xs text-muted-foreground",
646
+ children: [
647
+ "Showing ",
648
+ resultCount,
649
+ " of ",
650
+ totalCount,
651
+ " resources"
652
+ ]
653
+ }),
654
+ noResults && /* @__PURE__ */ jsx("p", {
655
+ className: "mt-2 text-sm text-destructive",
656
+ children: "No resources match this search."
657
+ })
658
+ ]
659
+ });
492
660
  }
493
- const sections = [
494
- { type: "tool", title: "Tools", subtitle: "Remote tools available to agents via Vertesia." },
495
- { type: "activity", title: "Activities", subtitle: "Remote activities for DSL workflows, invoked via HTTP." },
496
- { type: "skill", title: "Skills", subtitle: "Reusable instructions and scripts packaged as tools." },
497
- { type: "interaction", title: "Interactions", subtitle: "Conversation blueprints surfaced in the Vertesia UI." },
498
- { type: "type", title: "Content Types", subtitle: "Schema definitions for structured content in the data store." },
499
- { type: "template", title: "Rendering Templates", subtitle: "Document and presentation templates for content generation." },
500
- { type: "mcp", title: "MCP Providers", subtitle: "Remote MCP servers available through this tools server." }
661
+ //#endregion
662
+ //#region src/pages/HomePage.tsx
663
+ var sections = [
664
+ {
665
+ type: "tool",
666
+ title: "Tools",
667
+ subtitle: "Remote tools available to agents via Vertesia."
668
+ },
669
+ {
670
+ type: "activity",
671
+ title: "Activities",
672
+ subtitle: "Remote activities for DSL workflows, invoked via HTTP."
673
+ },
674
+ {
675
+ type: "skill",
676
+ title: "Skills",
677
+ subtitle: "Reusable instructions and scripts packaged as tools."
678
+ },
679
+ {
680
+ type: "interaction",
681
+ title: "Interactions",
682
+ subtitle: "Conversation blueprints surfaced in the Vertesia UI."
683
+ },
684
+ {
685
+ type: "type",
686
+ title: "Content Types",
687
+ subtitle: "Schema definitions for structured content in the data store."
688
+ },
689
+ {
690
+ type: "template",
691
+ title: "Rendering Templates",
692
+ subtitle: "Document and presentation templates for content generation."
693
+ },
694
+ {
695
+ type: "mcp",
696
+ title: "MCP Providers",
697
+ subtitle: "Remote MCP servers available through this tools server."
698
+ }
501
699
  ];
502
700
  function HomePage() {
503
- const { serverInfo, collections, resources } = useAdminContext();
504
- const [search, setSearch] = useState("");
505
- const filtered = useMemo(
506
- () => filterResources(resources, search),
507
- [resources, search]
508
- );
509
- const isSearching = search.trim().length > 0;
510
- return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl px-7 py-10", children: [
511
- /* @__PURE__ */ jsx(
512
- HeroSection,
513
- {
514
- title: serverInfo.message.replace("Vertesia Tools API", "Tools Server"),
515
- version: serverInfo.version,
516
- resources
517
- }
518
- ),
519
- /* @__PURE__ */ jsx(
520
- SearchBar,
521
- {
522
- value: search,
523
- onChange: setSearch,
524
- placeholder: "Search tools, skills, interactions, types, templates...",
525
- resultCount: filtered.length,
526
- totalCount: resources.length
527
- }
528
- ),
529
- isSearching ? sections.map((section, i) => {
530
- const sectionItems = filtered.filter((r) => r.type === section.type);
531
- return /* @__PURE__ */ jsx(
532
- ResourceSection,
533
- {
534
- title: section.title,
535
- subtitle: section.subtitle,
536
- resources: sectionItems,
537
- showDivider: i > 0
538
- },
539
- section.type
540
- );
541
- }) : sections.map((section, i) => {
542
- const sectionCollections = collections.filter((c) => c.type === section.type);
543
- const mcpResources = section.type === "mcp" ? resources.filter((r) => r.type === "mcp") : [];
544
- if (sectionCollections.length === 0 && mcpResources.length === 0) return null;
545
- return /* @__PURE__ */ jsxs("section", { children: [
546
- i > 0 && /* @__PURE__ */ jsx(Separator, { className: "my-8" }),
547
- /* @__PURE__ */ jsxs("div", { children: [
548
- /* @__PURE__ */ jsxs("h2", { className: "text-xl font-semibold text-foreground", children: [
549
- section.title,
550
- /* @__PURE__ */ jsxs("span", { className: "ml-2 text-sm font-normal text-muted-foreground", children: [
551
- "(",
552
- sectionCollections.length,
553
- sectionCollections.length === 1 ? " collection" : " collections",
554
- ")"
555
- ] })
556
- ] }),
557
- /* @__PURE__ */ jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: section.subtitle })
558
- ] }),
559
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: [
560
- sectionCollections.map((col) => /* @__PURE__ */ jsx(CollectionCard, { collection: col }, `${col.type}:${col.name}`)),
561
- mcpResources.map((r) => /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-border bg-card p-5 shadow-sm", children: [
562
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.mcp}`, children: "mcp" }),
563
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: r.title }),
564
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: r.description || "No description" }),
565
- r.url && /* @__PURE__ */ jsx("div", { className: "mt-2 truncate font-mono text-xs text-muted-foreground", children: r.url })
566
- ] }, r.name))
567
- ] })
568
- ] }, section.type);
569
- })
570
- ] });
701
+ const { serverInfo, collections, resources } = useAdminContext();
702
+ const [search, setSearch] = useState("");
703
+ const filtered = useMemo(() => filterResources(resources, search), [resources, search]);
704
+ const isSearching = search.trim().length > 0;
705
+ return /* @__PURE__ */ jsxs("div", {
706
+ className: "mx-auto max-w-5xl px-7 py-10",
707
+ children: [
708
+ /* @__PURE__ */ jsx(HeroSection, {
709
+ title: serverInfo.message.replace("Vertesia Tools API", "Tools Server"),
710
+ version: serverInfo.version,
711
+ resources
712
+ }),
713
+ /* @__PURE__ */ jsx(SearchBar, {
714
+ value: search,
715
+ onChange: setSearch,
716
+ placeholder: "Search tools, skills, interactions, types, templates...",
717
+ resultCount: filtered.length,
718
+ totalCount: resources.length
719
+ }),
720
+ isSearching ? sections.map((section, i) => {
721
+ const sectionItems = filtered.filter((r) => r.type === section.type);
722
+ return /* @__PURE__ */ jsx(ResourceSection, {
723
+ title: section.title,
724
+ subtitle: section.subtitle,
725
+ resources: sectionItems,
726
+ showDivider: i > 0
727
+ }, section.type);
728
+ }) : sections.map((section, i) => {
729
+ const sectionCollections = collections.filter((c) => c.type === section.type);
730
+ const mcpResources = section.type === "mcp" ? resources.filter((r) => r.type === "mcp") : [];
731
+ if (sectionCollections.length === 0 && mcpResources.length === 0) return null;
732
+ return /* @__PURE__ */ jsxs("section", { children: [
733
+ i > 0 && /* @__PURE__ */ jsx(Separator, { className: "my-8" }),
734
+ /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("h2", {
735
+ className: "text-xl font-semibold text-foreground",
736
+ children: [section.title, /* @__PURE__ */ jsxs("span", {
737
+ className: "ml-2 text-sm font-normal text-muted-foreground",
738
+ children: [
739
+ "(",
740
+ sectionCollections.length,
741
+ sectionCollections.length === 1 ? " collection" : " collections",
742
+ ")"
743
+ ]
744
+ })]
745
+ }), /* @__PURE__ */ jsx("p", {
746
+ className: "mb-4 text-sm text-muted-foreground",
747
+ children: section.subtitle
748
+ })] }),
749
+ /* @__PURE__ */ jsxs("div", {
750
+ className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3",
751
+ children: [sectionCollections.map((col) => /* @__PURE__ */ jsx(CollectionCard, { collection: col }, `${col.type}:${col.name}`)), mcpResources.map((r) => /* @__PURE__ */ jsxs("div", {
752
+ className: "rounded-xl border border-border bg-card p-5 shadow-sm",
753
+ children: [
754
+ /* @__PURE__ */ jsx("span", {
755
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.mcp}`,
756
+ children: "mcp"
757
+ }),
758
+ /* @__PURE__ */ jsx("div", {
759
+ className: "font-semibold text-card-foreground",
760
+ children: r.title
761
+ }),
762
+ /* @__PURE__ */ jsx("div", {
763
+ className: "mt-1 text-sm text-muted-foreground",
764
+ children: r.description || "No description"
765
+ }),
766
+ r.url && /* @__PURE__ */ jsx("div", {
767
+ className: "mt-2 truncate font-mono text-xs text-muted-foreground",
768
+ children: r.url
769
+ })
770
+ ]
771
+ }, r.name))]
772
+ })
773
+ ] }, section.type);
774
+ })
775
+ ]
776
+ });
571
777
  }
778
+ //#endregion
779
+ //#region src/pages/InteractionCollection.tsx
572
780
  function InteractionCollection() {
573
- const collection = useParams("collection");
574
- const { baseUrl } = useAdminContext();
575
- const { data: interactions, error } = useFetch(
576
- () => fetch(`${baseUrl}/interactions/${collection}`).then((r) => {
577
- if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
578
- return r.json();
579
- }),
580
- [baseUrl, collection]
581
- );
582
- if (error) {
583
- return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
584
- "Failed to load collection “",
585
- collection,
586
- "”."
587
- ] });
588
- }
589
- if (!interactions) {
590
- return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
591
- }
592
- return /* @__PURE__ */ jsx(
593
- DetailPage,
594
- {
595
- type: "interaction",
596
- title: collection,
597
- description: `${interactions.length} interaction${interactions.length !== 1 ? "s" : ""} in this collection.`,
598
- children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: interactions.map((inter) => /* @__PURE__ */ jsx(NavLink, { href: `/interactions/${collection}/${inter.name}`, className: "block no-underline", children: /* @__PURE__ */ jsx(Card, { className: "cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
599
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.interaction}`, children: "interaction" }),
600
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: inter.title || inter.name }),
601
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: inter.description || "No description" }),
602
- inter.tags && inter.tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-1", children: inter.tags.map((tag) => /* @__PURE__ */ jsx(Badge, { children: tag }, tag)) })
603
- ] }) }) }, inter.id)) })
604
- }
605
- );
781
+ const collection = useParams("collection");
782
+ const { baseUrl } = useAdminContext();
783
+ const { data: interactions, error } = useFetch(() => fetch(`${baseUrl}/interactions/${collection}`).then((r) => {
784
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
785
+ return r.json();
786
+ }), [baseUrl, collection]);
787
+ if (error) return /* @__PURE__ */ jsxs("div", {
788
+ className: "p-6 text-destructive",
789
+ children: [
790
+ "Failed to load collection “",
791
+ collection,
792
+ "”."
793
+ ]
794
+ });
795
+ if (!interactions) return /* @__PURE__ */ jsx("div", {
796
+ className: "flex h-64 items-center justify-center text-muted-foreground",
797
+ children: /* @__PURE__ */ jsx(Spinner, {})
798
+ });
799
+ return /* @__PURE__ */ jsx(DetailPage, {
800
+ type: "interaction",
801
+ title: collection,
802
+ description: `${interactions.length} interaction${interactions.length !== 1 ? "s" : ""} in this collection.`,
803
+ children: /* @__PURE__ */ jsx("div", {
804
+ className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3",
805
+ children: interactions.map((inter) => /* @__PURE__ */ jsx(NavLink, {
806
+ href: `/interactions/${collection}/${inter.name}`,
807
+ className: "block no-underline",
808
+ children: /* @__PURE__ */ jsx(Card, {
809
+ className: "cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md",
810
+ children: /* @__PURE__ */ jsxs(CardContent, {
811
+ className: "p-5",
812
+ children: [
813
+ /* @__PURE__ */ jsx("span", {
814
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.interaction}`,
815
+ children: "interaction"
816
+ }),
817
+ /* @__PURE__ */ jsx("div", {
818
+ className: "font-semibold text-card-foreground",
819
+ children: inter.title || inter.name
820
+ }),
821
+ /* @__PURE__ */ jsx("div", {
822
+ className: "mt-1 text-sm text-muted-foreground",
823
+ children: inter.description || "No description"
824
+ }),
825
+ inter.tags && inter.tags.length > 0 && /* @__PURE__ */ jsx("div", {
826
+ className: "mt-2 flex flex-wrap gap-1",
827
+ children: inter.tags.map((tag) => /* @__PURE__ */ jsx(Badge, { children: tag }, tag))
828
+ })
829
+ ]
830
+ })
831
+ })
832
+ }, inter.id))
833
+ })
834
+ });
606
835
  }
836
+ //#endregion
837
+ //#region src/pages/InteractionDetail.tsx
607
838
  function InteractionDetail() {
608
- const { client } = useUserSession();
609
- const params = useParams();
610
- const collection = params.collection;
611
- const name = params.name;
612
- const { baseUrl } = useAdminContext();
613
- const { data: interaction, error } = useFetch(
614
- () => client.getRawJWT().then((token) => fetch(`${baseUrl}/interactions/${collection}/${name}`, {
615
- headers: {
616
- Authorization: `Bearer ${token}`
617
- }
618
- })).then((r) => {
619
- if (!r.ok) throw new Error(`Failed to load interaction: ${r.statusText}`);
620
- return r.json();
621
- }),
622
- [baseUrl, collection, name]
623
- );
624
- if (error) {
625
- return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
626
- "Failed to load interaction “",
627
- name,
628
- "”."
629
- ] });
630
- }
631
- if (!interaction) {
632
- return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
633
- }
634
- const { agent_runner_options } = interaction;
635
- const hasAgentFlags = agent_runner_options && (agent_runner_options.is_agent || agent_runner_options.is_tool || agent_runner_options.is_skill);
636
- return /* @__PURE__ */ jsxs(
637
- DetailPage,
638
- {
639
- type: "interaction",
640
- title: interaction.title || interaction.name,
641
- description: interaction.description,
642
- tags: interaction.tags,
643
- backHref: `/interactions/${collection}`,
644
- children: [
645
- interaction.prompts && interaction.prompts.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
646
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Prompts" }),
647
- interaction.prompts.map((prompt) => /* @__PURE__ */ jsx(Card, { className: "mb-3", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-4", children: [
648
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
649
- /* @__PURE__ */ jsx("span", { className: `rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${ROLE_VARIANTS[prompt.role] ?? ""}`, children: prompt.role }),
650
- prompt.name && /* @__PURE__ */ jsx("span", { className: "text-sm italic text-muted-foreground", children: prompt.name })
651
- ] }),
652
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: prompt.content })
653
- ] }) }, `${prompt.role}-${prompt.name ?? ""}`))
654
- ] }),
655
- interaction.result_schema && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
656
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Result Schema" }),
657
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(interaction.result_schema, null, 2) })
658
- ] }),
659
- hasAgentFlags && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
660
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Agent Runner" }),
661
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
662
- agent_runner_options.is_agent && /* @__PURE__ */ jsx(Badge, { variant: "success", children: "Agent" }),
663
- agent_runner_options.is_tool && /* @__PURE__ */ jsx(Badge, { variant: "success", children: "Tool" }),
664
- agent_runner_options.is_skill && /* @__PURE__ */ jsx(Badge, { variant: "success", children: "Skill" })
665
- ] })
666
- ] })
667
- ]
668
- }
669
- );
839
+ const { client } = useUserSession();
840
+ const params = useParams();
841
+ const collection = params.collection;
842
+ const name = params.name;
843
+ const { baseUrl } = useAdminContext();
844
+ const { data: interaction, error } = useFetch(() => client.getRawJWT().then((token) => fetch(`${baseUrl}/interactions/${collection}/${name}`, { headers: { Authorization: `Bearer ${token}` } })).then((r) => {
845
+ if (!r.ok) throw new Error(`Failed to load interaction: ${r.statusText}`);
846
+ return r.json();
847
+ }), [
848
+ baseUrl,
849
+ collection,
850
+ name
851
+ ]);
852
+ if (error) return /* @__PURE__ */ jsxs("div", {
853
+ className: "p-6 text-destructive",
854
+ children: [
855
+ "Failed to load interaction “",
856
+ name,
857
+ "”."
858
+ ]
859
+ });
860
+ if (!interaction) return /* @__PURE__ */ jsx("div", {
861
+ className: "flex h-64 items-center justify-center text-muted-foreground",
862
+ children: /* @__PURE__ */ jsx(Spinner, {})
863
+ });
864
+ const { agent_runner_options } = interaction;
865
+ const hasAgentFlags = agent_runner_options && (agent_runner_options.is_agent || agent_runner_options.is_tool || agent_runner_options.is_skill);
866
+ return /* @__PURE__ */ jsxs(DetailPage, {
867
+ type: "interaction",
868
+ title: interaction.title || interaction.name,
869
+ description: interaction.description,
870
+ tags: interaction.tags,
871
+ backHref: `/interactions/${collection}`,
872
+ children: [
873
+ interaction.prompts && interaction.prompts.length > 0 && /* @__PURE__ */ jsxs("div", {
874
+ className: "mb-8",
875
+ children: [/* @__PURE__ */ jsx("h2", {
876
+ className: "mb-3 text-lg font-semibold text-foreground",
877
+ children: "Prompts"
878
+ }), interaction.prompts.map((prompt) => /* @__PURE__ */ jsx(Card, {
879
+ className: "mb-3",
880
+ children: /* @__PURE__ */ jsxs(CardContent, {
881
+ className: "p-4",
882
+ children: [/* @__PURE__ */ jsxs("div", {
883
+ className: "mb-2 flex items-center gap-2",
884
+ children: [/* @__PURE__ */ jsx("span", {
885
+ className: `rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${ROLE_VARIANTS[prompt.role] ?? ""}`,
886
+ children: prompt.role
887
+ }), prompt.name && /* @__PURE__ */ jsx("span", {
888
+ className: "text-sm italic text-muted-foreground",
889
+ children: prompt.name
890
+ })]
891
+ }), /* @__PURE__ */ jsx("pre", {
892
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
893
+ children: prompt.content
894
+ })]
895
+ })
896
+ }, `${prompt.role}-${prompt.name ?? ""}`))]
897
+ }),
898
+ interaction.result_schema && /* @__PURE__ */ jsxs("div", {
899
+ className: "mb-8",
900
+ children: [/* @__PURE__ */ jsx("h2", {
901
+ className: "mb-3 text-lg font-semibold text-foreground",
902
+ children: "Result Schema"
903
+ }), /* @__PURE__ */ jsx("pre", {
904
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
905
+ children: JSON.stringify(interaction.result_schema, null, 2)
906
+ })]
907
+ }),
908
+ hasAgentFlags && /* @__PURE__ */ jsxs("div", {
909
+ className: "mb-8",
910
+ children: [/* @__PURE__ */ jsx("h2", {
911
+ className: "mb-3 text-lg font-semibold text-foreground",
912
+ children: "Agent Runner"
913
+ }), /* @__PURE__ */ jsxs("div", {
914
+ className: "flex flex-wrap gap-2",
915
+ children: [
916
+ agent_runner_options.is_agent && /* @__PURE__ */ jsx(Badge, {
917
+ variant: "success",
918
+ children: "Agent"
919
+ }),
920
+ agent_runner_options.is_tool && /* @__PURE__ */ jsx(Badge, {
921
+ variant: "success",
922
+ children: "Tool"
923
+ }),
924
+ agent_runner_options.is_skill && /* @__PURE__ */ jsx(Badge, {
925
+ variant: "success",
926
+ children: "Skill"
927
+ })
928
+ ]
929
+ })]
930
+ })
931
+ ]
932
+ });
670
933
  }
934
+ //#endregion
935
+ //#region src/pages/SkillCollection.tsx
936
+ /** Strip the learn_ prefix added by the SDK when exposing skills as tools. */
671
937
  function skillDisplayName(name) {
672
- return name.startsWith("learn_") ? name.slice(6) : name;
938
+ return name.startsWith("learn_") ? name.slice(6) : name;
673
939
  }
674
940
  function SkillCollection() {
675
- const collection = useParams("collection");
676
- const { baseUrl } = useAdminContext();
677
- const { data, error } = useFetch(
678
- () => fetch(`${baseUrl}/skills/${collection}`).then((r) => {
679
- if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
680
- return r.json();
681
- }),
682
- [baseUrl, collection]
683
- );
684
- const { data: widgetsData } = useFetch(
685
- () => fetch(`${baseUrl}/package?scope=widgets`).then((r) => r.ok ? r.json() : { widgets: {} }),
686
- [baseUrl]
687
- );
688
- const collectionWidgets = useMemo(() => {
689
- if (!widgetsData?.widgets) return [];
690
- return Object.entries(widgetsData.widgets).filter(([_, w]) => w.collection === collection).map(([name, w]) => ({ name, ...w }));
691
- }, [widgetsData, collection]);
692
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
693
- "Failed to load skill collection “",
694
- collection,
695
- "”."
696
- ] });
697
- if (!data) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
698
- return /* @__PURE__ */ jsxs(
699
- DetailPage,
700
- {
701
- type: "skill",
702
- title: data.title || collection,
703
- description: data.description || `${data.tools.length} skill${data.tools.length !== 1 ? "s" : ""} in this collection.`,
704
- children: [
705
- collectionWidgets.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
706
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Widgets" }),
707
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: collectionWidgets.map((w) => /* @__PURE__ */ jsxs(Badge, { variant: "success", children: [
708
- w.name,
709
- /* @__PURE__ */ jsxs("span", { className: "ml-2 font-mono text-xs opacity-70", children: [
710
- "(skill: ",
711
- w.skill,
712
- ")"
713
- ] })
714
- ] }, w.name)) })
715
- ] }),
716
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: data.tools.map((skill) => {
717
- const displayName = skillDisplayName(skill.name);
718
- return /* @__PURE__ */ jsx(NavLink, { href: `/skills/${collection}/${displayName}`, className: "block no-underline", children: /* @__PURE__ */ jsx(Card, { className: "cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
719
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.skill}`, children: "skill" }),
720
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: displayName }),
721
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: skill.description || "No description" }),
722
- skill.related_tools && skill.related_tools.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-1", children: skill.related_tools.map((t) => /* @__PURE__ */ jsx(Badge, { children: t }, t)) })
723
- ] }) }) }, skill.name);
724
- }) })
725
- ]
726
- }
727
- );
941
+ const collection = useParams("collection");
942
+ const { baseUrl } = useAdminContext();
943
+ const { data, error } = useFetch(() => fetch(`${baseUrl}/skills/${collection}`).then((r) => {
944
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
945
+ return r.json();
946
+ }), [baseUrl, collection]);
947
+ const { data: widgetsData } = useFetch(() => fetch(`${baseUrl}/package?scope=widgets`).then((r) => r.ok ? r.json() : { widgets: {} }), [baseUrl]);
948
+ const collectionWidgets = useMemo(() => {
949
+ if (!widgetsData?.widgets) return [];
950
+ return Object.entries(widgetsData.widgets).filter(([_, w]) => w.collection === collection).map(([name, w]) => ({
951
+ name,
952
+ ...w
953
+ }));
954
+ }, [widgetsData, collection]);
955
+ if (error) return /* @__PURE__ */ jsxs("div", {
956
+ className: "p-6 text-destructive",
957
+ children: [
958
+ "Failed to load skill collection ",
959
+ collection,
960
+ "”."
961
+ ]
962
+ });
963
+ if (!data) return /* @__PURE__ */ jsx("div", {
964
+ className: "flex h-64 items-center justify-center text-muted-foreground",
965
+ children: /* @__PURE__ */ jsx(Spinner, {})
966
+ });
967
+ return /* @__PURE__ */ jsxs(DetailPage, {
968
+ type: "skill",
969
+ title: data.title || collection,
970
+ description: data.description || `${data.tools.length} skill${data.tools.length !== 1 ? "s" : ""} in this collection.`,
971
+ children: [collectionWidgets.length > 0 && /* @__PURE__ */ jsxs("div", {
972
+ className: "mb-8",
973
+ children: [/* @__PURE__ */ jsx("h2", {
974
+ className: "mb-3 text-lg font-semibold text-foreground",
975
+ children: "Widgets"
976
+ }), /* @__PURE__ */ jsx("div", {
977
+ className: "flex flex-wrap gap-2",
978
+ children: collectionWidgets.map((w) => /* @__PURE__ */ jsxs(Badge, {
979
+ variant: "success",
980
+ children: [w.name, /* @__PURE__ */ jsxs("span", {
981
+ className: "ml-2 font-mono text-xs opacity-70",
982
+ children: [
983
+ "(skill: ",
984
+ w.skill,
985
+ ")"
986
+ ]
987
+ })]
988
+ }, w.name))
989
+ })]
990
+ }), /* @__PURE__ */ jsx("div", {
991
+ className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3",
992
+ children: data.tools.map((skill) => {
993
+ const displayName = skillDisplayName(skill.name);
994
+ return /* @__PURE__ */ jsx(NavLink, {
995
+ href: `/skills/${collection}/${displayName}`,
996
+ className: "block no-underline",
997
+ children: /* @__PURE__ */ jsx(Card, {
998
+ className: "cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md",
999
+ children: /* @__PURE__ */ jsxs(CardContent, {
1000
+ className: "p-5",
1001
+ children: [
1002
+ /* @__PURE__ */ jsx("span", {
1003
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.skill}`,
1004
+ children: "skill"
1005
+ }),
1006
+ /* @__PURE__ */ jsx("div", {
1007
+ className: "font-semibold text-card-foreground",
1008
+ children: displayName
1009
+ }),
1010
+ /* @__PURE__ */ jsx("div", {
1011
+ className: "mt-1 text-sm text-muted-foreground",
1012
+ children: skill.description || "No description"
1013
+ }),
1014
+ skill.tools && skill.tools.length > 0 && /* @__PURE__ */ jsx("div", {
1015
+ className: "mt-2 flex flex-wrap gap-1",
1016
+ children: skill.tools.map((t) => /* @__PURE__ */ jsx(Badge, { children: t }, t))
1017
+ })
1018
+ ]
1019
+ })
1020
+ })
1021
+ }, skill.name);
1022
+ })
1023
+ })]
1024
+ });
728
1025
  }
1026
+ //#endregion
1027
+ //#region src/pages/SkillDetail.tsx
729
1028
  function SkillDetail() {
730
- const params = useParams();
731
- const collection = params.collection;
732
- const name = params.name;
733
- const { baseUrl } = useAdminContext();
734
- const { data: skill, error } = useFetch(
735
- () => fetch(`${baseUrl}/skills/${collection}/${name}`).then((r) => {
736
- if (!r.ok) throw new Error(`Failed to load skill: ${r.statusText}`);
737
- return r.json();
738
- }),
739
- [baseUrl, collection, name]
740
- );
741
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
742
- "Failed to load skill ",
743
- name,
744
- "”."
745
- ] });
746
- if (!skill) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
747
- return /* @__PURE__ */ jsxs(
748
- DetailPage,
749
- {
750
- type: "skill",
751
- title: skill.title || skill.name,
752
- description: skill.description,
753
- backHref: `/skills/${collection}`,
754
- children: [
755
- skill.widgets && skill.widgets.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
756
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Widgets" }),
757
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: skill.widgets.map((w) => /* @__PURE__ */ jsx(Badge, { variant: "success", children: w }, w)) })
758
- ] }),
759
- skill.scripts && skill.scripts.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
760
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Scripts" }),
761
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: skill.scripts.map((s) => /* @__PURE__ */ jsx(Badge, { variant: "success", children: s }, s)) })
762
- ] }),
763
- skill.related_tools && skill.related_tools.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
764
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Related Tools" }),
765
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: skill.related_tools.map((t) => /* @__PURE__ */ jsx(Badge, { variant: "success", children: t }, t)) })
766
- ] }),
767
- skill.execution && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
768
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Execution" }),
769
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
770
- /* @__PURE__ */ jsx(Badge, { variant: "success", children: skill.execution.language }),
771
- skill.execution.packages?.map((p) => /* @__PURE__ */ jsx(Badge, { variant: "success", children: p }, p))
772
- ] })
773
- ] }),
774
- /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
775
- /* @__PURE__ */ jsxs("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: [
776
- "Instructions",
777
- skill.content_type === "jst" && /* @__PURE__ */ jsx(Badge, { className: "ml-2", children: "JST template" })
778
- ] }),
779
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: skill.instructions })
780
- ] }),
781
- skill.input_schema && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
782
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Input Schema" }),
783
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(skill.input_schema, null, 2) })
784
- ] })
785
- ]
786
- }
787
- );
1029
+ const params = useParams();
1030
+ const collection = params.collection;
1031
+ const name = params.name;
1032
+ const { baseUrl } = useAdminContext();
1033
+ const { data: skill, error } = useFetch(() => fetch(`${baseUrl}/skills/${collection}/${name}`).then((r) => {
1034
+ if (!r.ok) throw new Error(`Failed to load skill: ${r.statusText}`);
1035
+ return r.json();
1036
+ }), [
1037
+ baseUrl,
1038
+ collection,
1039
+ name
1040
+ ]);
1041
+ if (error) return /* @__PURE__ */ jsxs("div", {
1042
+ className: "p-6 text-destructive",
1043
+ children: [
1044
+ "Failed to load skill “",
1045
+ name,
1046
+ "”."
1047
+ ]
1048
+ });
1049
+ if (!skill) return /* @__PURE__ */ jsx("div", {
1050
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1051
+ children: /* @__PURE__ */ jsx(Spinner, {})
1052
+ });
1053
+ return /* @__PURE__ */ jsxs(DetailPage, {
1054
+ type: "skill",
1055
+ title: skill.title || skill.name,
1056
+ description: skill.description,
1057
+ backHref: `/skills/${collection}`,
1058
+ children: [
1059
+ skill.widgets && skill.widgets.length > 0 && /* @__PURE__ */ jsxs("div", {
1060
+ className: "mb-8",
1061
+ children: [/* @__PURE__ */ jsx("h2", {
1062
+ className: "mb-3 text-lg font-semibold text-foreground",
1063
+ children: "Widgets"
1064
+ }), /* @__PURE__ */ jsx("div", {
1065
+ className: "flex flex-wrap gap-2",
1066
+ children: skill.widgets.map((w) => /* @__PURE__ */ jsx(Badge, {
1067
+ variant: "success",
1068
+ children: w
1069
+ }, w))
1070
+ })]
1071
+ }),
1072
+ skill.scripts && skill.scripts.length > 0 && /* @__PURE__ */ jsxs("div", {
1073
+ className: "mb-8",
1074
+ children: [/* @__PURE__ */ jsx("h2", {
1075
+ className: "mb-3 text-lg font-semibold text-foreground",
1076
+ children: "Scripts"
1077
+ }), /* @__PURE__ */ jsx("div", {
1078
+ className: "flex flex-wrap gap-2",
1079
+ children: skill.scripts.map((s) => /* @__PURE__ */ jsx(Badge, {
1080
+ variant: "success",
1081
+ children: s
1082
+ }, s))
1083
+ })]
1084
+ }),
1085
+ skill.tools && skill.tools.length > 0 && /* @__PURE__ */ jsxs("div", {
1086
+ className: "mb-8",
1087
+ children: [/* @__PURE__ */ jsx("h2", {
1088
+ className: "mb-3 text-lg font-semibold text-foreground",
1089
+ children: "Related Tools"
1090
+ }), /* @__PURE__ */ jsx("div", {
1091
+ className: "flex flex-wrap gap-2",
1092
+ children: skill.tools.map((t) => /* @__PURE__ */ jsx(Badge, {
1093
+ variant: "success",
1094
+ children: t
1095
+ }, t))
1096
+ })]
1097
+ }),
1098
+ skill.execution && /* @__PURE__ */ jsxs("div", {
1099
+ className: "mb-8",
1100
+ children: [/* @__PURE__ */ jsx("h2", {
1101
+ className: "mb-3 text-lg font-semibold text-foreground",
1102
+ children: "Execution"
1103
+ }), /* @__PURE__ */ jsxs("div", {
1104
+ className: "flex flex-wrap gap-2",
1105
+ children: [/* @__PURE__ */ jsx(Badge, {
1106
+ variant: "success",
1107
+ children: skill.execution.language
1108
+ }), skill.execution.packages?.map((p) => /* @__PURE__ */ jsx(Badge, {
1109
+ variant: "success",
1110
+ children: p
1111
+ }, p))]
1112
+ })]
1113
+ }),
1114
+ /* @__PURE__ */ jsxs("div", {
1115
+ className: "mb-8",
1116
+ children: [/* @__PURE__ */ jsxs("h2", {
1117
+ className: "mb-3 text-lg font-semibold text-foreground",
1118
+ children: ["Instructions", skill.content_type === "jst" && /* @__PURE__ */ jsx(Badge, {
1119
+ className: "ml-2",
1120
+ children: "JST template"
1121
+ })]
1122
+ }), /* @__PURE__ */ jsx("pre", {
1123
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
1124
+ children: skill.instructions
1125
+ })]
1126
+ }),
1127
+ skill.input_schema && /* @__PURE__ */ jsxs("div", {
1128
+ className: "mb-8",
1129
+ children: [/* @__PURE__ */ jsx("h2", {
1130
+ className: "mb-3 text-lg font-semibold text-foreground",
1131
+ children: "Input Schema"
1132
+ }), /* @__PURE__ */ jsx("pre", {
1133
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
1134
+ children: JSON.stringify(skill.input_schema, null, 2)
1135
+ })]
1136
+ })
1137
+ ]
1138
+ });
788
1139
  }
1140
+ //#endregion
1141
+ //#region src/pages/TemplateCollection.tsx
789
1142
  function TemplateCollection() {
790
- const collection = useParams("collection");
791
- const { baseUrl } = useAdminContext();
792
- const { data: templates, error } = useFetch(
793
- () => fetch(`${baseUrl}/templates/${collection}`).then((r) => {
794
- if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
795
- return r.json();
796
- }),
797
- [baseUrl, collection]
798
- );
799
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
800
- "Failed to load template collection “",
801
- collection,
802
- "”."
803
- ] });
804
- if (!templates) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
805
- return /* @__PURE__ */ jsx(
806
- DetailPage,
807
- {
808
- type: "template",
809
- title: collection,
810
- description: `${templates.length} template${templates.length !== 1 ? "s" : ""} in this collection.`,
811
- children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: templates.map((tmpl) => /* @__PURE__ */ jsx(
812
- NavLink,
813
- {
814
- href: `/templates/${collection}/${tmpl.name}`,
815
- className: "no-underline",
816
- children: /* @__PURE__ */ jsx(Card, { className: "h-full transition-all hover:-translate-y-0.5 hover:shadow-md", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
817
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.template}`, children: tmpl.type || "template" }),
818
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: tmpl.title || tmpl.name }),
819
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: tmpl.description || "No description" }),
820
- tmpl.tags && tmpl.tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-1.5", children: tmpl.tags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: tag }, tag)) })
821
- ] }) })
822
- },
823
- tmpl.name
824
- )) })
825
- }
826
- );
1143
+ const collection = useParams("collection");
1144
+ const { baseUrl } = useAdminContext();
1145
+ const { data: templates, error } = useFetch(() => fetch(`${baseUrl}/templates/${collection}`).then((r) => {
1146
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
1147
+ return r.json();
1148
+ }), [baseUrl, collection]);
1149
+ if (error) return /* @__PURE__ */ jsxs("div", {
1150
+ className: "p-6 text-destructive",
1151
+ children: [
1152
+ "Failed to load template collection ",
1153
+ collection,
1154
+ "”."
1155
+ ]
1156
+ });
1157
+ if (!templates) return /* @__PURE__ */ jsx("div", {
1158
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1159
+ children: /* @__PURE__ */ jsx(Spinner, {})
1160
+ });
1161
+ return /* @__PURE__ */ jsx(DetailPage, {
1162
+ type: "template",
1163
+ title: collection,
1164
+ description: `${templates.length} template${templates.length !== 1 ? "s" : ""} in this collection.`,
1165
+ children: /* @__PURE__ */ jsx("div", {
1166
+ className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3",
1167
+ children: templates.map((tmpl) => /* @__PURE__ */ jsx(NavLink, {
1168
+ href: `/templates/${collection}/${tmpl.name}`,
1169
+ className: "no-underline",
1170
+ children: /* @__PURE__ */ jsx(Card, {
1171
+ className: "h-full transition-all hover:-translate-y-0.5 hover:shadow-md",
1172
+ children: /* @__PURE__ */ jsxs(CardContent, {
1173
+ className: "p-5",
1174
+ children: [
1175
+ /* @__PURE__ */ jsx("span", {
1176
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.template}`,
1177
+ children: tmpl.type || "template"
1178
+ }),
1179
+ /* @__PURE__ */ jsx("div", {
1180
+ className: "font-semibold text-card-foreground",
1181
+ children: tmpl.title || tmpl.name
1182
+ }),
1183
+ /* @__PURE__ */ jsx("div", {
1184
+ className: "mt-1 text-sm text-muted-foreground",
1185
+ children: tmpl.description || "No description"
1186
+ }),
1187
+ tmpl.tags && tmpl.tags.length > 0 && /* @__PURE__ */ jsx("div", {
1188
+ className: "mt-3 flex flex-wrap gap-1.5",
1189
+ children: tmpl.tags.map((tag) => /* @__PURE__ */ jsx(Badge, {
1190
+ variant: "default",
1191
+ children: tag
1192
+ }, tag))
1193
+ })
1194
+ ]
1195
+ })
1196
+ })
1197
+ }, tmpl.name))
1198
+ })
1199
+ });
827
1200
  }
1201
+ //#endregion
1202
+ //#region src/pages/TemplateDetail.tsx
828
1203
  function TemplateDetail() {
829
- const params = useParams();
830
- const collection = params.collection;
831
- const name = params.name;
832
- const { baseUrl } = useAdminContext();
833
- const { data: template, error } = useFetch(
834
- () => fetch(`${baseUrl}/templates/${collection}/${name}`).then((r) => {
835
- if (!r.ok) throw new Error(`Failed to load template: ${r.statusText}`);
836
- return r.json();
837
- }),
838
- [baseUrl, collection, name]
839
- );
840
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
841
- "Failed to load template ",
842
- name,
843
- "”."
844
- ] });
845
- if (!template) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
846
- return /* @__PURE__ */ jsxs(
847
- DetailPage,
848
- {
849
- type: "template",
850
- title: template.title || template.name,
851
- description: template.description,
852
- tags: template.tags,
853
- backHref: `/templates/${collection}`,
854
- children: [
855
- /* @__PURE__ */ jsx("div", { className: "mb-8", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: /* @__PURE__ */ jsx(Badge, { variant: "success", children: template.type }) }) }),
856
- template.assets && template.assets.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
857
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Assets" }),
858
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: template.assets.map((asset) => /* @__PURE__ */ jsx(Badge, { variant: "success", children: asset.split("/").pop() }, asset)) })
859
- ] }),
860
- /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
861
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Instructions" }),
862
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: template.instructions })
863
- ] })
864
- ]
865
- }
866
- );
1204
+ const params = useParams();
1205
+ const collection = params.collection;
1206
+ const name = params.name;
1207
+ const { baseUrl } = useAdminContext();
1208
+ const { data: template, error } = useFetch(() => fetch(`${baseUrl}/templates/${collection}/${name}`).then((r) => {
1209
+ if (!r.ok) throw new Error(`Failed to load template: ${r.statusText}`);
1210
+ return r.json();
1211
+ }), [
1212
+ baseUrl,
1213
+ collection,
1214
+ name
1215
+ ]);
1216
+ if (error) return /* @__PURE__ */ jsxs("div", {
1217
+ className: "p-6 text-destructive",
1218
+ children: [
1219
+ "Failed to load template “",
1220
+ name,
1221
+ "”."
1222
+ ]
1223
+ });
1224
+ if (!template) return /* @__PURE__ */ jsx("div", {
1225
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1226
+ children: /* @__PURE__ */ jsx(Spinner, {})
1227
+ });
1228
+ return /* @__PURE__ */ jsxs(DetailPage, {
1229
+ type: "template",
1230
+ title: template.title || template.name,
1231
+ description: template.description,
1232
+ tags: template.tags,
1233
+ backHref: `/templates/${collection}`,
1234
+ children: [
1235
+ /* @__PURE__ */ jsx("div", {
1236
+ className: "mb-8",
1237
+ children: /* @__PURE__ */ jsx("div", {
1238
+ className: "flex flex-wrap gap-2",
1239
+ children: /* @__PURE__ */ jsx(Badge, {
1240
+ variant: "success",
1241
+ children: template.type
1242
+ })
1243
+ })
1244
+ }),
1245
+ template.assets && template.assets.length > 0 && /* @__PURE__ */ jsxs("div", {
1246
+ className: "mb-8",
1247
+ children: [/* @__PURE__ */ jsx("h2", {
1248
+ className: "mb-3 text-lg font-semibold text-foreground",
1249
+ children: "Assets"
1250
+ }), /* @__PURE__ */ jsx("div", {
1251
+ className: "flex flex-wrap gap-2",
1252
+ children: template.assets.map((asset) => /* @__PURE__ */ jsx(Badge, {
1253
+ variant: "success",
1254
+ children: asset.split("/").pop()
1255
+ }, asset))
1256
+ })]
1257
+ }),
1258
+ /* @__PURE__ */ jsxs("div", {
1259
+ className: "mb-8",
1260
+ children: [/* @__PURE__ */ jsx("h2", {
1261
+ className: "mb-3 text-lg font-semibold text-foreground",
1262
+ children: "Instructions"
1263
+ }), /* @__PURE__ */ jsx("pre", {
1264
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
1265
+ children: template.instructions
1266
+ })]
1267
+ })
1268
+ ]
1269
+ });
867
1270
  }
1271
+ //#endregion
1272
+ //#region src/pages/ToolCollection.tsx
868
1273
  function ToolCollection() {
869
- const collection = useParams("collection");
870
- const { baseUrl } = useAdminContext();
871
- const { data, error } = useFetch(
872
- () => fetch(`${baseUrl}/tools/${collection}`).then((r) => {
873
- if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
874
- return r.json();
875
- }),
876
- [baseUrl, collection]
877
- );
878
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
879
- "Failed to load tool collection “",
880
- collection,
881
- "”."
882
- ] });
883
- if (!data) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
884
- return /* @__PURE__ */ jsx(
885
- DetailPage,
886
- {
887
- type: "tool",
888
- title: data.title || collection,
889
- description: data.description || `${data.tools.length} tool${data.tools.length !== 1 ? "s" : ""} in this collection.`,
890
- children: data.tools.map((tool) => /* @__PURE__ */ jsx(Card, { className: "mb-4", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
891
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
892
- /* @__PURE__ */ jsx("span", { className: `inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.tool}`, children: "tool" }),
893
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-card-foreground", children: tool.name })
894
- ] }),
895
- /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: tool.description || "No description" }),
896
- tool.input_schema && /* @__PURE__ */ jsx("pre", { className: "mt-3 whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(tool.input_schema, null, 2) })
897
- ] }) }, tool.name))
898
- }
899
- );
1274
+ const collection = useParams("collection");
1275
+ const { baseUrl } = useAdminContext();
1276
+ const { data, error } = useFetch(() => fetch(`${baseUrl}/tools/${collection}`).then((r) => {
1277
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
1278
+ return r.json();
1279
+ }), [baseUrl, collection]);
1280
+ if (error) return /* @__PURE__ */ jsxs("div", {
1281
+ className: "p-6 text-destructive",
1282
+ children: [
1283
+ "Failed to load tool collection ",
1284
+ collection,
1285
+ "”."
1286
+ ]
1287
+ });
1288
+ if (!data) return /* @__PURE__ */ jsx("div", {
1289
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1290
+ children: /* @__PURE__ */ jsx(Spinner, {})
1291
+ });
1292
+ return /* @__PURE__ */ jsx(DetailPage, {
1293
+ type: "tool",
1294
+ title: data.title || collection,
1295
+ description: data.description || `${data.tools.length} tool${data.tools.length !== 1 ? "s" : ""} in this collection.`,
1296
+ children: data.tools.map((tool) => /* @__PURE__ */ jsx(Card, {
1297
+ className: "mb-4",
1298
+ children: /* @__PURE__ */ jsxs(CardContent, {
1299
+ className: "p-5",
1300
+ children: [
1301
+ /* @__PURE__ */ jsxs("div", {
1302
+ className: "mb-2 flex items-center gap-2",
1303
+ children: [/* @__PURE__ */ jsx("span", {
1304
+ className: `inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.tool}`,
1305
+ children: "tool"
1306
+ }), /* @__PURE__ */ jsx("span", {
1307
+ className: "font-semibold text-card-foreground",
1308
+ children: tool.name
1309
+ })]
1310
+ }),
1311
+ /* @__PURE__ */ jsx("div", {
1312
+ className: "text-sm text-muted-foreground",
1313
+ children: tool.description || "No description"
1314
+ }),
1315
+ tool.input_schema && /* @__PURE__ */ jsx("pre", {
1316
+ className: "mt-3 whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
1317
+ children: JSON.stringify(tool.input_schema, null, 2)
1318
+ })
1319
+ ]
1320
+ })
1321
+ }, tool.name))
1322
+ });
900
1323
  }
1324
+ //#endregion
1325
+ //#region src/pages/TypeCollection.tsx
901
1326
  function TypeCollection() {
902
- const collection = useParams("collection");
903
- const { baseUrl } = useAdminContext();
904
- const { data: types, error } = useFetch(
905
- () => fetch(`${baseUrl}/types/${collection}`).then((r) => {
906
- if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
907
- return r.json();
908
- }),
909
- [baseUrl, collection]
910
- );
911
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
912
- "Failed to load type collection “",
913
- collection,
914
- "”."
915
- ] });
916
- if (!types) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
917
- return /* @__PURE__ */ jsx(
918
- DetailPage,
919
- {
920
- type: "type",
921
- title: collection,
922
- description: `${types.length} content type${types.length !== 1 ? "s" : ""} in this collection.`,
923
- children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: types.map((t) => {
924
- const typeName = t.id?.split(":")[1] || t.name;
925
- return /* @__PURE__ */ jsx(
926
- NavLink,
927
- {
928
- href: `/types/${collection}/${typeName}`,
929
- className: "no-underline",
930
- children: /* @__PURE__ */ jsx(Card, { className: "h-full transition-all hover:-translate-y-0.5 hover:shadow-md", children: /* @__PURE__ */ jsxs(CardContent, { className: "p-5", children: [
931
- /* @__PURE__ */ jsx("span", { className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.type}`, children: "type" }),
932
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: t.name }),
933
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: t.description || "No description" }),
934
- t.tags && t.tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-1.5", children: t.tags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: tag }, tag)) }),
935
- (t.is_chunkable || t.strict_mode) && /* @__PURE__ */ jsxs("div", { className: "mt-2 truncate font-mono text-xs text-muted-foreground", children: [
936
- t.is_chunkable && "chunkable",
937
- t.is_chunkable && t.strict_mode && " · ",
938
- t.strict_mode && "strict"
939
- ] })
940
- ] }) })
941
- },
942
- t.name
943
- );
944
- }) })
945
- }
946
- );
1327
+ const collection = useParams("collection");
1328
+ const { baseUrl } = useAdminContext();
1329
+ const { data: types, error } = useFetch(() => fetch(`${baseUrl}/types/${collection}`).then((r) => {
1330
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
1331
+ return r.json();
1332
+ }), [baseUrl, collection]);
1333
+ if (error) return /* @__PURE__ */ jsxs("div", {
1334
+ className: "p-6 text-destructive",
1335
+ children: [
1336
+ "Failed to load type collection ",
1337
+ collection,
1338
+ "”."
1339
+ ]
1340
+ });
1341
+ if (!types) return /* @__PURE__ */ jsx("div", {
1342
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1343
+ children: /* @__PURE__ */ jsx(Spinner, {})
1344
+ });
1345
+ return /* @__PURE__ */ jsx(DetailPage, {
1346
+ type: "type",
1347
+ title: collection,
1348
+ description: `${types.length} content type${types.length !== 1 ? "s" : ""} in this collection.`,
1349
+ children: /* @__PURE__ */ jsx("div", {
1350
+ className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3",
1351
+ children: types.map((t) => {
1352
+ return /* @__PURE__ */ jsx(NavLink, {
1353
+ href: `/types/${collection}/${t.id?.split(":")[1] || t.name}`,
1354
+ className: "no-underline",
1355
+ children: /* @__PURE__ */ jsx(Card, {
1356
+ className: "h-full transition-all hover:-translate-y-0.5 hover:shadow-md",
1357
+ children: /* @__PURE__ */ jsxs(CardContent, {
1358
+ className: "p-5",
1359
+ children: [
1360
+ /* @__PURE__ */ jsx("span", {
1361
+ className: `mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.type}`,
1362
+ children: "type"
1363
+ }),
1364
+ /* @__PURE__ */ jsx("div", {
1365
+ className: "font-semibold text-card-foreground",
1366
+ children: t.name
1367
+ }),
1368
+ /* @__PURE__ */ jsx("div", {
1369
+ className: "mt-1 text-sm text-muted-foreground",
1370
+ children: t.description || "No description"
1371
+ }),
1372
+ t.tags && t.tags.length > 0 && /* @__PURE__ */ jsx("div", {
1373
+ className: "mt-3 flex flex-wrap gap-1.5",
1374
+ children: t.tags.map((tag) => /* @__PURE__ */ jsx(Badge, {
1375
+ variant: "default",
1376
+ children: tag
1377
+ }, tag))
1378
+ }),
1379
+ (t.is_chunkable || t.strict_mode) && /* @__PURE__ */ jsxs("div", {
1380
+ className: "mt-2 truncate font-mono text-xs text-muted-foreground",
1381
+ children: [
1382
+ t.is_chunkable && "chunkable",
1383
+ t.is_chunkable && t.strict_mode && " · ",
1384
+ t.strict_mode && "strict"
1385
+ ]
1386
+ })
1387
+ ]
1388
+ })
1389
+ })
1390
+ }, t.name);
1391
+ })
1392
+ })
1393
+ });
947
1394
  }
1395
+ //#endregion
1396
+ //#region src/pages/TypeDetail.tsx
948
1397
  function TypeDetail() {
949
- const params = useParams();
950
- const collection = params.collection;
951
- const name = params.name;
952
- const { baseUrl } = useAdminContext();
953
- const { data: typeDef, error } = useFetch(
954
- () => fetch(`${baseUrl}/types/${collection}/${name}`).then((r) => {
955
- if (!r.ok) throw new Error(`Failed to load type: ${r.statusText}`);
956
- return r.json();
957
- }),
958
- [baseUrl, collection, name]
959
- );
960
- if (error) return /* @__PURE__ */ jsxs("div", { className: "p-6 text-destructive", children: [
961
- "Failed to load type ",
962
- name,
963
- "”."
964
- ] });
965
- if (!typeDef) return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
966
- return /* @__PURE__ */ jsxs(
967
- DetailPage,
968
- {
969
- type: "type",
970
- title: typeDef.name,
971
- description: typeDef.description,
972
- tags: typeDef.tags,
973
- backHref: `/types/${collection}`,
974
- children: [
975
- (typeDef.is_chunkable || typeDef.strict_mode) && /* @__PURE__ */ jsx("div", { className: "mb-8", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
976
- typeDef.is_chunkable && /* @__PURE__ */ jsx(Badge, { variant: "success", children: "Chunkable" }),
977
- typeDef.strict_mode && /* @__PURE__ */ jsx(Badge, { variant: "success", children: "Strict Mode" })
978
- ] }) }),
979
- typeDef.object_schema && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
980
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Object Schema" }),
981
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(typeDef.object_schema, null, 2) })
982
- ] }),
983
- typeDef.table_layout && typeDef.table_layout.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
984
- /* @__PURE__ */ jsx("h2", { className: "mb-3 text-lg font-semibold text-foreground", children: "Table Layout" }),
985
- /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground", children: JSON.stringify(typeDef.table_layout, null, 2) })
986
- ] })
987
- ]
988
- }
989
- );
1398
+ const params = useParams();
1399
+ const collection = params.collection;
1400
+ const name = params.name;
1401
+ const { baseUrl } = useAdminContext();
1402
+ const { data: typeDef, error } = useFetch(() => fetch(`${baseUrl}/types/${collection}/${name}`).then((r) => {
1403
+ if (!r.ok) throw new Error(`Failed to load type: ${r.statusText}`);
1404
+ return r.json();
1405
+ }), [
1406
+ baseUrl,
1407
+ collection,
1408
+ name
1409
+ ]);
1410
+ if (error) return /* @__PURE__ */ jsxs("div", {
1411
+ className: "p-6 text-destructive",
1412
+ children: [
1413
+ "Failed to load type “",
1414
+ name,
1415
+ "”."
1416
+ ]
1417
+ });
1418
+ if (!typeDef) return /* @__PURE__ */ jsx("div", {
1419
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1420
+ children: /* @__PURE__ */ jsx(Spinner, {})
1421
+ });
1422
+ return /* @__PURE__ */ jsxs(DetailPage, {
1423
+ type: "type",
1424
+ title: typeDef.name,
1425
+ description: typeDef.description,
1426
+ tags: typeDef.tags,
1427
+ backHref: `/types/${collection}`,
1428
+ children: [
1429
+ (typeDef.is_chunkable || typeDef.strict_mode) && /* @__PURE__ */ jsx("div", {
1430
+ className: "mb-8",
1431
+ children: /* @__PURE__ */ jsxs("div", {
1432
+ className: "flex flex-wrap gap-2",
1433
+ children: [typeDef.is_chunkable && /* @__PURE__ */ jsx(Badge, {
1434
+ variant: "success",
1435
+ children: "Chunkable"
1436
+ }), typeDef.strict_mode && /* @__PURE__ */ jsx(Badge, {
1437
+ variant: "success",
1438
+ children: "Strict Mode"
1439
+ })]
1440
+ })
1441
+ }),
1442
+ typeDef.object_schema && /* @__PURE__ */ jsxs("div", {
1443
+ className: "mb-8",
1444
+ children: [/* @__PURE__ */ jsx("h2", {
1445
+ className: "mb-3 text-lg font-semibold text-foreground",
1446
+ children: "Object Schema"
1447
+ }), /* @__PURE__ */ jsx("pre", {
1448
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
1449
+ children: JSON.stringify(typeDef.object_schema, null, 2)
1450
+ })]
1451
+ }),
1452
+ typeDef.table_layout && typeDef.table_layout.length > 0 && /* @__PURE__ */ jsxs("div", {
1453
+ className: "mb-8",
1454
+ children: [/* @__PURE__ */ jsx("h2", {
1455
+ className: "mb-3 text-lg font-semibold text-foreground",
1456
+ children: "Table Layout"
1457
+ }), /* @__PURE__ */ jsx("pre", {
1458
+ className: "whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground",
1459
+ children: JSON.stringify(typeDef.table_layout, null, 2)
1460
+ })]
1461
+ })
1462
+ ]
1463
+ });
990
1464
  }
991
- const routes = [
992
- { path: "/", Component: HomePage },
993
- { path: "/interactions/:collection", Component: InteractionCollection },
994
- { path: "/interactions/:collection/:name", Component: InteractionDetail },
995
- { path: "/tools/:collection", Component: ToolCollection },
996
- { path: "/activities/:collection", Component: ActivityCollection },
997
- { path: "/skills/:collection", Component: SkillCollection },
998
- { path: "/skills/:collection/:name", Component: SkillDetail },
999
- { path: "/types/:collection", Component: TypeCollection },
1000
- { path: "/types/:collection/:name", Component: TypeDetail },
1001
- { path: "/templates/:collection", Component: TemplateCollection },
1002
- { path: "/templates/:collection/:name", Component: TemplateDetail }
1465
+ //#endregion
1466
+ //#region src/AdminApp.tsx
1467
+ var routes = [
1468
+ {
1469
+ path: "/",
1470
+ Component: HomePage
1471
+ },
1472
+ {
1473
+ path: "/interactions/:collection",
1474
+ Component: InteractionCollection
1475
+ },
1476
+ {
1477
+ path: "/interactions/:collection/:name",
1478
+ Component: InteractionDetail
1479
+ },
1480
+ {
1481
+ path: "/tools/:collection",
1482
+ Component: ToolCollection
1483
+ },
1484
+ {
1485
+ path: "/activities/:collection",
1486
+ Component: ActivityCollection
1487
+ },
1488
+ {
1489
+ path: "/skills/:collection",
1490
+ Component: SkillCollection
1491
+ },
1492
+ {
1493
+ path: "/skills/:collection/:name",
1494
+ Component: SkillDetail
1495
+ },
1496
+ {
1497
+ path: "/types/:collection",
1498
+ Component: TypeCollection
1499
+ },
1500
+ {
1501
+ path: "/types/:collection/:name",
1502
+ Component: TypeDetail
1503
+ },
1504
+ {
1505
+ path: "/templates/:collection",
1506
+ Component: TemplateCollection
1507
+ },
1508
+ {
1509
+ path: "/templates/:collection/:name",
1510
+ Component: TemplateDetail
1511
+ }
1003
1512
  ];
1513
+ /**
1514
+ * Admin app shell — loads data, provides context, and renders nested routes.
1515
+ *
1516
+ * Requires a parent VertesiaShell (or equivalent providers for ThemeProvider,
1517
+ * UserSessionProvider, ToastProvider).
1518
+ */
1004
1519
  function AdminApp({ baseUrl = "/api" }) {
1005
- const { data: serverInfo, isLoading: loadingInfo, error: infoError } = useServerInfo(baseUrl);
1006
- const { data: resourceData, isLoading: loadingData, error: dataError } = useResourceData(
1007
- baseUrl,
1008
- serverInfo?.endpoints.mcp
1009
- );
1010
- const isLoading = loadingInfo || loadingData;
1011
- const error = infoError || dataError;
1012
- if (isLoading) {
1013
- return /* @__PURE__ */ jsx("div", { className: "flex h-64 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx(Spinner, {}) });
1014
- }
1015
- if (error) {
1016
- return /* @__PURE__ */ jsx("div", { className: "p-6 text-destructive", children: "Failed to load server info. Is the API running?" });
1017
- }
1018
- if (!serverInfo || !resourceData) return null;
1019
- const title = serverInfo.message.replace("Vertesia Tools API", "Tools Server");
1020
- return /* @__PURE__ */ jsxs("div", { className: "min-h-screen bg-background text-foreground", children: [
1021
- /* @__PURE__ */ jsx(AdminTopBar, { title }),
1022
- /* @__PURE__ */ jsx(AdminContext.Provider, { value: {
1023
- serverInfo,
1024
- collections: resourceData.collections,
1025
- resources: resourceData.resources,
1026
- baseUrl
1027
- }, children: /* @__PURE__ */ jsx(NestedRouterProvider, { routes, children: /* @__PURE__ */ jsx(RouteComponent, {}) }) })
1028
- ] });
1520
+ const { data: serverInfo, isLoading: loadingInfo, error: infoError } = useServerInfo(baseUrl);
1521
+ const { data: resourceData, isLoading: loadingData, error: dataError } = useResourceData(baseUrl, serverInfo?.endpoints?.mcp);
1522
+ const isLoading = loadingInfo || loadingData;
1523
+ const error = infoError || dataError;
1524
+ if (isLoading) return /* @__PURE__ */ jsx("div", {
1525
+ className: "flex h-64 items-center justify-center text-muted-foreground",
1526
+ children: /* @__PURE__ */ jsx(Spinner, {})
1527
+ });
1528
+ if (error) return /* @__PURE__ */ jsx("div", {
1529
+ className: "p-6 text-destructive",
1530
+ children: "Failed to load server info. Is the API running?"
1531
+ });
1532
+ if (!serverInfo || !resourceData) return null;
1533
+ return /* @__PURE__ */ jsxs("div", {
1534
+ className: "min-h-screen bg-background text-foreground",
1535
+ children: [/* @__PURE__ */ jsx(AdminTopBar, { title: serverInfo.message.replace("Vertesia Tools API", "Tools Server") }), /* @__PURE__ */ jsx(AdminContext.Provider, {
1536
+ value: {
1537
+ serverInfo,
1538
+ collections: resourceData.collections,
1539
+ resources: resourceData.resources,
1540
+ baseUrl
1541
+ },
1542
+ children: /* @__PURE__ */ jsx(NestedRouterProvider, {
1543
+ routes,
1544
+ children: /* @__PURE__ */ jsx(RouteComponent, {})
1545
+ })
1546
+ })]
1547
+ });
1029
1548
  }
1030
- export {
1031
- AdminApp,
1032
- AdminContext,
1033
- buildResourceData,
1034
- filterResources,
1035
- useAdminContext
1036
- };
1037
- //# sourceMappingURL=tools-admin-ui.js.map
1549
+ //#endregion
1550
+ export { AdminApp, AdminContext, buildResourceData, filterResources, useAdminContext };
1551
+
1552
+ //# sourceMappingURL=tools-admin-ui.js.map