@vertesia/tools-admin-ui 1.0.0-dev.20260305.083323Z → 1.0.0-dev.20260331.091034Z

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AdminApp.d.ts","sourceRoot":"","sources":["../src/AdminApp.tsx"],"names":[],"mappings":"AA+BA,MAAM,WAAW,aAAa;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,OAAgB,EAAE,EAAE,aAAa,kDA6C3D"}
1
+ {"version":3,"file":"AdminApp.d.ts","sourceRoot":"","sources":["../src/AdminApp.tsx"],"names":[],"mappings":"AAiCA,MAAM,WAAW,aAAa;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,OAAgB,EAAE,EAAE,aAAa,kDA6C3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionCard.d.ts","sourceRoot":"","sources":["../../src/components/CollectionCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,wBAAgB,cAAc,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,cAAc,CAAA;CAAE,2CAqB5E"}
1
+ {"version":3,"file":"CollectionCard.d.ts","sourceRoot":"","sources":["../../src/components/CollectionCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,wBAAgB,cAAc,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,cAAc,CAAA;CAAE,2CAsB5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"HeroSection.d.ts","sourceRoot":"","sources":["../../src/components/HeroSection.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,aAAa,CAAC;AAI9D,UAAU,gBAAgB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC7B;AAuBD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CA2D1E"}
1
+ {"version":3,"file":"HeroSection.d.ts","sourceRoot":"","sources":["../../src/components/HeroSection.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,aAAa,CAAC;AAI9D,UAAU,gBAAgB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC7B;AAwBD,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CA2D1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"typeVariants.d.ts","sourceRoot":"","sources":["../../src/components/typeVariants.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOhD,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMhD,CAAC"}
1
+ {"version":3,"file":"typeVariants.d.ts","sourceRoot":"","sources":["../../src/components/typeVariants.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQhD,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMhD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG3D;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM;;;;;;EAK5C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;;;;;;EAavE"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG3D;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM;;;;;;EAK5C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;;;;;;EAcvE"}
@@ -0,0 +1,2 @@
1
+ export declare function ActivityCollection(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=ActivityCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActivityCollection.d.ts","sourceRoot":"","sources":["../../src/pages/ActivityCollection.tsx"],"names":[],"mappings":"AAcA,wBAAgB,kBAAkB,4CAoDjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"HomePage.d.ts","sourceRoot":"","sources":["../../src/pages/HomePage.tsx"],"names":[],"mappings":"AAkBA,wBAAgB,QAAQ,4CAmFvB"}
1
+ {"version":3,"file":"HomePage.d.ts","sourceRoot":"","sources":["../../src/pages/HomePage.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,QAAQ,4CAmFvB"}
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
- import { ModeToggle, Avatar, Button, useFetch, Card, CardContent, Badge, DotBadge, Separator, Input, Spinner } from "@vertesia/ui/core";
2
+ import { ModeToggle, Avatar, Button, useFetch, Badge, Spinner, Card, CardContent, DotBadge, Separator, Input } from "@vertesia/ui/core";
3
3
  import { NavLink, useParams, NestedRouterProvider, RouteComponent } from "@vertesia/ui/router";
4
4
  import { createContext, useContext, useState, useMemo } from "react";
5
5
  import { useUserSession } from "@vertesia/ui/session";
@@ -53,7 +53,7 @@ function countPerCollection(items, collections, extractCollection) {
53
53
  }
54
54
  return counts;
55
55
  }
56
- function buildResourceData(interactionsResp, toolsResp, skillsResp, typesResp, templatesResp, mcpEndpoints) {
56
+ function buildResourceData(interactionsResp, toolsResp, skillsResp, activitiesResp, typesResp, templatesResp, mcpEndpoints) {
57
57
  const collections = [];
58
58
  const resources = [];
59
59
  const interCounts = countPerCollection(
@@ -126,6 +126,29 @@ function buildResourceData(interactionsResp, toolsResp, skillsResp, typesResp, t
126
126
  url: skill.url
127
127
  });
128
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
+ }
129
152
  const typeCounts = countPerCollection(
130
153
  typesResp.types,
131
154
  typesResp.collections,
@@ -208,10 +231,11 @@ function useResourceData(baseUrl, mcpEndpoints) {
208
231
  fetchJson("interactions"),
209
232
  fetchJson("tools"),
210
233
  fetchJson("skills"),
234
+ fetchJson("activities"),
211
235
  fetchJson("types"),
212
236
  fetchJson("templates")
213
237
  ]).then(
214
- ([interactions, tools, skills, types, templates]) => buildResourceData(interactions, tools, skills, types, templates, mcpEndpoints)
238
+ ([interactions, tools, skills, activities, types, templates]) => buildResourceData(interactions, tools, skills, activities, types, templates, mcpEndpoints)
215
239
  );
216
240
  }, [baseUrl, mcpEndpoints]);
217
241
  }
@@ -221,6 +245,7 @@ const TYPE_VARIANTS = {
221
245
  interaction: "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300",
222
246
  type: "bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-300",
223
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",
224
249
  mcp: "bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300"
225
250
  };
226
251
  const ROLE_VARIANTS = {
@@ -230,19 +255,6 @@ const ROLE_VARIANTS = {
230
255
  safety: "bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300",
231
256
  tool: "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300"
232
257
  };
233
- function CollectionCard({ collection }) {
234
- const href = `/${collection.type}s/${collection.name}`;
235
- 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: [
236
- /* @__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 }),
237
- /* @__PURE__ */ jsx("div", { className: "font-semibold text-card-foreground", children: collection.title }),
238
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: collection.description || "No description" }),
239
- /* @__PURE__ */ jsxs("div", { className: "mt-2 font-mono text-xs text-muted-foreground", children: [
240
- collection.count,
241
- " ",
242
- collection.count === 1 ? "item" : "items"
243
- ] })
244
- ] }) }) });
245
- }
246
258
  function DetailPage({ type, title, description, tags, backHref = "/", children }) {
247
259
  return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl px-7 py-10", children: [
248
260
  /* @__PURE__ */ jsxs("nav", { className: "mb-5 flex items-center gap-4", children: [
@@ -261,6 +273,60 @@ function DetailPage({ type, title, description, tags, backHref = "/", children }
261
273
  children
262
274
  ] });
263
275
  }
276
+ 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
+ );
315
+ }
316
+ 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
+ ] }) }) });
329
+ }
264
330
  function EndpointPanel({ label, path }) {
265
331
  const [copied, setCopied] = useState(false);
266
332
  function handleCopy() {
@@ -307,6 +373,7 @@ function countByType(resources) {
307
373
  }
308
374
  const badgeLabels = [
309
375
  { type: "tool", label: "tool" },
376
+ { type: "activity", label: "activity" },
310
377
  { type: "skill", label: "skill" },
311
378
  { type: "interaction", label: "interaction" },
312
379
  { type: "type", label: "content type" },
@@ -425,6 +492,7 @@ function SearchBar({ value, onChange, placeholder, resultCount, totalCount }) {
425
492
  }
426
493
  const sections = [
427
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." },
428
496
  { type: "skill", title: "Skills", subtitle: "Reusable instructions and scripts packaged as tools." },
429
497
  { type: "interaction", title: "Interactions", subtitle: "Conversation blueprints surfaced in the Vertesia UI." },
430
498
  { type: "type", title: "Content Types", subtitle: "Schema definitions for structured content in the data store." },
@@ -925,6 +993,7 @@ const routes = [
925
993
  { path: "/interactions/:collection", Component: InteractionCollection },
926
994
  { path: "/interactions/:collection/:name", Component: InteractionDetail },
927
995
  { path: "/tools/:collection", Component: ToolCollection },
996
+ { path: "/activities/:collection", Component: ActivityCollection },
928
997
  { path: "/skills/:collection", Component: SkillCollection },
929
998
  { path: "/skills/:collection/:name", Component: SkillDetail },
930
999
  { path: "/types/:collection", Component: TypeCollection },
@@ -1 +1 @@
1
- {"version":3,"file":"tools-admin-ui.js","sources":["../src/AdminContext.ts","../src/components/AdminTopBar.tsx","../src/types.ts","../src/hooks.ts","../src/components/typeVariants.ts","../src/components/CollectionCard.tsx","../src/components/DetailPage.tsx","../src/components/EndpointPanel.tsx","../src/components/SummaryBadge.tsx","../src/components/HeroSection.tsx","../src/components/ResourceCard.tsx","../src/components/ResourceSection.tsx","../src/components/SearchBar.tsx","../src/pages/HomePage.tsx","../src/pages/InteractionCollection.tsx","../src/pages/InteractionDetail.tsx","../src/pages/SkillCollection.tsx","../src/pages/SkillDetail.tsx","../src/pages/TemplateCollection.tsx","../src/pages/TemplateDetail.tsx","../src/pages/ToolCollection.tsx","../src/pages/TypeCollection.tsx","../src/pages/TypeDetail.tsx","../src/AdminApp.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\nimport type { CollectionInfo, ResourceItem, ServerInfo } from './types.js';\n\nexport interface AdminContextValue {\n serverInfo: ServerInfo;\n collections: CollectionInfo[];\n resources: ResourceItem[];\n baseUrl: string;\n}\n\nexport const AdminContext = createContext<AdminContextValue | undefined>(undefined);\n\nexport function useAdminContext(): AdminContextValue {\n const ctx = useContext(AdminContext);\n if (!ctx) throw new Error('useAdminContext must be used within AdminApp');\n return ctx;\n}\n","import { Avatar, Button, ModeToggle } from '@vertesia/ui/core';\nimport { useUserSession } from '@vertesia/ui/session';\nimport { LogOut } from 'lucide-react';\n\ninterface AdminTopBarProps {\n title: string;\n}\n\nexport function AdminTopBar({ title }: AdminTopBarProps) {\n const { user, logout } = useUserSession();\n\n return (\n <header className=\"sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background px-6\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-8 items-center justify-center rounded-lg bg-primary text-xs font-semibold uppercase tracking-wider text-primary-foreground\">\n {title.split(/\\s+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('')}\n </div>\n <span className=\"text-sm font-semibold text-foreground\">{title}</span>\n </div>\n\n <div className=\"flex items-center gap-3\">\n <ModeToggle label={false} />\n {user && (\n <>\n <Avatar size=\"sm\" name={user.name} color=\"bg-primary\" />\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => logout()}\n alt=\"Sign out\"\n >\n <LogOut className=\"size-4\" />\n </Button>\n </>\n )}\n </div>\n </header>\n );\n}\n","/**\n * Types for the admin panel\n */\n\nimport type {\n AgentToolDefinition,\n CatalogInteractionRef,\n InCodeTypeDefinition,\n RenderingTemplateDefinitionRef,\n} from '@vertesia/common';\n\n/**\n * Server info from GET /api\n */\nexport interface ServerInfo {\n message: string;\n version: string;\n endpoints: {\n tools: string[];\n interactions: string[];\n templates: string[];\n mcp: string[];\n };\n}\n\nexport type ResourceType = 'tool' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';\n\n/**\n * A normalized resource entry for display and search.\n */\nexport interface ResourceItem {\n /** Unique identifier used for fetching details (e.g. \"collection:name\" for interactions). */\n id?: string;\n name: string;\n title: string;\n description: string;\n type: ResourceType;\n tags?: string[];\n url?: string;\n}\n\n/**\n * Metadata about a collection of resources, enriched with type and count client-side.\n */\nexport interface CollectionInfo {\n name: string;\n title: string;\n description: string;\n type: ResourceType;\n count: number;\n}\n\n/**\n * Collection metadata as returned by each API endpoint.\n */\ninterface CollectionMeta {\n name: string;\n title?: string;\n description?: string;\n}\n\n/**\n * Response shapes for each resource endpoint.\n */\ninterface InteractionsResponse {\n interactions: CatalogInteractionRef[];\n collections: CollectionMeta[];\n}\n\ninterface ToolsResponse {\n tools: AgentToolDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface SkillsResponse {\n tools: AgentToolDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface TypesResponse {\n types: InCodeTypeDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface TemplatesResponse {\n templates: RenderingTemplateDefinitionRef[];\n collections: CollectionMeta[];\n}\n\n/**\n * Combined result of processing all endpoint responses.\n */\nexport interface ResourceData {\n collections: CollectionInfo[];\n resources: ResourceItem[];\n}\n\n/**\n * Formats a kebab/snake-case name into a title.\n */\nfunction formatTitle(name: string): string {\n return name.replace(/[-_]/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase());\n}\n\n/**\n * Counts items per collection by matching each item to a collection name.\n * If there is only one collection, all items belong to it.\n */\nfunction countPerCollection<T>(\n items: T[],\n collections: CollectionMeta[],\n extractCollection: (item: T) => string | undefined,\n): Map<string, number> {\n const counts = new Map<string, number>();\n for (const col of collections) counts.set(col.name, 0);\n\n if (collections.length === 1) {\n counts.set(collections[0].name, items.length);\n return counts;\n }\n\n for (const item of items) {\n const colName = extractCollection(item);\n if (colName && counts.has(colName)) {\n counts.set(colName, (counts.get(colName) || 0) + 1);\n }\n }\n\n return counts;\n}\n\n/**\n * Builds collections and a flat resource list from the 5 endpoint responses + MCP endpoints.\n */\nexport function buildResourceData(\n interactionsResp: InteractionsResponse,\n toolsResp: ToolsResponse,\n skillsResp: SkillsResponse,\n typesResp: TypesResponse,\n templatesResp: TemplatesResponse,\n mcpEndpoints?: string[],\n): ResourceData {\n const collections: CollectionInfo[] = [];\n const resources: ResourceItem[] = [];\n\n // --- Interactions (id format: \"collection:name\") ---\n const interCounts = countPerCollection(\n interactionsResp.interactions,\n interactionsResp.collections,\n (i) => i.id.split(':')[0],\n );\n for (const col of interactionsResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'interaction',\n count: interCounts.get(col.name) || 0,\n });\n }\n for (const inter of interactionsResp.interactions) {\n resources.push({\n id: inter.id,\n name: inter.name,\n title: inter.title || formatTitle(inter.name),\n description: inter.description || '',\n type: 'interaction',\n tags: inter.tags,\n });\n }\n\n // --- Tools (url format: \"tools/{collection}\") ---\n const toolCounts = countPerCollection(\n toolsResp.tools,\n toolsResp.collections,\n (t) => t.url?.split('/').pop(),\n );\n for (const col of toolsResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'tool',\n count: toolCounts.get(col.name) || 0,\n });\n }\n for (const tool of toolsResp.tools) {\n resources.push({\n name: tool.name,\n title: formatTitle(tool.name),\n description: tool.description || '',\n type: 'tool',\n url: tool.url,\n });\n }\n\n // --- Skills (url format: \"skills/{collection}\") ---\n const skillCounts = countPerCollection(\n skillsResp.tools,\n skillsResp.collections,\n (t) => t.url?.split('/').pop(),\n );\n for (const col of skillsResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'skill',\n count: skillCounts.get(col.name) || 0,\n });\n }\n for (const skill of skillsResp.tools) {\n resources.push({\n name: skill.name,\n title: formatTitle(skill.name),\n description: skill.description || '',\n type: 'skill',\n url: skill.url,\n });\n }\n\n // --- Types (id format: \"collection:pathName\") ---\n const typeCounts = countPerCollection(\n typesResp.types,\n typesResp.collections,\n (t) => t.id?.split(':')[0],\n );\n for (const col of typesResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'type',\n count: typeCounts.get(col.name) || 0,\n });\n }\n for (const t of typesResp.types) {\n resources.push({\n name: t.name,\n title: formatTitle(t.name),\n description: t.description || '',\n type: 'type',\n tags: t.tags,\n });\n }\n\n // --- Templates (path format: \"/api/templates/{collection}/{name}\") ---\n const tmplCounts = countPerCollection(\n templatesResp.templates,\n templatesResp.collections,\n (t) => {\n const segments = t.path?.split('/');\n return segments && segments.length >= 4 ? segments[3] : undefined;\n },\n );\n for (const col of templatesResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'template',\n count: tmplCounts.get(col.name) || 0,\n });\n }\n for (const tmpl of templatesResp.templates) {\n resources.push({\n name: tmpl.name,\n title: tmpl.title || formatTitle(tmpl.name),\n description: tmpl.description || '',\n type: 'template',\n tags: tmpl.tags,\n url: tmpl.path,\n });\n }\n\n // --- MCP (derived from serverInfo, no endpoint) ---\n for (const endpoint of mcpEndpoints || []) {\n const name = endpoint.split('/').pop() || endpoint;\n resources.push({\n name,\n title: formatTitle(name),\n description: '',\n type: 'mcp',\n url: endpoint,\n });\n }\n\n return { collections, resources };\n}\n\n/**\n * Filters resources by a search query, matching against name, title, description, type, and tags.\n */\nexport function filterResources(items: ResourceItem[], query: string): ResourceItem[] {\n const q = query.toLowerCase().trim();\n if (!q) return items;\n return items.filter(item =>\n item.name.toLowerCase().includes(q) ||\n item.title.toLowerCase().includes(q) ||\n item.description.toLowerCase().includes(q) ||\n item.type.includes(q) ||\n item.tags?.some(t => t.toLowerCase().includes(q))\n );\n}\n","/**\n * Data fetching hooks for the admin panel.\n */\n\nimport { useFetch } from '@vertesia/ui/core';\n\nimport type { ResourceData, ServerInfo } from './types.js';\nimport { buildResourceData } from './types.js';\n\n/**\n * Fetches the tool server info (message, version, endpoints).\n */\nexport function useServerInfo(baseUrl: string) {\n return useFetch<ServerInfo>(() =>\n fetch(baseUrl).then(r => r.json()),\n [baseUrl]\n );\n}\n\n/**\n * Fetches all 5 resource endpoints in parallel and builds collections + flat resource list.\n * MCP endpoints are passed separately since they come from serverInfo.\n */\nexport function useResourceData(baseUrl: string, mcpEndpoints?: string[]) {\n return useFetch<ResourceData>(() => {\n const fetchJson = (path: string) => fetch(`${baseUrl}/${path}`).then(r => r.json());\n return Promise.all([\n fetchJson('interactions'),\n fetchJson('tools'),\n fetchJson('skills'),\n fetchJson('types'),\n fetchJson('templates'),\n ]).then(([interactions, tools, skills, types, templates]) =>\n buildResourceData(interactions, tools, skills, types, templates, mcpEndpoints)\n );\n }, [baseUrl, mcpEndpoints]);\n}\n","/** Tailwind class mappings for resource type badges. */\nexport const TYPE_VARIANTS: Record<string, string> = {\n tool: 'bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300',\n skill: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300',\n interaction: 'bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300',\n type: 'bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-300',\n template: 'bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300',\n mcp: 'bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300',\n};\n\n/** Tailwind class mappings for prompt role badges. */\nexport const ROLE_VARIANTS: Record<string, string> = {\n system: 'bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300',\n user: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300',\n assistant: 'bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300',\n safety: 'bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300',\n tool: 'bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300',\n};\n","import { Card, CardContent } from '@vertesia/ui/core';\nimport { NavLink } from '@vertesia/ui/router';\n\nimport type { CollectionInfo } from '../types.js';\nimport { TYPE_VARIANTS } from './typeVariants.js';\n\nexport function CollectionCard({ collection }: { collection: CollectionInfo }) {\n const href = `/${collection.type}s/${collection.name}`;\n\n return (\n <NavLink href={href} className=\"block no-underline\">\n <Card className=\"cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <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] ?? ''}`}>\n {collection.type}\n </span>\n <div className=\"font-semibold text-card-foreground\">{collection.title}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">\n {collection.description || 'No description'}\n </div>\n <div className=\"mt-2 font-mono text-xs text-muted-foreground\">\n {collection.count} {collection.count === 1 ? 'item' : 'items'}\n </div>\n </CardContent>\n </Card>\n </NavLink>\n );\n}\n","import { Badge } from '@vertesia/ui/core';\nimport { NavLink } from '@vertesia/ui/router';\nimport { ArrowLeft } from 'lucide-react';\nimport type { ReactNode } from 'react';\n\nimport type { ResourceType } from '../types.js';\nimport { TYPE_VARIANTS } from './typeVariants.js';\n\ninterface DetailPageProps {\n type: ResourceType;\n title: string;\n description?: string;\n tags?: string[];\n backHref?: string;\n children?: ReactNode;\n}\n\nexport function DetailPage({ type, title, description, tags, backHref = '/', children }: DetailPageProps) {\n return (\n <div className=\"mx-auto max-w-5xl px-7 py-10\">\n <nav className=\"mb-5 flex items-center gap-4\">\n {backHref !== '/' && (\n <NavLink href=\"/\" className=\"text-sm text-primary hover:opacity-75\">Home</NavLink>\n )}\n <NavLink href={backHref} className=\"flex items-center gap-1 text-sm text-primary hover:opacity-75\">\n <ArrowLeft className=\"size-3.5\" />\n Back\n </NavLink>\n </nav>\n\n <div className=\"mb-8\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[type] ?? ''}`}>\n {type}\n </span>\n <h1 className=\"-tracking-wide text-3xl font-bold text-foreground\">{title}</h1>\n {description && <p className=\"mt-1 text-sm leading-relaxed text-muted-foreground\">{description}</p>}\n {tags && tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n </div>\n\n {children}\n </div>\n );\n}\n","import { Button } from '@vertesia/ui/core';\nimport { Check, Copy } from 'lucide-react';\nimport { useState } from 'react';\n\nexport function EndpointPanel({ label, path }: { label: string; path: string }) {\n const [copied, setCopied] = useState(false);\n\n function handleCopy() {\n const url = window.location.origin + path;\n navigator.clipboard.writeText(url);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n }\n\n return (\n <div className=\"mb-3\">\n <div className=\"mb-1 text-[0.7rem] font-medium uppercase tracking-widest text-primary\">\n {label}\n </div>\n <div className=\"flex items-center gap-2 rounded-lg border border-border bg-muted-background px-3 py-2\">\n <code className=\"flex-1 font-mono text-sm text-foreground\">{path}</code>\n <Button\n variant=\"ghost\"\n size=\"xs\"\n onClick={handleCopy}\n aria-label=\"Copy full URL\"\n >\n {copied ? <Check className=\"size-3.5\" /> : <Copy className=\"size-3.5\" />}\n </Button>\n </div>\n </div>\n );\n}\n","import { DotBadge } from '@vertesia/ui/core';\n\nexport function SummaryBadge({ count, label }: { count: number; label: string }) {\n if (count === 0) return null;\n return (\n <DotBadge variant=\"success\">\n {count} {label}{count !== 1 ? 's' : ''}\n </DotBadge>\n );\n}\n","import { Card } from '@vertesia/ui/core';\nimport { Download, LayoutDashboard } from 'lucide-react';\n\nimport type { ResourceItem, ResourceType } from '../types.js';\nimport { EndpointPanel } from './EndpointPanel.js';\nimport { SummaryBadge } from './SummaryBadge.js';\n\ninterface HeroSectionProps {\n title: string;\n version: string;\n resources: ResourceItem[];\n}\n\nfunction getInitials(title: string): string {\n return title.split(/\\s+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('').toUpperCase();\n}\n\nfunction countByType(resources: ResourceItem[]): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const r of resources) {\n counts[r.type] = (counts[r.type] || 0) + 1;\n }\n return counts;\n}\n\nconst badgeLabels: { type: ResourceType; label: string }[] = [\n { type: 'tool', label: 'tool' },\n { type: 'skill', label: 'skill' },\n { type: 'interaction', label: 'interaction' },\n { type: 'type', label: 'content type' },\n { type: 'template', label: 'template' },\n { type: 'mcp', label: 'MCP provider' },\n];\n\nexport function HeroSection({ title, version, resources }: HeroSectionProps) {\n const counts = countByType(resources);\n\n return (\n <Card className=\"mb-10 overflow-hidden border bg-linear-to-br from-card to-muted-background\">\n <div className=\"flex flex-col gap-6 p-6 md:flex-row md:items-start md:justify-between\">\n <div className=\"flex flex-1 flex-col gap-3\">\n <div className=\"flex items-center gap-4\">\n <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\">\n {getInitials(title)}\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase tracking-widest text-muted-foreground\">Tools Server</p>\n <h1 className=\"-tracking-wide text-2xl font-bold text-foreground\">{title}</h1>\n </div>\n </div>\n\n <p className=\"text-sm text-muted-foreground\">\n Discover the tools, skills, interactions, and content types exposed by this server.\n </p>\n\n <div className=\"flex flex-wrap gap-2\">\n {badgeLabels.map(({ type, label }) => (\n <SummaryBadge key={type} count={counts[type] || 0} label={label} />\n ))}\n </div>\n\n <div className=\"flex flex-wrap gap-3 pt-1\">\n <a\n href=\"/app/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n 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\"\n >\n <LayoutDashboard className=\"size-4\" />\n UI Plugin Dev\n </a>\n <a\n href=\"/lib/plugin.js\"\n 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\"\n >\n <Download className=\"size-4\" />\n Plugin Bundle\n </a>\n </div>\n </div>\n\n <aside className=\"min-w-55 max-w-65 shrink-0\">\n <EndpointPanel label=\"Base endpoint\" path=\"/api\" />\n <EndpointPanel label=\"Package endpoint\" path=\"/api/package\" />\n <p className=\"mt-2 text-xs leading-relaxed text-muted-foreground\">\n Use <strong className=\"text-foreground\">POST /api/tools/&lt;collection&gt;</strong> or{' '}\n <strong className=\"text-foreground\">POST /api/skills/&lt;collection&gt;</strong> to call these from your apps or agents.\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">v{version}</p>\n </aside>\n </div>\n </Card>\n );\n}\n","import { Badge, Card, CardContent } from '@vertesia/ui/core';\n\nimport type { ResourceItem } from '../types.js';\nimport { TYPE_VARIANTS } from './typeVariants.js';\n\nexport function ResourceCard({ resource }: { resource: ResourceItem }) {\n return (\n <Card className=\"transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <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] ?? ''}`}>\n {resource.type}\n </span>\n <div className=\"font-semibold text-card-foreground\">{resource.title}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">\n {resource.description || 'No description'}\n </div>\n {resource.tags && resource.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {resource.tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n {resource.url && (\n <div className=\"mt-2 truncate font-mono text-xs text-muted-foreground\">{resource.url}</div>\n )}\n </CardContent>\n </Card>\n );\n}\n","import { Separator } from '@vertesia/ui/core';\n\nimport type { ResourceItem } from '../types.js';\nimport { ResourceCard } from './ResourceCard.js';\n\ninterface ResourceSectionProps {\n title: string;\n subtitle: string;\n resources: ResourceItem[];\n showDivider?: boolean;\n}\n\nexport function ResourceSection({ title, subtitle, resources, showDivider }: ResourceSectionProps) {\n if (resources.length === 0) return null;\n\n return (\n <section>\n {showDivider && <Separator className=\"my-8\" />}\n <div>\n <h2 className=\"text-xl font-semibold text-foreground\">\n {title}\n <span className=\"ml-2 text-sm font-normal text-muted-foreground\">({resources.length})</span>\n </h2>\n <p className=\"mb-4 text-sm text-muted-foreground\">{subtitle}</p>\n </div>\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {resources.map(r => (\n <ResourceCard key={`${r.type}:${r.name}`} resource={r} />\n ))}\n </div>\n </section>\n );\n}\n","import { Input } from '@vertesia/ui/core';\n\ninterface SearchBarProps {\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n resultCount?: number;\n totalCount?: number;\n}\n\nexport function SearchBar({ value, onChange, placeholder, resultCount, totalCount }: SearchBarProps) {\n const hasQuery = value.trim().length > 0;\n const noResults = hasQuery && resultCount === 0;\n\n return (\n <div className=\"mb-7\">\n <Input\n type=\"search\"\n value={value}\n onChange={onChange}\n placeholder={placeholder || 'Search collections...'}\n className=\"max-w-sm rounded-full\"\n autoComplete=\"off\"\n />\n {hasQuery && !noResults && (\n <p className=\"mt-1.5 text-xs text-muted-foreground\">\n Showing {resultCount} of {totalCount} resources\n </p>\n )}\n {noResults && (\n <p className=\"mt-2 text-sm text-destructive\">\n No resources match this search.\n </p>\n )}\n </div>\n );\n}\n","import { Separator } from '@vertesia/ui/core';\nimport { useMemo, useState } from 'react';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { CollectionCard, HeroSection, ResourceSection, SearchBar } from '../components/index.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\nimport type { ResourceType } from '../types.js';\nimport { filterResources } from '../types.js';\n\nconst sections: { type: ResourceType; title: string; subtitle: string }[] = [\n { type: 'tool', title: 'Tools', subtitle: 'Remote tools available to agents via Vertesia.' },\n { type: 'skill', title: 'Skills', subtitle: 'Reusable instructions and scripts packaged as tools.' },\n { type: 'interaction', title: 'Interactions', subtitle: 'Conversation blueprints surfaced in the Vertesia UI.' },\n { type: 'type', title: 'Content Types', subtitle: 'Schema definitions for structured content in the data store.' },\n { type: 'template', title: 'Rendering Templates', subtitle: 'Document and presentation templates for content generation.' },\n { type: 'mcp', title: 'MCP Providers', subtitle: 'Remote MCP servers available through this tools server.' },\n];\n\nexport function HomePage() {\n const { serverInfo, collections, resources } = useAdminContext();\n const [search, setSearch] = useState('');\n\n const filtered = useMemo(() =>\n filterResources(resources, search),\n [resources, search]\n );\n\n const isSearching = search.trim().length > 0;\n\n return (\n <div className=\"mx-auto max-w-5xl px-7 py-10\">\n <HeroSection\n title={serverInfo.message.replace('Vertesia Tools API', 'Tools Server')}\n version={serverInfo.version}\n resources={resources}\n />\n\n <SearchBar\n value={search}\n onChange={setSearch}\n placeholder=\"Search tools, skills, interactions, types, templates...\"\n resultCount={filtered.length}\n totalCount={resources.length}\n />\n\n {isSearching ? (\n sections.map((section, i) => {\n const sectionItems = filtered.filter(r => r.type === section.type);\n return (\n <ResourceSection\n key={section.type}\n title={section.title}\n subtitle={section.subtitle}\n resources={sectionItems}\n showDivider={i > 0}\n />\n );\n })\n ) : (\n sections.map((section, i) => {\n const sectionCollections = collections.filter(c => c.type === section.type);\n const mcpResources = section.type === 'mcp'\n ? resources.filter(r => r.type === 'mcp')\n : [];\n\n if (sectionCollections.length === 0 && mcpResources.length === 0) return null;\n\n return (\n <section key={section.type}>\n {i > 0 && <Separator className=\"my-8\" />}\n <div>\n <h2 className=\"text-xl font-semibold text-foreground\">\n {section.title}\n <span className=\"ml-2 text-sm font-normal text-muted-foreground\">\n ({sectionCollections.length}{sectionCollections.length === 1\n ? ' collection' : ' collections'})\n </span>\n </h2>\n <p className=\"mb-4 text-sm text-muted-foreground\">{section.subtitle}</p>\n </div>\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {sectionCollections.map(col => (\n <CollectionCard key={`${col.type}:${col.name}`} collection={col} />\n ))}\n {mcpResources.map(r => (\n <div key={r.name} className=\"rounded-xl border border-border bg-card p-5 shadow-sm\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.mcp}`}>\n mcp\n </span>\n <div className=\"font-semibold text-card-foreground\">{r.title}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{r.description || 'No description'}</div>\n {r.url && <div className=\"mt-2 truncate font-mono text-xs text-muted-foreground\">{r.url}</div>}\n </div>\n ))}\n </div>\n </section>\n );\n })\n )}\n </div>\n );\n}\n","import type { CatalogInteractionRef } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\nexport function InteractionCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data: interactions, error } = useFetch<CatalogInteractionRef[]>(\n () => fetch(`${baseUrl}/interactions/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load collection &ldquo;{collection}&rdquo;.</div>;\n }\n\n if (!interactions) {\n return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n }\n\n return (\n <DetailPage\n type=\"interaction\"\n title={collection}\n description={`${interactions.length} interaction${interactions.length !== 1 ? 's' : ''} in this collection.`}\n >\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {interactions.map(inter => (\n <NavLink key={inter.id} href={`/interactions/${collection}/${inter.name}`} className=\"block no-underline\">\n <Card className=\"cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.interaction}`}>\n interaction\n </span>\n <div className=\"font-semibold text-card-foreground\">{inter.title || inter.name}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{inter.description || 'No description'}</div>\n {inter.tags && inter.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {inter.tags.map(tag => <Badge key={tag}>{tag}</Badge>)}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n ))}\n </div>\n </DetailPage>\n );\n}\n","import type { InteractionSpec } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\nimport { useUserSession } from '@vertesia/ui/session';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { ROLE_VARIANTS } from '../components/typeVariants.js';\n\ntype InteractionResponse = InteractionSpec & { id: string };\n\nexport function InteractionDetail() {\n const { client } = useUserSession();\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: interaction, error } = useFetch<InteractionResponse>(\n () => client.getRawJWT().then(token => fetch(`${baseUrl}/interactions/${collection}/${name}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n })).then(r => {\n if (!r.ok) throw new Error(`Failed to load interaction: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load interaction &ldquo;{name}&rdquo;.</div>;\n }\n\n if (!interaction) {\n return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n }\n\n const { agent_runner_options } = interaction;\n const hasAgentFlags = agent_runner_options &&\n (agent_runner_options.is_agent || agent_runner_options.is_tool || agent_runner_options.is_skill);\n\n return (\n <DetailPage\n type=\"interaction\"\n title={interaction.title || interaction.name}\n description={interaction.description}\n tags={interaction.tags}\n backHref={`/interactions/${collection}`}\n >\n {interaction.prompts && interaction.prompts.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Prompts</h2>\n {interaction.prompts.map((prompt) => (\n <Card key={`${prompt.role}-${prompt.name ?? ''}`} className=\"mb-3\">\n <CardContent className=\"p-4\">\n <div className=\"mb-2 flex items-center gap-2\">\n <span className={`rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${ROLE_VARIANTS[prompt.role] ?? ''}`}>\n {prompt.role}\n </span>\n {prompt.name && (\n <span className=\"text-sm italic text-muted-foreground\">{prompt.name}</span>\n )}\n </div>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">{prompt.content}</pre>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {interaction.result_schema && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Result Schema</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(interaction.result_schema, null, 2)}\n </pre>\n </div>\n )}\n\n {hasAgentFlags && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Agent Runner</h2>\n <div className=\"flex flex-wrap gap-2\">\n {agent_runner_options.is_agent && <Badge variant=\"success\">Agent</Badge>}\n {agent_runner_options.is_tool && <Badge variant=\"success\">Tool</Badge>}\n {agent_runner_options.is_skill && <Badge variant=\"success\">Skill</Badge>}\n </div>\n </div>\n )}\n </DetailPage>\n );\n}\n","import { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\nimport { useMemo } from 'react';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\ninterface SkillToolDef {\n name: string;\n description?: string;\n related_tools?: string[];\n}\n\ninterface SkillCollectionResponse {\n title: string;\n description: string;\n tools: SkillToolDef[];\n}\n\ninterface WidgetInfo {\n skill: string;\n collection: string;\n url: string;\n}\n\ninterface WidgetsResponse {\n widgets: Record<string, WidgetInfo>;\n}\n\n/** Strip the learn_ prefix added by the SDK when exposing skills as tools. */\nfunction skillDisplayName(name: string): string {\n return name.startsWith('learn_') ? name.slice(6) : name;\n}\n\nexport function SkillCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data, error } = useFetch<SkillCollectionResponse>(\n () => fetch(`${baseUrl}/skills/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n const { data: widgetsData } = useFetch<WidgetsResponse>(\n () => fetch(`${baseUrl}/package?scope=widgets`).then(r => r.ok ? r.json() : { widgets: {} }),\n [baseUrl]\n );\n\n const collectionWidgets = useMemo(() => {\n if (!widgetsData?.widgets) return [];\n return Object.entries(widgetsData.widgets)\n .filter(([_, w]) => w.collection === collection)\n .map(([name, w]) => ({ name, ...w }));\n }, [widgetsData, collection]);\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load skill collection &ldquo;{collection}&rdquo;.</div>;\n if (!data) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"skill\"\n title={data.title || collection}\n description={data.description || `${data.tools.length} skill${data.tools.length !== 1 ? 's' : ''} in this collection.`}\n >\n {collectionWidgets.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Widgets</h2>\n <div className=\"flex flex-wrap gap-2\">\n {collectionWidgets.map(w => (\n <Badge key={w.name} variant=\"success\">\n {w.name}\n <span className=\"ml-2 font-mono text-xs opacity-70\">(skill: {w.skill})</span>\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {data.tools.map(skill => {\n const displayName = skillDisplayName(skill.name);\n return (\n <NavLink key={skill.name} href={`/skills/${collection}/${displayName}`} className=\"block no-underline\">\n <Card className=\"cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.skill}`}>\n skill\n </span>\n <div className=\"font-semibold text-card-foreground\">{displayName}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{skill.description || 'No description'}</div>\n {skill.related_tools && skill.related_tools.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {skill.related_tools.map(t => <Badge key={t}>{t}</Badge>)}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n );\n })}\n </div>\n </DetailPage>\n );\n}\n","import { Badge, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\n\ninterface SkillDefinitionResponse {\n name: string;\n title?: string;\n description: string;\n instructions: string;\n content_type: 'md' | 'jst';\n input_schema?: Record<string, unknown>;\n related_tools?: string[];\n execution?: {\n language: string;\n packages?: string[];\n };\n scripts?: string[];\n widgets?: string[];\n}\n\nexport function SkillDetail() {\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: skill, error } = useFetch<SkillDefinitionResponse>(\n () => fetch(`${baseUrl}/skills/${collection}/${name}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load skill: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load skill &ldquo;{name}&rdquo;.</div>;\n if (!skill) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"skill\"\n title={skill.title || skill.name}\n description={skill.description}\n backHref={`/skills/${collection}`}\n >\n {skill.widgets && skill.widgets.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Widgets</h2>\n <div className=\"flex flex-wrap gap-2\">\n {skill.widgets.map(w => <Badge key={w} variant=\"success\">{w}</Badge>)}\n </div>\n </div>\n )}\n\n {skill.scripts && skill.scripts.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Scripts</h2>\n <div className=\"flex flex-wrap gap-2\">\n {skill.scripts.map(s => <Badge key={s} variant=\"success\">{s}</Badge>)}\n </div>\n </div>\n )}\n\n {skill.related_tools && skill.related_tools.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Related Tools</h2>\n <div className=\"flex flex-wrap gap-2\">\n {skill.related_tools.map(t => <Badge key={t} variant=\"success\">{t}</Badge>)}\n </div>\n </div>\n )}\n\n {skill.execution && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Execution</h2>\n <div className=\"flex flex-wrap gap-2\">\n <Badge variant=\"success\">{skill.execution.language}</Badge>\n {skill.execution.packages?.map(p => <Badge key={p} variant=\"success\">{p}</Badge>)}\n </div>\n </div>\n )}\n\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">\n Instructions\n {skill.content_type === 'jst' && <Badge className=\"ml-2\">JST template</Badge>}\n </h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">{skill.instructions}</pre>\n </div>\n\n {skill.input_schema && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Input Schema</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(skill.input_schema, null, 2)}\n </pre>\n </div>\n )}\n </DetailPage>\n );\n}\n","import type { RenderingTemplateDefinitionRef } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\nexport function TemplateCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data: templates, error } = useFetch<RenderingTemplateDefinitionRef[]>(\n () => fetch(`${baseUrl}/templates/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load template collection &ldquo;{collection}&rdquo;.</div>;\n if (!templates) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"template\"\n title={collection}\n description={`${templates.length} template${templates.length !== 1 ? 's' : ''} in this collection.`}\n >\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {templates.map(tmpl => (\n <NavLink\n key={tmpl.name}\n href={`/templates/${collection}/${tmpl.name}`}\n className=\"no-underline\"\n >\n <Card className=\"h-full transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.template}`}>\n {tmpl.type || 'template'}\n </span>\n <div className=\"font-semibold text-card-foreground\">{tmpl.title || tmpl.name}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{tmpl.description || 'No description'}</div>\n {tmpl.tags && tmpl.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {tmpl.tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n ))}\n </div>\n </DetailPage>\n );\n}\n","import { Badge, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\n\ninterface TemplateDefinitionResponse {\n name: string;\n title?: string;\n description: string;\n type: 'presentation' | 'document';\n tags?: string[];\n assets: string[];\n instructions: string;\n}\n\nexport function TemplateDetail() {\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: template, error } = useFetch<TemplateDefinitionResponse>(\n () => fetch(`${baseUrl}/templates/${collection}/${name}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load template: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load template &ldquo;{name}&rdquo;.</div>;\n if (!template) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"template\"\n title={template.title || template.name}\n description={template.description}\n tags={template.tags}\n backHref={`/templates/${collection}`}\n >\n <div className=\"mb-8\">\n <div className=\"flex flex-wrap gap-2\">\n <Badge variant=\"success\">{template.type}</Badge>\n </div>\n </div>\n\n {template.assets && template.assets.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Assets</h2>\n <div className=\"flex flex-wrap gap-2\">\n {template.assets.map(asset => (\n <Badge key={asset} variant=\"success\">\n {asset.split('/').pop()}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Instructions</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {template.instructions}\n </pre>\n </div>\n </DetailPage>\n );\n}\n","import { Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\ninterface ToolDef {\n name: string;\n description?: string;\n input_schema?: Record<string, unknown>;\n}\n\ninterface ToolCollectionResponse {\n title: string;\n description: string;\n tools: ToolDef[];\n}\n\nexport function ToolCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data, error } = useFetch<ToolCollectionResponse>(\n () => fetch(`${baseUrl}/tools/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load tool collection &ldquo;{collection}&rdquo;.</div>;\n if (!data) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"tool\"\n title={data.title || collection}\n description={data.description || `${data.tools.length} tool${data.tools.length !== 1 ? 's' : ''} in this collection.`}\n >\n {data.tools.map(tool => (\n <Card key={tool.name} className=\"mb-4\">\n <CardContent className=\"p-5\">\n <div className=\"mb-2 flex items-center gap-2\">\n <span className={`inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.tool}`}>\n tool\n </span>\n <span className=\"font-semibold text-card-foreground\">{tool.name}</span>\n </div>\n <div className=\"text-sm text-muted-foreground\">{tool.description || 'No description'}</div>\n {tool.input_schema && (\n <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\">\n {JSON.stringify(tool.input_schema, null, 2)}\n </pre>\n )}\n </CardContent>\n </Card>\n ))}\n </DetailPage>\n );\n}\n","import type { InCodeTypeDefinition } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\nexport function TypeCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data: types, error } = useFetch<InCodeTypeDefinition[]>(\n () => fetch(`${baseUrl}/types/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load type collection &ldquo;{collection}&rdquo;.</div>;\n if (!types) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"type\"\n title={collection}\n description={`${types.length} content type${types.length !== 1 ? 's' : ''} in this collection.`}\n >\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {types.map(t => {\n const typeName = t.id?.split(':')[1] || t.name;\n return (\n <NavLink\n key={t.name}\n href={`/types/${collection}/${typeName}`}\n className=\"no-underline\"\n >\n <Card className=\"h-full transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.type}`}>\n type\n </span>\n <div className=\"font-semibold text-card-foreground\">{t.name}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{t.description || 'No description'}</div>\n {t.tags && t.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {t.tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n {(t.is_chunkable || t.strict_mode) && (\n <div className=\"mt-2 truncate font-mono text-xs text-muted-foreground\">\n {t.is_chunkable && 'chunkable'}\n {t.is_chunkable && t.strict_mode && ' · '}\n {t.strict_mode && 'strict'}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n );\n })}\n </div>\n </DetailPage>\n );\n}\n","import type { InCodeTypeDefinition } from '@vertesia/common';\nimport { Badge, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\n\nexport function TypeDetail() {\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: typeDef, error } = useFetch<InCodeTypeDefinition>(\n () => fetch(`${baseUrl}/types/${collection}/${name}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load type: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load type &ldquo;{name}&rdquo;.</div>;\n if (!typeDef) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"type\"\n title={typeDef.name}\n description={typeDef.description}\n tags={typeDef.tags}\n backHref={`/types/${collection}`}\n >\n {(typeDef.is_chunkable || typeDef.strict_mode) && (\n <div className=\"mb-8\">\n <div className=\"flex flex-wrap gap-2\">\n {typeDef.is_chunkable && <Badge variant=\"success\">Chunkable</Badge>}\n {typeDef.strict_mode && <Badge variant=\"success\">Strict Mode</Badge>}\n </div>\n </div>\n )}\n\n {typeDef.object_schema && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Object Schema</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(typeDef.object_schema, null, 2)}\n </pre>\n </div>\n )}\n\n {typeDef.table_layout && typeDef.table_layout.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Table Layout</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(typeDef.table_layout, null, 2)}\n </pre>\n </div>\n )}\n </DetailPage>\n );\n}\n","import { Spinner } from '@vertesia/ui/core';\nimport type { Route } from '@vertesia/ui/router';\nimport { NestedRouterProvider, RouteComponent } from '@vertesia/ui/router';\n\nimport { AdminContext } from './AdminContext.js';\nimport { AdminTopBar } from './components/AdminTopBar.js';\nimport { useResourceData, useServerInfo } from './hooks.js';\nimport { HomePage } from './pages/HomePage.js';\nimport { InteractionCollection } from './pages/InteractionCollection.js';\nimport { InteractionDetail } from './pages/InteractionDetail.js';\nimport { SkillCollection } from './pages/SkillCollection.js';\nimport { SkillDetail } from './pages/SkillDetail.js';\nimport { TemplateCollection } from './pages/TemplateCollection.js';\nimport { TemplateDetail } from './pages/TemplateDetail.js';\nimport { ToolCollection } from './pages/ToolCollection.js';\nimport { TypeCollection } from './pages/TypeCollection.js';\nimport { TypeDetail } from './pages/TypeDetail.js';\n\nconst routes: Route[] = [\n { path: '/', Component: HomePage },\n { path: '/interactions/:collection', Component: InteractionCollection },\n { path: '/interactions/:collection/:name', Component: InteractionDetail },\n { path: '/tools/:collection', Component: ToolCollection },\n { path: '/skills/:collection', Component: SkillCollection },\n { path: '/skills/:collection/:name', Component: SkillDetail },\n { path: '/types/:collection', Component: TypeCollection },\n { path: '/types/:collection/:name', Component: TypeDetail },\n { path: '/templates/:collection', Component: TemplateCollection },\n { path: '/templates/:collection/:name', Component: TemplateDetail },\n];\n\nexport interface AdminAppProps {\n /**\n * Base URL for the tool server API.\n * @default '/api'\n */\n baseUrl?: string;\n}\n\n/**\n * Admin app shell — loads data, provides context, and renders nested routes.\n *\n * Requires a parent VertesiaShell (or equivalent providers for ThemeProvider,\n * UserSessionProvider, ToastProvider).\n */\nexport function AdminApp({ baseUrl = '/api' }: AdminAppProps) {\n const { data: serverInfo, isLoading: loadingInfo, error: infoError } = useServerInfo(baseUrl);\n const { data: resourceData, isLoading: loadingData, error: dataError } = useResourceData(\n baseUrl,\n serverInfo?.endpoints.mcp,\n );\n\n const isLoading = loadingInfo || loadingData;\n const error = infoError || dataError;\n\n if (isLoading) {\n return (\n <div className=\"flex h-64 items-center justify-center text-muted-foreground\">\n <Spinner />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"p-6 text-destructive\">\n Failed to load server info. Is the API running?\n </div>\n );\n }\n\n if (!serverInfo || !resourceData) return null;\n\n const title = serverInfo.message.replace('Vertesia Tools API', 'Tools Server');\n\n return (\n <div className=\"min-h-screen bg-background text-foreground\">\n <AdminTopBar title={title} />\n <AdminContext.Provider value={{\n serverInfo,\n collections: resourceData.collections,\n resources: resourceData.resources,\n baseUrl,\n }}>\n <NestedRouterProvider routes={routes}>\n <RouteComponent />\n </NestedRouterProvider>\n </AdminContext.Provider>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools-admin-ui.js","sources":["../src/AdminContext.ts","../src/components/AdminTopBar.tsx","../src/types.ts","../src/hooks.ts","../src/components/typeVariants.ts","../src/components/DetailPage.tsx","../src/pages/ActivityCollection.tsx","../src/components/CollectionCard.tsx","../src/components/EndpointPanel.tsx","../src/components/SummaryBadge.tsx","../src/components/HeroSection.tsx","../src/components/ResourceCard.tsx","../src/components/ResourceSection.tsx","../src/components/SearchBar.tsx","../src/pages/HomePage.tsx","../src/pages/InteractionCollection.tsx","../src/pages/InteractionDetail.tsx","../src/pages/SkillCollection.tsx","../src/pages/SkillDetail.tsx","../src/pages/TemplateCollection.tsx","../src/pages/TemplateDetail.tsx","../src/pages/ToolCollection.tsx","../src/pages/TypeCollection.tsx","../src/pages/TypeDetail.tsx","../src/AdminApp.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\nimport type { CollectionInfo, ResourceItem, ServerInfo } from './types.js';\n\nexport interface AdminContextValue {\n serverInfo: ServerInfo;\n collections: CollectionInfo[];\n resources: ResourceItem[];\n baseUrl: string;\n}\n\nexport const AdminContext = createContext<AdminContextValue | undefined>(undefined);\n\nexport function useAdminContext(): AdminContextValue {\n const ctx = useContext(AdminContext);\n if (!ctx) throw new Error('useAdminContext must be used within AdminApp');\n return ctx;\n}\n","import { Avatar, Button, ModeToggle } from '@vertesia/ui/core';\nimport { useUserSession } from '@vertesia/ui/session';\nimport { LogOut } from 'lucide-react';\n\ninterface AdminTopBarProps {\n title: string;\n}\n\nexport function AdminTopBar({ title }: AdminTopBarProps) {\n const { user, logout } = useUserSession();\n\n return (\n <header className=\"sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background px-6\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-8 items-center justify-center rounded-lg bg-primary text-xs font-semibold uppercase tracking-wider text-primary-foreground\">\n {title.split(/\\s+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('')}\n </div>\n <span className=\"text-sm font-semibold text-foreground\">{title}</span>\n </div>\n\n <div className=\"flex items-center gap-3\">\n <ModeToggle label={false} />\n {user && (\n <>\n <Avatar size=\"sm\" name={user.name} color=\"bg-primary\" />\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => logout()}\n alt=\"Sign out\"\n >\n <LogOut className=\"size-4\" />\n </Button>\n </>\n )}\n </div>\n </header>\n );\n}\n","/**\n * Types for the admin panel\n */\n\nimport type {\n AgentToolDefinition,\n CatalogInteractionRef,\n InCodeTypeDefinition,\n RemoteActivityDefinition,\n RenderingTemplateDefinitionRef,\n} from '@vertesia/common';\n\n/**\n * Server info from GET /api\n */\nexport interface ServerInfo {\n message: string;\n version: string;\n endpoints: {\n tools: string[];\n interactions: string[];\n activities: string[];\n templates: string[];\n mcp: string[];\n };\n}\n\nexport type ResourceType = 'tool' | 'activity' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';\n\n/**\n * A normalized resource entry for display and search.\n */\nexport interface ResourceItem {\n /** Unique identifier used for fetching details (e.g. \"collection:name\" for interactions). */\n id?: string;\n name: string;\n title: string;\n description: string;\n type: ResourceType;\n tags?: string[];\n url?: string;\n}\n\n/**\n * Metadata about a collection of resources, enriched with type and count client-side.\n */\nexport interface CollectionInfo {\n name: string;\n title: string;\n description: string;\n type: ResourceType;\n count: number;\n}\n\n/**\n * Collection metadata as returned by each API endpoint.\n */\ninterface CollectionMeta {\n name: string;\n title?: string;\n description?: string;\n}\n\n/**\n * Response shapes for each resource endpoint.\n */\ninterface InteractionsResponse {\n interactions: CatalogInteractionRef[];\n collections: CollectionMeta[];\n}\n\ninterface ToolsResponse {\n tools: AgentToolDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface SkillsResponse {\n tools: AgentToolDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface TypesResponse {\n types: InCodeTypeDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface ActivitiesResponse {\n activities: RemoteActivityDefinition[];\n collections: CollectionMeta[];\n}\n\ninterface TemplatesResponse {\n templates: RenderingTemplateDefinitionRef[];\n collections: CollectionMeta[];\n}\n\n/**\n * Combined result of processing all endpoint responses.\n */\nexport interface ResourceData {\n collections: CollectionInfo[];\n resources: ResourceItem[];\n}\n\n/**\n * Formats a kebab/snake-case name into a title.\n */\nfunction formatTitle(name: string): string {\n return name.replace(/[-_]/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase());\n}\n\n/**\n * Counts items per collection by matching each item to a collection name.\n * If there is only one collection, all items belong to it.\n */\nfunction countPerCollection<T>(\n items: T[],\n collections: CollectionMeta[],\n extractCollection: (item: T) => string | undefined,\n): Map<string, number> {\n const counts = new Map<string, number>();\n for (const col of collections) counts.set(col.name, 0);\n\n if (collections.length === 1) {\n counts.set(collections[0].name, items.length);\n return counts;\n }\n\n for (const item of items) {\n const colName = extractCollection(item);\n if (colName && counts.has(colName)) {\n counts.set(colName, (counts.get(colName) || 0) + 1);\n }\n }\n\n return counts;\n}\n\n/**\n * Builds collections and a flat resource list from the 5 endpoint responses + MCP endpoints.\n */\nexport function buildResourceData(\n interactionsResp: InteractionsResponse,\n toolsResp: ToolsResponse,\n skillsResp: SkillsResponse,\n activitiesResp: ActivitiesResponse,\n typesResp: TypesResponse,\n templatesResp: TemplatesResponse,\n mcpEndpoints?: string[],\n): ResourceData {\n const collections: CollectionInfo[] = [];\n const resources: ResourceItem[] = [];\n\n // --- Interactions (id format: \"collection:name\") ---\n const interCounts = countPerCollection(\n interactionsResp.interactions,\n interactionsResp.collections,\n (i) => i.id.split(':')[0],\n );\n for (const col of interactionsResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'interaction',\n count: interCounts.get(col.name) || 0,\n });\n }\n for (const inter of interactionsResp.interactions) {\n resources.push({\n id: inter.id,\n name: inter.name,\n title: inter.title || formatTitle(inter.name),\n description: inter.description || '',\n type: 'interaction',\n tags: inter.tags,\n });\n }\n\n // --- Tools (url format: \"tools/{collection}\") ---\n const toolCounts = countPerCollection(\n toolsResp.tools,\n toolsResp.collections,\n (t) => t.url?.split('/').pop(),\n );\n for (const col of toolsResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'tool',\n count: toolCounts.get(col.name) || 0,\n });\n }\n for (const tool of toolsResp.tools) {\n resources.push({\n name: tool.name,\n title: formatTitle(tool.name),\n description: tool.description || '',\n type: 'tool',\n url: tool.url,\n });\n }\n\n // --- Skills (url format: \"skills/{collection}\") ---\n const skillCounts = countPerCollection(\n skillsResp.tools,\n skillsResp.collections,\n (t) => t.url?.split('/').pop(),\n );\n for (const col of skillsResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'skill',\n count: skillCounts.get(col.name) || 0,\n });\n }\n for (const skill of skillsResp.tools) {\n resources.push({\n name: skill.name,\n title: formatTitle(skill.name),\n description: skill.description || '',\n type: 'skill',\n url: skill.url,\n });\n }\n\n // --- Activities (use collection field from definition) ---\n const actCounts = countPerCollection(\n activitiesResp.activities,\n activitiesResp.collections,\n (a) => a.collection,\n );\n for (const col of activitiesResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'activity',\n count: actCounts.get(col.name) || 0,\n });\n }\n for (const act of activitiesResp.activities) {\n resources.push({\n name: act.name,\n title: act.title || formatTitle(act.name),\n description: act.description || '',\n type: 'activity',\n url: act.url,\n });\n }\n\n // --- Types (id format: \"collection:pathName\") ---\n const typeCounts = countPerCollection(\n typesResp.types,\n typesResp.collections,\n (t) => t.id?.split(':')[0],\n );\n for (const col of typesResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'type',\n count: typeCounts.get(col.name) || 0,\n });\n }\n for (const t of typesResp.types) {\n resources.push({\n name: t.name,\n title: formatTitle(t.name),\n description: t.description || '',\n type: 'type',\n tags: t.tags,\n });\n }\n\n // --- Templates (path format: \"/api/templates/{collection}/{name}\") ---\n const tmplCounts = countPerCollection(\n templatesResp.templates,\n templatesResp.collections,\n (t) => {\n const segments = t.path?.split('/');\n return segments && segments.length >= 4 ? segments[3] : undefined;\n },\n );\n for (const col of templatesResp.collections) {\n collections.push({\n name: col.name,\n title: col.title || formatTitle(col.name),\n description: col.description || '',\n type: 'template',\n count: tmplCounts.get(col.name) || 0,\n });\n }\n for (const tmpl of templatesResp.templates) {\n resources.push({\n name: tmpl.name,\n title: tmpl.title || formatTitle(tmpl.name),\n description: tmpl.description || '',\n type: 'template',\n tags: tmpl.tags,\n url: tmpl.path,\n });\n }\n\n // --- MCP (derived from serverInfo, no endpoint) ---\n for (const endpoint of mcpEndpoints || []) {\n const name = endpoint.split('/').pop() || endpoint;\n resources.push({\n name,\n title: formatTitle(name),\n description: '',\n type: 'mcp',\n url: endpoint,\n });\n }\n\n return { collections, resources };\n}\n\n/**\n * Filters resources by a search query, matching against name, title, description, type, and tags.\n */\nexport function filterResources(items: ResourceItem[], query: string): ResourceItem[] {\n const q = query.toLowerCase().trim();\n if (!q) return items;\n return items.filter(item =>\n item.name.toLowerCase().includes(q) ||\n item.title.toLowerCase().includes(q) ||\n item.description.toLowerCase().includes(q) ||\n item.type.includes(q) ||\n item.tags?.some(t => t.toLowerCase().includes(q))\n );\n}\n","/**\n * Data fetching hooks for the admin panel.\n */\n\nimport { useFetch } from '@vertesia/ui/core';\n\nimport type { ResourceData, ServerInfo } from './types.js';\nimport { buildResourceData } from './types.js';\n\n/**\n * Fetches the tool server info (message, version, endpoints).\n */\nexport function useServerInfo(baseUrl: string) {\n return useFetch<ServerInfo>(() =>\n fetch(baseUrl).then(r => r.json()),\n [baseUrl]\n );\n}\n\n/**\n * Fetches all 5 resource endpoints in parallel and builds collections + flat resource list.\n * MCP endpoints are passed separately since they come from serverInfo.\n */\nexport function useResourceData(baseUrl: string, mcpEndpoints?: string[]) {\n return useFetch<ResourceData>(() => {\n const fetchJson = (path: string) => fetch(`${baseUrl}/${path}`).then(r => r.json());\n return Promise.all([\n fetchJson('interactions'),\n fetchJson('tools'),\n fetchJson('skills'),\n fetchJson('activities'),\n fetchJson('types'),\n fetchJson('templates'),\n ]).then(([interactions, tools, skills, activities, types, templates]) =>\n buildResourceData(interactions, tools, skills, activities, types, templates, mcpEndpoints)\n );\n }, [baseUrl, mcpEndpoints]);\n}\n","/** Tailwind class mappings for resource type badges. */\nexport const TYPE_VARIANTS: Record<string, string> = {\n tool: 'bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300',\n skill: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300',\n interaction: 'bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300',\n type: 'bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-300',\n template: 'bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300',\n activity: 'bg-rose-100 text-rose-800 dark:bg-rose-500/15 dark:text-rose-300',\n mcp: 'bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300',\n};\n\n/** Tailwind class mappings for prompt role badges. */\nexport const ROLE_VARIANTS: Record<string, string> = {\n system: 'bg-blue-100 text-blue-800 dark:bg-blue-500/15 dark:text-blue-300',\n user: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-300',\n assistant: 'bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300',\n safety: 'bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300',\n tool: 'bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300',\n};\n","import { Badge } from '@vertesia/ui/core';\nimport { NavLink } from '@vertesia/ui/router';\nimport { ArrowLeft } from 'lucide-react';\nimport type { ReactNode } from 'react';\n\nimport type { ResourceType } from '../types.js';\nimport { TYPE_VARIANTS } from './typeVariants.js';\n\ninterface DetailPageProps {\n type: ResourceType;\n title: string;\n description?: string;\n tags?: string[];\n backHref?: string;\n children?: ReactNode;\n}\n\nexport function DetailPage({ type, title, description, tags, backHref = '/', children }: DetailPageProps) {\n return (\n <div className=\"mx-auto max-w-5xl px-7 py-10\">\n <nav className=\"mb-5 flex items-center gap-4\">\n {backHref !== '/' && (\n <NavLink href=\"/\" className=\"text-sm text-primary hover:opacity-75\">Home</NavLink>\n )}\n <NavLink href={backHref} className=\"flex items-center gap-1 text-sm text-primary hover:opacity-75\">\n <ArrowLeft className=\"size-3.5\" />\n Back\n </NavLink>\n </nav>\n\n <div className=\"mb-8\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS[type] ?? ''}`}>\n {type}\n </span>\n <h1 className=\"-tracking-wide text-3xl font-bold text-foreground\">{title}</h1>\n {description && <p className=\"mt-1 text-sm leading-relaxed text-muted-foreground\">{description}</p>}\n {tags && tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n </div>\n\n {children}\n </div>\n );\n}\n","import type { RemoteActivityDefinition } from '@vertesia/common';\nimport { Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\ninterface ActivityCollectionResponse {\n title: string;\n description: string;\n activities: RemoteActivityDefinition[];\n}\n\nexport function ActivityCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data, error } = useFetch<ActivityCollectionResponse>(\n () => fetch(`${baseUrl}/activities/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load activity collection &ldquo;{collection}&rdquo;.</div>;\n if (!data) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"activity\"\n title={data.title || collection}\n description={data.description || `${data.activities.length} activit${data.activities.length !== 1 ? 'ies' : 'y'} in this collection.`}\n >\n {data.activities.map(activity => (\n <Card key={activity.name} className=\"mb-4\">\n <CardContent className=\"p-5\">\n <div className=\"mb-2 flex items-center gap-2\">\n <span className={`inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.activity}`}>\n activity\n </span>\n <span className=\"font-semibold text-card-foreground\">{activity.name}</span>\n </div>\n <div className=\"text-sm text-muted-foreground\">{activity.description || 'No description'}</div>\n {activity.input_schema && (\n <div className=\"mt-3\">\n <p className=\"mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">Input Schema</p>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(activity.input_schema, null, 2)}\n </pre>\n </div>\n )}\n {activity.output_schema && (\n <div className=\"mt-3\">\n <p className=\"mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">Output Schema</p>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(activity.output_schema, null, 2)}\n </pre>\n </div>\n )}\n </CardContent>\n </Card>\n ))}\n </DetailPage>\n );\n}\n","import { Card, CardContent } from '@vertesia/ui/core';\nimport { NavLink } from '@vertesia/ui/router';\n\nimport type { CollectionInfo } from '../types.js';\nimport { TYPE_VARIANTS } from './typeVariants.js';\n\nexport function CollectionCard({ collection }: { collection: CollectionInfo }) {\n const plural = collection.type === 'activity' ? 'activities' : `${collection.type}s`;\n const href = `/${plural}/${collection.name}`;\n\n return (\n <NavLink href={href} className=\"block no-underline\">\n <Card className=\"cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <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] ?? ''}`}>\n {collection.type}\n </span>\n <div className=\"font-semibold text-card-foreground\">{collection.title}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">\n {collection.description || 'No description'}\n </div>\n <div className=\"mt-2 font-mono text-xs text-muted-foreground\">\n {collection.count} {collection.count === 1 ? 'item' : 'items'}\n </div>\n </CardContent>\n </Card>\n </NavLink>\n );\n}\n","import { Button } from '@vertesia/ui/core';\nimport { Check, Copy } from 'lucide-react';\nimport { useState } from 'react';\n\nexport function EndpointPanel({ label, path }: { label: string; path: string }) {\n const [copied, setCopied] = useState(false);\n\n function handleCopy() {\n const url = window.location.origin + path;\n navigator.clipboard.writeText(url);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n }\n\n return (\n <div className=\"mb-3\">\n <div className=\"mb-1 text-[0.7rem] font-medium uppercase tracking-widest text-primary\">\n {label}\n </div>\n <div className=\"flex items-center gap-2 rounded-lg border border-border bg-muted-background px-3 py-2\">\n <code className=\"flex-1 font-mono text-sm text-foreground\">{path}</code>\n <Button\n variant=\"ghost\"\n size=\"xs\"\n onClick={handleCopy}\n aria-label=\"Copy full URL\"\n >\n {copied ? <Check className=\"size-3.5\" /> : <Copy className=\"size-3.5\" />}\n </Button>\n </div>\n </div>\n );\n}\n","import { DotBadge } from '@vertesia/ui/core';\n\nexport function SummaryBadge({ count, label }: { count: number; label: string }) {\n if (count === 0) return null;\n return (\n <DotBadge variant=\"success\">\n {count} {label}{count !== 1 ? 's' : ''}\n </DotBadge>\n );\n}\n","import { Card } from '@vertesia/ui/core';\nimport { Download, LayoutDashboard } from 'lucide-react';\n\nimport type { ResourceItem, ResourceType } from '../types.js';\nimport { EndpointPanel } from './EndpointPanel.js';\nimport { SummaryBadge } from './SummaryBadge.js';\n\ninterface HeroSectionProps {\n title: string;\n version: string;\n resources: ResourceItem[];\n}\n\nfunction getInitials(title: string): string {\n return title.split(/\\s+/).map(w => w[0]).filter(Boolean).slice(0, 2).join('').toUpperCase();\n}\n\nfunction countByType(resources: ResourceItem[]): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const r of resources) {\n counts[r.type] = (counts[r.type] || 0) + 1;\n }\n return counts;\n}\n\nconst badgeLabels: { type: ResourceType; label: string }[] = [\n { type: 'tool', label: 'tool' },\n { type: 'activity', label: 'activity' },\n { type: 'skill', label: 'skill' },\n { type: 'interaction', label: 'interaction' },\n { type: 'type', label: 'content type' },\n { type: 'template', label: 'template' },\n { type: 'mcp', label: 'MCP provider' },\n];\n\nexport function HeroSection({ title, version, resources }: HeroSectionProps) {\n const counts = countByType(resources);\n\n return (\n <Card className=\"mb-10 overflow-hidden border bg-linear-to-br from-card to-muted-background\">\n <div className=\"flex flex-col gap-6 p-6 md:flex-row md:items-start md:justify-between\">\n <div className=\"flex flex-1 flex-col gap-3\">\n <div className=\"flex items-center gap-4\">\n <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\">\n {getInitials(title)}\n </div>\n <div>\n <p className=\"text-xs font-medium uppercase tracking-widest text-muted-foreground\">Tools Server</p>\n <h1 className=\"-tracking-wide text-2xl font-bold text-foreground\">{title}</h1>\n </div>\n </div>\n\n <p className=\"text-sm text-muted-foreground\">\n Discover the tools, skills, interactions, and content types exposed by this server.\n </p>\n\n <div className=\"flex flex-wrap gap-2\">\n {badgeLabels.map(({ type, label }) => (\n <SummaryBadge key={type} count={counts[type] || 0} label={label} />\n ))}\n </div>\n\n <div className=\"flex flex-wrap gap-3 pt-1\">\n <a\n href=\"/app/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n 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\"\n >\n <LayoutDashboard className=\"size-4\" />\n UI Plugin Dev\n </a>\n <a\n href=\"/lib/plugin.js\"\n 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\"\n >\n <Download className=\"size-4\" />\n Plugin Bundle\n </a>\n </div>\n </div>\n\n <aside className=\"min-w-55 max-w-65 shrink-0\">\n <EndpointPanel label=\"Base endpoint\" path=\"/api\" />\n <EndpointPanel label=\"Package endpoint\" path=\"/api/package\" />\n <p className=\"mt-2 text-xs leading-relaxed text-muted-foreground\">\n Use <strong className=\"text-foreground\">POST /api/tools/&lt;collection&gt;</strong> or{' '}\n <strong className=\"text-foreground\">POST /api/skills/&lt;collection&gt;</strong> to call these from your apps or agents.\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">v{version}</p>\n </aside>\n </div>\n </Card>\n );\n}\n","import { Badge, Card, CardContent } from '@vertesia/ui/core';\n\nimport type { ResourceItem } from '../types.js';\nimport { TYPE_VARIANTS } from './typeVariants.js';\n\nexport function ResourceCard({ resource }: { resource: ResourceItem }) {\n return (\n <Card className=\"transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <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] ?? ''}`}>\n {resource.type}\n </span>\n <div className=\"font-semibold text-card-foreground\">{resource.title}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">\n {resource.description || 'No description'}\n </div>\n {resource.tags && resource.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {resource.tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n {resource.url && (\n <div className=\"mt-2 truncate font-mono text-xs text-muted-foreground\">{resource.url}</div>\n )}\n </CardContent>\n </Card>\n );\n}\n","import { Separator } from '@vertesia/ui/core';\n\nimport type { ResourceItem } from '../types.js';\nimport { ResourceCard } from './ResourceCard.js';\n\ninterface ResourceSectionProps {\n title: string;\n subtitle: string;\n resources: ResourceItem[];\n showDivider?: boolean;\n}\n\nexport function ResourceSection({ title, subtitle, resources, showDivider }: ResourceSectionProps) {\n if (resources.length === 0) return null;\n\n return (\n <section>\n {showDivider && <Separator className=\"my-8\" />}\n <div>\n <h2 className=\"text-xl font-semibold text-foreground\">\n {title}\n <span className=\"ml-2 text-sm font-normal text-muted-foreground\">({resources.length})</span>\n </h2>\n <p className=\"mb-4 text-sm text-muted-foreground\">{subtitle}</p>\n </div>\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {resources.map(r => (\n <ResourceCard key={`${r.type}:${r.name}`} resource={r} />\n ))}\n </div>\n </section>\n );\n}\n","import { Input } from '@vertesia/ui/core';\n\ninterface SearchBarProps {\n value: string;\n onChange: (value: string) => void;\n placeholder?: string;\n resultCount?: number;\n totalCount?: number;\n}\n\nexport function SearchBar({ value, onChange, placeholder, resultCount, totalCount }: SearchBarProps) {\n const hasQuery = value.trim().length > 0;\n const noResults = hasQuery && resultCount === 0;\n\n return (\n <div className=\"mb-7\">\n <Input\n type=\"search\"\n value={value}\n onChange={onChange}\n placeholder={placeholder || 'Search collections...'}\n className=\"max-w-sm rounded-full\"\n autoComplete=\"off\"\n />\n {hasQuery && !noResults && (\n <p className=\"mt-1.5 text-xs text-muted-foreground\">\n Showing {resultCount} of {totalCount} resources\n </p>\n )}\n {noResults && (\n <p className=\"mt-2 text-sm text-destructive\">\n No resources match this search.\n </p>\n )}\n </div>\n );\n}\n","import { Separator } from '@vertesia/ui/core';\nimport { useMemo, useState } from 'react';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { CollectionCard, HeroSection, ResourceSection, SearchBar } from '../components/index.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\nimport type { ResourceType } from '../types.js';\nimport { filterResources } from '../types.js';\n\nconst sections: { type: ResourceType; title: string; subtitle: string }[] = [\n { type: 'tool', title: 'Tools', subtitle: 'Remote tools available to agents via Vertesia.' },\n { type: 'activity', title: 'Activities', subtitle: 'Remote activities for DSL workflows, invoked via HTTP.' },\n { type: 'skill', title: 'Skills', subtitle: 'Reusable instructions and scripts packaged as tools.' },\n { type: 'interaction', title: 'Interactions', subtitle: 'Conversation blueprints surfaced in the Vertesia UI.' },\n { type: 'type', title: 'Content Types', subtitle: 'Schema definitions for structured content in the data store.' },\n { type: 'template', title: 'Rendering Templates', subtitle: 'Document and presentation templates for content generation.' },\n { type: 'mcp', title: 'MCP Providers', subtitle: 'Remote MCP servers available through this tools server.' },\n];\n\nexport function HomePage() {\n const { serverInfo, collections, resources } = useAdminContext();\n const [search, setSearch] = useState('');\n\n const filtered = useMemo(() =>\n filterResources(resources, search),\n [resources, search]\n );\n\n const isSearching = search.trim().length > 0;\n\n return (\n <div className=\"mx-auto max-w-5xl px-7 py-10\">\n <HeroSection\n title={serverInfo.message.replace('Vertesia Tools API', 'Tools Server')}\n version={serverInfo.version}\n resources={resources}\n />\n\n <SearchBar\n value={search}\n onChange={setSearch}\n placeholder=\"Search tools, skills, interactions, types, templates...\"\n resultCount={filtered.length}\n totalCount={resources.length}\n />\n\n {isSearching ? (\n sections.map((section, i) => {\n const sectionItems = filtered.filter(r => r.type === section.type);\n return (\n <ResourceSection\n key={section.type}\n title={section.title}\n subtitle={section.subtitle}\n resources={sectionItems}\n showDivider={i > 0}\n />\n );\n })\n ) : (\n sections.map((section, i) => {\n const sectionCollections = collections.filter(c => c.type === section.type);\n const mcpResources = section.type === 'mcp'\n ? resources.filter(r => r.type === 'mcp')\n : [];\n\n if (sectionCollections.length === 0 && mcpResources.length === 0) return null;\n\n return (\n <section key={section.type}>\n {i > 0 && <Separator className=\"my-8\" />}\n <div>\n <h2 className=\"text-xl font-semibold text-foreground\">\n {section.title}\n <span className=\"ml-2 text-sm font-normal text-muted-foreground\">\n ({sectionCollections.length}{sectionCollections.length === 1\n ? ' collection' : ' collections'})\n </span>\n </h2>\n <p className=\"mb-4 text-sm text-muted-foreground\">{section.subtitle}</p>\n </div>\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {sectionCollections.map(col => (\n <CollectionCard key={`${col.type}:${col.name}`} collection={col} />\n ))}\n {mcpResources.map(r => (\n <div key={r.name} className=\"rounded-xl border border-border bg-card p-5 shadow-sm\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.mcp}`}>\n mcp\n </span>\n <div className=\"font-semibold text-card-foreground\">{r.title}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{r.description || 'No description'}</div>\n {r.url && <div className=\"mt-2 truncate font-mono text-xs text-muted-foreground\">{r.url}</div>}\n </div>\n ))}\n </div>\n </section>\n );\n })\n )}\n </div>\n );\n}\n","import type { CatalogInteractionRef } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\nexport function InteractionCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data: interactions, error } = useFetch<CatalogInteractionRef[]>(\n () => fetch(`${baseUrl}/interactions/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load collection &ldquo;{collection}&rdquo;.</div>;\n }\n\n if (!interactions) {\n return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n }\n\n return (\n <DetailPage\n type=\"interaction\"\n title={collection}\n description={`${interactions.length} interaction${interactions.length !== 1 ? 's' : ''} in this collection.`}\n >\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {interactions.map(inter => (\n <NavLink key={inter.id} href={`/interactions/${collection}/${inter.name}`} className=\"block no-underline\">\n <Card className=\"cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.interaction}`}>\n interaction\n </span>\n <div className=\"font-semibold text-card-foreground\">{inter.title || inter.name}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{inter.description || 'No description'}</div>\n {inter.tags && inter.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {inter.tags.map(tag => <Badge key={tag}>{tag}</Badge>)}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n ))}\n </div>\n </DetailPage>\n );\n}\n","import type { InteractionSpec } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\nimport { useUserSession } from '@vertesia/ui/session';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { ROLE_VARIANTS } from '../components/typeVariants.js';\n\ntype InteractionResponse = InteractionSpec & { id: string };\n\nexport function InteractionDetail() {\n const { client } = useUserSession();\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: interaction, error } = useFetch<InteractionResponse>(\n () => client.getRawJWT().then(token => fetch(`${baseUrl}/interactions/${collection}/${name}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n })).then(r => {\n if (!r.ok) throw new Error(`Failed to load interaction: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load interaction &ldquo;{name}&rdquo;.</div>;\n }\n\n if (!interaction) {\n return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n }\n\n const { agent_runner_options } = interaction;\n const hasAgentFlags = agent_runner_options &&\n (agent_runner_options.is_agent || agent_runner_options.is_tool || agent_runner_options.is_skill);\n\n return (\n <DetailPage\n type=\"interaction\"\n title={interaction.title || interaction.name}\n description={interaction.description}\n tags={interaction.tags}\n backHref={`/interactions/${collection}`}\n >\n {interaction.prompts && interaction.prompts.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Prompts</h2>\n {interaction.prompts.map((prompt) => (\n <Card key={`${prompt.role}-${prompt.name ?? ''}`} className=\"mb-3\">\n <CardContent className=\"p-4\">\n <div className=\"mb-2 flex items-center gap-2\">\n <span className={`rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${ROLE_VARIANTS[prompt.role] ?? ''}`}>\n {prompt.role}\n </span>\n {prompt.name && (\n <span className=\"text-sm italic text-muted-foreground\">{prompt.name}</span>\n )}\n </div>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">{prompt.content}</pre>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {interaction.result_schema && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Result Schema</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(interaction.result_schema, null, 2)}\n </pre>\n </div>\n )}\n\n {hasAgentFlags && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Agent Runner</h2>\n <div className=\"flex flex-wrap gap-2\">\n {agent_runner_options.is_agent && <Badge variant=\"success\">Agent</Badge>}\n {agent_runner_options.is_tool && <Badge variant=\"success\">Tool</Badge>}\n {agent_runner_options.is_skill && <Badge variant=\"success\">Skill</Badge>}\n </div>\n </div>\n )}\n </DetailPage>\n );\n}\n","import { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\nimport { useMemo } from 'react';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\ninterface SkillToolDef {\n name: string;\n description?: string;\n related_tools?: string[];\n}\n\ninterface SkillCollectionResponse {\n title: string;\n description: string;\n tools: SkillToolDef[];\n}\n\ninterface WidgetInfo {\n skill: string;\n collection: string;\n url: string;\n}\n\ninterface WidgetsResponse {\n widgets: Record<string, WidgetInfo>;\n}\n\n/** Strip the learn_ prefix added by the SDK when exposing skills as tools. */\nfunction skillDisplayName(name: string): string {\n return name.startsWith('learn_') ? name.slice(6) : name;\n}\n\nexport function SkillCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data, error } = useFetch<SkillCollectionResponse>(\n () => fetch(`${baseUrl}/skills/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n const { data: widgetsData } = useFetch<WidgetsResponse>(\n () => fetch(`${baseUrl}/package?scope=widgets`).then(r => r.ok ? r.json() : { widgets: {} }),\n [baseUrl]\n );\n\n const collectionWidgets = useMemo(() => {\n if (!widgetsData?.widgets) return [];\n return Object.entries(widgetsData.widgets)\n .filter(([_, w]) => w.collection === collection)\n .map(([name, w]) => ({ name, ...w }));\n }, [widgetsData, collection]);\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load skill collection &ldquo;{collection}&rdquo;.</div>;\n if (!data) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"skill\"\n title={data.title || collection}\n description={data.description || `${data.tools.length} skill${data.tools.length !== 1 ? 's' : ''} in this collection.`}\n >\n {collectionWidgets.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Widgets</h2>\n <div className=\"flex flex-wrap gap-2\">\n {collectionWidgets.map(w => (\n <Badge key={w.name} variant=\"success\">\n {w.name}\n <span className=\"ml-2 font-mono text-xs opacity-70\">(skill: {w.skill})</span>\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {data.tools.map(skill => {\n const displayName = skillDisplayName(skill.name);\n return (\n <NavLink key={skill.name} href={`/skills/${collection}/${displayName}`} className=\"block no-underline\">\n <Card className=\"cursor-pointer transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.skill}`}>\n skill\n </span>\n <div className=\"font-semibold text-card-foreground\">{displayName}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{skill.description || 'No description'}</div>\n {skill.related_tools && skill.related_tools.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {skill.related_tools.map(t => <Badge key={t}>{t}</Badge>)}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n );\n })}\n </div>\n </DetailPage>\n );\n}\n","import { Badge, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\n\ninterface SkillDefinitionResponse {\n name: string;\n title?: string;\n description: string;\n instructions: string;\n content_type: 'md' | 'jst';\n input_schema?: Record<string, unknown>;\n related_tools?: string[];\n execution?: {\n language: string;\n packages?: string[];\n };\n scripts?: string[];\n widgets?: string[];\n}\n\nexport function SkillDetail() {\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: skill, error } = useFetch<SkillDefinitionResponse>(\n () => fetch(`${baseUrl}/skills/${collection}/${name}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load skill: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load skill &ldquo;{name}&rdquo;.</div>;\n if (!skill) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"skill\"\n title={skill.title || skill.name}\n description={skill.description}\n backHref={`/skills/${collection}`}\n >\n {skill.widgets && skill.widgets.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Widgets</h2>\n <div className=\"flex flex-wrap gap-2\">\n {skill.widgets.map(w => <Badge key={w} variant=\"success\">{w}</Badge>)}\n </div>\n </div>\n )}\n\n {skill.scripts && skill.scripts.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Scripts</h2>\n <div className=\"flex flex-wrap gap-2\">\n {skill.scripts.map(s => <Badge key={s} variant=\"success\">{s}</Badge>)}\n </div>\n </div>\n )}\n\n {skill.related_tools && skill.related_tools.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Related Tools</h2>\n <div className=\"flex flex-wrap gap-2\">\n {skill.related_tools.map(t => <Badge key={t} variant=\"success\">{t}</Badge>)}\n </div>\n </div>\n )}\n\n {skill.execution && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Execution</h2>\n <div className=\"flex flex-wrap gap-2\">\n <Badge variant=\"success\">{skill.execution.language}</Badge>\n {skill.execution.packages?.map(p => <Badge key={p} variant=\"success\">{p}</Badge>)}\n </div>\n </div>\n )}\n\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">\n Instructions\n {skill.content_type === 'jst' && <Badge className=\"ml-2\">JST template</Badge>}\n </h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">{skill.instructions}</pre>\n </div>\n\n {skill.input_schema && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Input Schema</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(skill.input_schema, null, 2)}\n </pre>\n </div>\n )}\n </DetailPage>\n );\n}\n","import type { RenderingTemplateDefinitionRef } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\nexport function TemplateCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data: templates, error } = useFetch<RenderingTemplateDefinitionRef[]>(\n () => fetch(`${baseUrl}/templates/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load template collection &ldquo;{collection}&rdquo;.</div>;\n if (!templates) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"template\"\n title={collection}\n description={`${templates.length} template${templates.length !== 1 ? 's' : ''} in this collection.`}\n >\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {templates.map(tmpl => (\n <NavLink\n key={tmpl.name}\n href={`/templates/${collection}/${tmpl.name}`}\n className=\"no-underline\"\n >\n <Card className=\"h-full transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.template}`}>\n {tmpl.type || 'template'}\n </span>\n <div className=\"font-semibold text-card-foreground\">{tmpl.title || tmpl.name}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{tmpl.description || 'No description'}</div>\n {tmpl.tags && tmpl.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {tmpl.tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n ))}\n </div>\n </DetailPage>\n );\n}\n","import { Badge, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\n\ninterface TemplateDefinitionResponse {\n name: string;\n title?: string;\n description: string;\n type: 'presentation' | 'document';\n tags?: string[];\n assets: string[];\n instructions: string;\n}\n\nexport function TemplateDetail() {\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: template, error } = useFetch<TemplateDefinitionResponse>(\n () => fetch(`${baseUrl}/templates/${collection}/${name}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load template: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load template &ldquo;{name}&rdquo;.</div>;\n if (!template) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"template\"\n title={template.title || template.name}\n description={template.description}\n tags={template.tags}\n backHref={`/templates/${collection}`}\n >\n <div className=\"mb-8\">\n <div className=\"flex flex-wrap gap-2\">\n <Badge variant=\"success\">{template.type}</Badge>\n </div>\n </div>\n\n {template.assets && template.assets.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Assets</h2>\n <div className=\"flex flex-wrap gap-2\">\n {template.assets.map(asset => (\n <Badge key={asset} variant=\"success\">\n {asset.split('/').pop()}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Instructions</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {template.instructions}\n </pre>\n </div>\n </DetailPage>\n );\n}\n","import { Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\ninterface ToolDef {\n name: string;\n description?: string;\n input_schema?: Record<string, unknown>;\n}\n\ninterface ToolCollectionResponse {\n title: string;\n description: string;\n tools: ToolDef[];\n}\n\nexport function ToolCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data, error } = useFetch<ToolCollectionResponse>(\n () => fetch(`${baseUrl}/tools/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load tool collection &ldquo;{collection}&rdquo;.</div>;\n if (!data) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"tool\"\n title={data.title || collection}\n description={data.description || `${data.tools.length} tool${data.tools.length !== 1 ? 's' : ''} in this collection.`}\n >\n {data.tools.map(tool => (\n <Card key={tool.name} className=\"mb-4\">\n <CardContent className=\"p-5\">\n <div className=\"mb-2 flex items-center gap-2\">\n <span className={`inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.tool}`}>\n tool\n </span>\n <span className=\"font-semibold text-card-foreground\">{tool.name}</span>\n </div>\n <div className=\"text-sm text-muted-foreground\">{tool.description || 'No description'}</div>\n {tool.input_schema && (\n <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\">\n {JSON.stringify(tool.input_schema, null, 2)}\n </pre>\n )}\n </CardContent>\n </Card>\n ))}\n </DetailPage>\n );\n}\n","import type { InCodeTypeDefinition } from '@vertesia/common';\nimport { Badge, Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';\nimport { NavLink, useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\nimport { TYPE_VARIANTS } from '../components/typeVariants.js';\n\nexport function TypeCollection() {\n const collection = useParams('collection');\n const { baseUrl } = useAdminContext();\n\n const { data: types, error } = useFetch<InCodeTypeDefinition[]>(\n () => fetch(`${baseUrl}/types/${collection}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load type collection &ldquo;{collection}&rdquo;.</div>;\n if (!types) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"type\"\n title={collection}\n description={`${types.length} content type${types.length !== 1 ? 's' : ''} in this collection.`}\n >\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {types.map(t => {\n const typeName = t.id?.split(':')[1] || t.name;\n return (\n <NavLink\n key={t.name}\n href={`/types/${collection}/${typeName}`}\n className=\"no-underline\"\n >\n <Card className=\"h-full transition-all hover:-translate-y-0.5 hover:shadow-md\">\n <CardContent className=\"p-5\">\n <span className={`mb-2 inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.type}`}>\n type\n </span>\n <div className=\"font-semibold text-card-foreground\">{t.name}</div>\n <div className=\"mt-1 text-sm text-muted-foreground\">{t.description || 'No description'}</div>\n {t.tags && t.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {t.tags.map(tag => (\n <Badge key={tag} variant=\"default\">{tag}</Badge>\n ))}\n </div>\n )}\n {(t.is_chunkable || t.strict_mode) && (\n <div className=\"mt-2 truncate font-mono text-xs text-muted-foreground\">\n {t.is_chunkable && 'chunkable'}\n {t.is_chunkable && t.strict_mode && ' · '}\n {t.strict_mode && 'strict'}\n </div>\n )}\n </CardContent>\n </Card>\n </NavLink>\n );\n })}\n </div>\n </DetailPage>\n );\n}\n","import type { InCodeTypeDefinition } from '@vertesia/common';\nimport { Badge, Spinner, useFetch } from '@vertesia/ui/core';\nimport { useParams } from '@vertesia/ui/router';\n\nimport { useAdminContext } from '../AdminContext.js';\nimport { DetailPage } from '../components/DetailPage.js';\n\nexport function TypeDetail() {\n const params = useParams();\n const collection = params.collection;\n const name = params.name;\n const { baseUrl } = useAdminContext();\n\n const { data: typeDef, error } = useFetch<InCodeTypeDefinition>(\n () => fetch(`${baseUrl}/types/${collection}/${name}`).then(r => {\n if (!r.ok) throw new Error(`Failed to load type: ${r.statusText}`);\n return r.json();\n }),\n [baseUrl, collection, name]\n );\n\n if (error) return <div className=\"p-6 text-destructive\">Failed to load type &ldquo;{name}&rdquo;.</div>;\n if (!typeDef) return <div className=\"flex h-64 items-center justify-center text-muted-foreground\"><Spinner /></div>;\n\n return (\n <DetailPage\n type=\"type\"\n title={typeDef.name}\n description={typeDef.description}\n tags={typeDef.tags}\n backHref={`/types/${collection}`}\n >\n {(typeDef.is_chunkable || typeDef.strict_mode) && (\n <div className=\"mb-8\">\n <div className=\"flex flex-wrap gap-2\">\n {typeDef.is_chunkable && <Badge variant=\"success\">Chunkable</Badge>}\n {typeDef.strict_mode && <Badge variant=\"success\">Strict Mode</Badge>}\n </div>\n </div>\n )}\n\n {typeDef.object_schema && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Object Schema</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(typeDef.object_schema, null, 2)}\n </pre>\n </div>\n )}\n\n {typeDef.table_layout && typeDef.table_layout.length > 0 && (\n <div className=\"mb-8\">\n <h2 className=\"mb-3 text-lg font-semibold text-foreground\">Table Layout</h2>\n <pre className=\"whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground\">\n {JSON.stringify(typeDef.table_layout, null, 2)}\n </pre>\n </div>\n )}\n </DetailPage>\n );\n}\n","import { Spinner } from '@vertesia/ui/core';\nimport type { Route } from '@vertesia/ui/router';\nimport { NestedRouterProvider, RouteComponent } from '@vertesia/ui/router';\n\nimport { AdminContext } from './AdminContext.js';\nimport { AdminTopBar } from './components/AdminTopBar.js';\nimport { useResourceData, useServerInfo } from './hooks.js';\nimport { ActivityCollection } from './pages/ActivityCollection.js';\nimport { HomePage } from './pages/HomePage.js';\nimport { InteractionCollection } from './pages/InteractionCollection.js';\nimport { InteractionDetail } from './pages/InteractionDetail.js';\nimport { SkillCollection } from './pages/SkillCollection.js';\nimport { SkillDetail } from './pages/SkillDetail.js';\nimport { TemplateCollection } from './pages/TemplateCollection.js';\nimport { TemplateDetail } from './pages/TemplateDetail.js';\nimport { ToolCollection } from './pages/ToolCollection.js';\nimport { TypeCollection } from './pages/TypeCollection.js';\nimport { TypeDetail } from './pages/TypeDetail.js';\n\nconst routes: Route[] = [\n { path: '/', Component: HomePage },\n { path: '/interactions/:collection', Component: InteractionCollection },\n { path: '/interactions/:collection/:name', Component: InteractionDetail },\n { path: '/tools/:collection', Component: ToolCollection },\n { path: '/activities/:collection', Component: ActivityCollection },\n { path: '/skills/:collection', Component: SkillCollection },\n { path: '/skills/:collection/:name', Component: SkillDetail },\n { path: '/types/:collection', Component: TypeCollection },\n { path: '/types/:collection/:name', Component: TypeDetail },\n { path: '/templates/:collection', Component: TemplateCollection },\n { path: '/templates/:collection/:name', Component: TemplateDetail },\n];\n\nexport interface AdminAppProps {\n /**\n * Base URL for the tool server API.\n * @default '/api'\n */\n baseUrl?: string;\n}\n\n/**\n * Admin app shell — loads data, provides context, and renders nested routes.\n *\n * Requires a parent VertesiaShell (or equivalent providers for ThemeProvider,\n * UserSessionProvider, ToastProvider).\n */\nexport function AdminApp({ baseUrl = '/api' }: AdminAppProps) {\n const { data: serverInfo, isLoading: loadingInfo, error: infoError } = useServerInfo(baseUrl);\n const { data: resourceData, isLoading: loadingData, error: dataError } = useResourceData(\n baseUrl,\n serverInfo?.endpoints.mcp,\n );\n\n const isLoading = loadingInfo || loadingData;\n const error = infoError || dataError;\n\n if (isLoading) {\n return (\n <div className=\"flex h-64 items-center justify-center text-muted-foreground\">\n <Spinner />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"p-6 text-destructive\">\n Failed to load server info. Is the API running?\n </div>\n );\n }\n\n if (!serverInfo || !resourceData) return null;\n\n const title = serverInfo.message.replace('Vertesia Tools API', 'Tools Server');\n\n return (\n <div className=\"min-h-screen bg-background text-foreground\">\n <AdminTopBar title={title} />\n <AdminContext.Provider value={{\n serverInfo,\n collections: resourceData.collections,\n resources: resourceData.resources,\n baseUrl,\n }}>\n <NestedRouterProvider routes={routes}>\n <RouteComponent />\n </NestedRouterProvider>\n </AdminContext.Provider>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
package/lib/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Types for the admin panel
3
3
  */
4
- import type { AgentToolDefinition, CatalogInteractionRef, InCodeTypeDefinition, RenderingTemplateDefinitionRef } from '@vertesia/common';
4
+ import type { AgentToolDefinition, CatalogInteractionRef, InCodeTypeDefinition, RemoteActivityDefinition, RenderingTemplateDefinitionRef } from '@vertesia/common';
5
5
  /**
6
6
  * Server info from GET /api
7
7
  */
@@ -11,11 +11,12 @@ export interface ServerInfo {
11
11
  endpoints: {
12
12
  tools: string[];
13
13
  interactions: string[];
14
+ activities: string[];
14
15
  templates: string[];
15
16
  mcp: string[];
16
17
  };
17
18
  }
18
- export type ResourceType = 'tool' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';
19
+ export type ResourceType = 'tool' | 'activity' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';
19
20
  /**
20
21
  * A normalized resource entry for display and search.
21
22
  */
@@ -66,6 +67,10 @@ interface TypesResponse {
66
67
  types: InCodeTypeDefinition[];
67
68
  collections: CollectionMeta[];
68
69
  }
70
+ interface ActivitiesResponse {
71
+ activities: RemoteActivityDefinition[];
72
+ collections: CollectionMeta[];
73
+ }
69
74
  interface TemplatesResponse {
70
75
  templates: RenderingTemplateDefinitionRef[];
71
76
  collections: CollectionMeta[];
@@ -80,7 +85,7 @@ export interface ResourceData {
80
85
  /**
81
86
  * Builds collections and a flat resource list from the 5 endpoint responses + MCP endpoints.
82
87
  */
83
- export declare function buildResourceData(interactionsResp: InteractionsResponse, toolsResp: ToolsResponse, skillsResp: SkillsResponse, typesResp: TypesResponse, templatesResp: TemplatesResponse, mcpEndpoints?: string[]): ResourceData;
88
+ export declare function buildResourceData(interactionsResp: InteractionsResponse, toolsResp: ToolsResponse, skillsResp: SkillsResponse, activitiesResp: ActivitiesResponse, typesResp: TypesResponse, templatesResp: TemplatesResponse, mcpEndpoints?: string[]): ResourceData;
84
89
  /**
85
90
  * Filters resources by a search query, matching against name, title, description, type, and tags.
86
91
  */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EACjC,MAAM,kBAAkB,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE;QACP,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,GAAG,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACL;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AAE1F;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,6FAA6F;IAC7F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,UAAU,cAAc;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,UAAU,oBAAoB;IAC1B,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,aAAa;IACnB,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,cAAc;IACpB,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,aAAa;IACnB,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,iBAAiB;IACvB,SAAS,EAAE,8BAA8B,EAAE,CAAC;IAC5C,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC7B;AAoCD;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,gBAAgB,EAAE,oBAAoB,EACtC,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,aAAa,EACxB,aAAa,EAAE,iBAAiB,EAChC,YAAY,CAAC,EAAE,MAAM,EAAE,GACxB,YAAY,CAmJd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAUpF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACR,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,8BAA8B,EACjC,MAAM,kBAAkB,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE;QACP,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,GAAG,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACL;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;AAEvG;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,6FAA6F;IAC7F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,UAAU,cAAc;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,UAAU,oBAAoB;IAC1B,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,aAAa;IACnB,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,cAAc;IACpB,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,aAAa;IACnB,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,kBAAkB;IACxB,UAAU,EAAE,wBAAwB,EAAE,CAAC;IACvC,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED,UAAU,iBAAiB;IACvB,SAAS,EAAE,8BAA8B,EAAE,CAAC;IAC5C,WAAW,EAAE,cAAc,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC7B;AAoCD;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,gBAAgB,EAAE,oBAAoB,EACtC,SAAS,EAAE,aAAa,EACxB,UAAU,EAAE,cAAc,EAC1B,cAAc,EAAE,kBAAkB,EAClC,SAAS,EAAE,aAAa,EACxB,aAAa,EAAE,iBAAiB,EAChC,YAAY,CAAC,EAAE,MAAM,EAAE,GACxB,YAAY,CA4Kd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAUpF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/tools-admin-ui",
3
- "version": "1.0.0-dev.20260305.083323Z",
3
+ "version": "1.0.0-dev.20260331.091034Z",
4
4
  "description": "Shared admin UI for Vertesia tool servers",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "lucide-react": "^0.562.0",
35
- "@vertesia/common": "1.0.0-dev.20260305.083323Z",
36
- "@vertesia/ui": "1.0.0-dev.20260305.083323Z"
35
+ "@vertesia/common": "1.0.0-dev.20260331.091034Z",
36
+ "@vertesia/ui": "1.0.0-dev.20260331.091034Z"
37
37
  },
38
38
  "repository": {
39
39
  "type": "git",
package/src/AdminApp.tsx CHANGED
@@ -5,6 +5,7 @@ import { NestedRouterProvider, RouteComponent } from '@vertesia/ui/router';
5
5
  import { AdminContext } from './AdminContext.js';
6
6
  import { AdminTopBar } from './components/AdminTopBar.js';
7
7
  import { useResourceData, useServerInfo } from './hooks.js';
8
+ import { ActivityCollection } from './pages/ActivityCollection.js';
8
9
  import { HomePage } from './pages/HomePage.js';
9
10
  import { InteractionCollection } from './pages/InteractionCollection.js';
10
11
  import { InteractionDetail } from './pages/InteractionDetail.js';
@@ -21,6 +22,7 @@ const routes: Route[] = [
21
22
  { path: '/interactions/:collection', Component: InteractionCollection },
22
23
  { path: '/interactions/:collection/:name', Component: InteractionDetail },
23
24
  { path: '/tools/:collection', Component: ToolCollection },
25
+ { path: '/activities/:collection', Component: ActivityCollection },
24
26
  { path: '/skills/:collection', Component: SkillCollection },
25
27
  { path: '/skills/:collection/:name', Component: SkillDetail },
26
28
  { path: '/types/:collection', Component: TypeCollection },
@@ -5,7 +5,8 @@ import type { CollectionInfo } from '../types.js';
5
5
  import { TYPE_VARIANTS } from './typeVariants.js';
6
6
 
7
7
  export function CollectionCard({ collection }: { collection: CollectionInfo }) {
8
- const href = `/${collection.type}s/${collection.name}`;
8
+ const plural = collection.type === 'activity' ? 'activities' : `${collection.type}s`;
9
+ const href = `/${plural}/${collection.name}`;
9
10
 
10
11
  return (
11
12
  <NavLink href={href} className="block no-underline">
@@ -25,6 +25,7 @@ function countByType(resources: ResourceItem[]): Record<string, number> {
25
25
 
26
26
  const badgeLabels: { type: ResourceType; label: string }[] = [
27
27
  { type: 'tool', label: 'tool' },
28
+ { type: 'activity', label: 'activity' },
28
29
  { type: 'skill', label: 'skill' },
29
30
  { type: 'interaction', label: 'interaction' },
30
31
  { type: 'type', label: 'content type' },
@@ -5,6 +5,7 @@ export const TYPE_VARIANTS: Record<string, string> = {
5
5
  interaction: 'bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-300',
6
6
  type: 'bg-gray-100 text-gray-700 dark:bg-gray-500/20 dark:text-gray-300',
7
7
  template: 'bg-violet-100 text-violet-800 dark:bg-violet-500/15 dark:text-violet-300',
8
+ activity: 'bg-rose-100 text-rose-800 dark:bg-rose-500/15 dark:text-rose-300',
8
9
  mcp: 'bg-pink-100 text-pink-800 dark:bg-pink-500/15 dark:text-pink-300',
9
10
  };
10
11
 
package/src/dev/env.ts CHANGED
@@ -7,8 +7,8 @@ Env.init({
7
7
  isDocker: true,
8
8
  type: "development",
9
9
  endpoints: {
10
- studio: "https://api.vertesia.io",
11
- zeno: "https://api.vertesia.io",
12
- sts: "https://sts.vertesia.io",
10
+ studio: "https://api.us1.vertesia.io",
11
+ zeno: "https://api.us1.vertesia.io",
12
+ sts: "https://sts.us1.vertesia.io",
13
13
  }
14
14
  });
package/src/dev/main.tsx CHANGED
@@ -2,6 +2,7 @@
2
2
  import './index.css';
3
3
  import "./env.js"
4
4
 
5
+ import { I18nProvider } from '@vertesia/ui/i18n';
5
6
  import { VertesiaShell } from '@vertesia/ui/shell';
6
7
  import { RouterProvider } from '@vertesia/ui/router';
7
8
  import { StrictMode } from 'react';
@@ -32,9 +33,11 @@ if (!baseUrl) {
32
33
  } else {
33
34
  root.render(
34
35
  <StrictMode>
35
- <VertesiaShell>
36
- <RouterProvider routes={devRoutes} />
37
- </VertesiaShell>
36
+ <I18nProvider lng="en">
37
+ <VertesiaShell>
38
+ <RouterProvider routes={devRoutes} />
39
+ </VertesiaShell>
40
+ </I18nProvider>
38
41
  </StrictMode>,
39
42
  );
40
43
  }
package/src/hooks.ts CHANGED
@@ -28,10 +28,11 @@ export function useResourceData(baseUrl: string, mcpEndpoints?: string[]) {
28
28
  fetchJson('interactions'),
29
29
  fetchJson('tools'),
30
30
  fetchJson('skills'),
31
+ fetchJson('activities'),
31
32
  fetchJson('types'),
32
33
  fetchJson('templates'),
33
- ]).then(([interactions, tools, skills, types, templates]) =>
34
- buildResourceData(interactions, tools, skills, types, templates, mcpEndpoints)
34
+ ]).then(([interactions, tools, skills, activities, types, templates]) =>
35
+ buildResourceData(interactions, tools, skills, activities, types, templates, mcpEndpoints)
35
36
  );
36
37
  }, [baseUrl, mcpEndpoints]);
37
38
  }
@@ -0,0 +1,67 @@
1
+ import type { RemoteActivityDefinition } from '@vertesia/common';
2
+ import { Card, CardContent, Spinner, useFetch } from '@vertesia/ui/core';
3
+ import { useParams } from '@vertesia/ui/router';
4
+
5
+ import { useAdminContext } from '../AdminContext.js';
6
+ import { DetailPage } from '../components/DetailPage.js';
7
+ import { TYPE_VARIANTS } from '../components/typeVariants.js';
8
+
9
+ interface ActivityCollectionResponse {
10
+ title: string;
11
+ description: string;
12
+ activities: RemoteActivityDefinition[];
13
+ }
14
+
15
+ export function ActivityCollection() {
16
+ const collection = useParams('collection');
17
+ const { baseUrl } = useAdminContext();
18
+
19
+ const { data, error } = useFetch<ActivityCollectionResponse>(
20
+ () => fetch(`${baseUrl}/activities/${collection}`).then(r => {
21
+ if (!r.ok) throw new Error(`Failed to load collection: ${r.statusText}`);
22
+ return r.json();
23
+ }),
24
+ [baseUrl, collection]
25
+ );
26
+
27
+ if (error) return <div className="p-6 text-destructive">Failed to load activity collection &ldquo;{collection}&rdquo;.</div>;
28
+ if (!data) return <div className="flex h-64 items-center justify-center text-muted-foreground"><Spinner /></div>;
29
+
30
+ return (
31
+ <DetailPage
32
+ type="activity"
33
+ title={data.title || collection}
34
+ description={data.description || `${data.activities.length} activit${data.activities.length !== 1 ? 'ies' : 'y'} in this collection.`}
35
+ >
36
+ {data.activities.map(activity => (
37
+ <Card key={activity.name} className="mb-4">
38
+ <CardContent className="p-5">
39
+ <div className="mb-2 flex items-center gap-2">
40
+ <span className={`inline-block rounded-full px-2 py-0.5 text-[0.7rem] font-semibold uppercase tracking-wide ${TYPE_VARIANTS.activity}`}>
41
+ activity
42
+ </span>
43
+ <span className="font-semibold text-card-foreground">{activity.name}</span>
44
+ </div>
45
+ <div className="text-sm text-muted-foreground">{activity.description || 'No description'}</div>
46
+ {activity.input_schema && (
47
+ <div className="mt-3">
48
+ <p className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">Input Schema</p>
49
+ <pre className="whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground">
50
+ {JSON.stringify(activity.input_schema, null, 2)}
51
+ </pre>
52
+ </div>
53
+ )}
54
+ {activity.output_schema && (
55
+ <div className="mt-3">
56
+ <p className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">Output Schema</p>
57
+ <pre className="whitespace-pre-wrap wrap-break-word rounded-lg border border-border bg-muted-background p-4 font-mono text-sm text-foreground">
58
+ {JSON.stringify(activity.output_schema, null, 2)}
59
+ </pre>
60
+ </div>
61
+ )}
62
+ </CardContent>
63
+ </Card>
64
+ ))}
65
+ </DetailPage>
66
+ );
67
+ }
@@ -9,6 +9,7 @@ import { filterResources } from '../types.js';
9
9
 
10
10
  const sections: { type: ResourceType; title: string; subtitle: string }[] = [
11
11
  { type: 'tool', title: 'Tools', subtitle: 'Remote tools available to agents via Vertesia.' },
12
+ { type: 'activity', title: 'Activities', subtitle: 'Remote activities for DSL workflows, invoked via HTTP.' },
12
13
  { type: 'skill', title: 'Skills', subtitle: 'Reusable instructions and scripts packaged as tools.' },
13
14
  { type: 'interaction', title: 'Interactions', subtitle: 'Conversation blueprints surfaced in the Vertesia UI.' },
14
15
  { type: 'type', title: 'Content Types', subtitle: 'Schema definitions for structured content in the data store.' },
package/src/types.ts CHANGED
@@ -6,6 +6,7 @@ import type {
6
6
  AgentToolDefinition,
7
7
  CatalogInteractionRef,
8
8
  InCodeTypeDefinition,
9
+ RemoteActivityDefinition,
9
10
  RenderingTemplateDefinitionRef,
10
11
  } from '@vertesia/common';
11
12
 
@@ -18,12 +19,13 @@ export interface ServerInfo {
18
19
  endpoints: {
19
20
  tools: string[];
20
21
  interactions: string[];
22
+ activities: string[];
21
23
  templates: string[];
22
24
  mcp: string[];
23
25
  };
24
26
  }
25
27
 
26
- export type ResourceType = 'tool' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';
28
+ export type ResourceType = 'tool' | 'activity' | 'skill' | 'interaction' | 'type' | 'template' | 'mcp';
27
29
 
28
30
  /**
29
31
  * A normalized resource entry for display and search.
@@ -82,6 +84,11 @@ interface TypesResponse {
82
84
  collections: CollectionMeta[];
83
85
  }
84
86
 
87
+ interface ActivitiesResponse {
88
+ activities: RemoteActivityDefinition[];
89
+ collections: CollectionMeta[];
90
+ }
91
+
85
92
  interface TemplatesResponse {
86
93
  templates: RenderingTemplateDefinitionRef[];
87
94
  collections: CollectionMeta[];
@@ -136,6 +143,7 @@ export function buildResourceData(
136
143
  interactionsResp: InteractionsResponse,
137
144
  toolsResp: ToolsResponse,
138
145
  skillsResp: SkillsResponse,
146
+ activitiesResp: ActivitiesResponse,
139
147
  typesResp: TypesResponse,
140
148
  templatesResp: TemplatesResponse,
141
149
  mcpEndpoints?: string[],
@@ -219,6 +227,31 @@ export function buildResourceData(
219
227
  });
220
228
  }
221
229
 
230
+ // --- Activities (use collection field from definition) ---
231
+ const actCounts = countPerCollection(
232
+ activitiesResp.activities,
233
+ activitiesResp.collections,
234
+ (a) => a.collection,
235
+ );
236
+ for (const col of activitiesResp.collections) {
237
+ collections.push({
238
+ name: col.name,
239
+ title: col.title || formatTitle(col.name),
240
+ description: col.description || '',
241
+ type: 'activity',
242
+ count: actCounts.get(col.name) || 0,
243
+ });
244
+ }
245
+ for (const act of activitiesResp.activities) {
246
+ resources.push({
247
+ name: act.name,
248
+ title: act.title || formatTitle(act.name),
249
+ description: act.description || '',
250
+ type: 'activity',
251
+ url: act.url,
252
+ });
253
+ }
254
+
222
255
  // --- Types (id format: "collection:pathName") ---
223
256
  const typeCounts = countPerCollection(
224
257
  typesResp.types,