sourcey 3.3.9 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +19 -3
  2. package/dist/cli.js +1 -5
  3. package/dist/client/scroll-tracker.js +8 -1
  4. package/dist/components/layout/Head.d.ts.map +1 -1
  5. package/dist/components/layout/Head.js +2 -1
  6. package/dist/components/layout/Page.d.ts.map +1 -1
  7. package/dist/components/layout/Page.js +2 -1
  8. package/dist/components/layout/Sidebar.d.ts.map +1 -1
  9. package/dist/components/layout/Sidebar.js +6 -1
  10. package/dist/components/layout/TableOfContents.js +1 -1
  11. package/dist/components/mcp/AnnotationBadges.d.ts +15 -0
  12. package/dist/components/mcp/AnnotationBadges.d.ts.map +1 -0
  13. package/dist/components/mcp/AnnotationBadges.js +10 -0
  14. package/dist/components/mcp/McpConnection.d.ts +10 -0
  15. package/dist/components/mcp/McpConnection.d.ts.map +1 -0
  16. package/dist/components/mcp/McpConnection.js +32 -0
  17. package/dist/components/mcp/McpEndpointBar.d.ts +8 -0
  18. package/dist/components/mcp/McpEndpointBar.d.ts.map +1 -0
  19. package/dist/components/mcp/McpEndpointBar.js +16 -0
  20. package/dist/components/mcp/McpReturns.d.ts +18 -0
  21. package/dist/components/mcp/McpReturns.d.ts.map +1 -0
  22. package/dist/components/mcp/McpReturns.js +33 -0
  23. package/dist/components/openapi/Operation.d.ts.map +1 -1
  24. package/dist/components/openapi/Operation.js +5 -1
  25. package/dist/config.d.ts +3 -0
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +8 -3
  28. package/dist/core/doxygen-loader.js +12 -12
  29. package/dist/core/mcp-normalizer.d.ts +11 -0
  30. package/dist/core/mcp-normalizer.d.ts.map +1 -0
  31. package/dist/core/mcp-normalizer.js +382 -0
  32. package/dist/core/types.d.ts +26 -2
  33. package/dist/core/types.d.ts.map +1 -1
  34. package/dist/dev-server.d.ts.map +1 -1
  35. package/dist/dev-server.js +46 -8
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +16 -9
  38. package/dist/renderer/html-builder.d.ts.map +1 -1
  39. package/dist/renderer/html-builder.js +9 -0
  40. package/dist/themes/default/sourcey.css +36 -8
  41. package/dist/utils/markdown.d.ts.map +1 -1
  42. package/dist/utils/markdown.js +50 -1
  43. package/package.json +15 -7
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Sourcey is an open source documentation platform. Point it at an OpenAPI spec, add markdown guides, get a complete docs site. Static HTML you own; no dashboard, no monthly bill, no API calls to render your own documentation. Deploy anywhere.
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/sourcey)](https://www.npmjs.com/package/sourcey)
8
- [![build](https://img.shields.io/github/actions/workflow/status/nilstate/sourcey/ci.yml?branch=master)](https://github.com/nilstate/sourcey/actions)
8
+ [![build](https://img.shields.io/github/actions/workflow/status/sourcey/sourcey/ci.yml?branch=master)](https://github.com/sourcey/sourcey/actions)
9
9
  [![node](https://img.shields.io/node/v/sourcey)](https://nodejs.org)
10
10
 
11
11
  ```bash
@@ -14,7 +14,7 @@ npx sourcey init
14
14
 
15
15
  ![Sourcey](assets/screenshot.jpg)
16
16
 
17
- **[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/nilstate/sourcey)
17
+ **[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/sourcey/sourcey)
18
18
 
19
19
  ## Features
20
20
 
@@ -43,6 +43,22 @@ npx sourcey init
43
43
  | Self-hosted | Yes | No | No | No | Yes | Yes |
44
44
  | Pricing | Free / AGPL | $150+/mo | Free / paid | Paid | Free / paid | Free |
45
45
 
46
+ ## Install
47
+
48
+ ```bash
49
+ # npm (recommended)
50
+ npx sourcey init
51
+
52
+ # Homebrew
53
+ brew tap sourcey/sourcey && brew install sourcey
54
+
55
+ # Docker
56
+ docker run -v $(pwd):/docs sourcey/sourcey build
57
+
58
+ # Nix
59
+ nix run github:sourcey/sourcey
60
+ ```
61
+
46
62
  ## Quick start
47
63
 
48
64
  ```bash
@@ -159,7 +175,7 @@ sourcey validate api.yaml Validate a spec file
159
175
  ## Development
160
176
 
161
177
  ```bash
162
- git clone https://github.com/nilstate/sourcey.git
178
+ git clone https://github.com/sourcey/sourcey.git
163
179
  cd sourcey && npm install
164
180
  npm run build && npm test
165
181
 
package/dist/cli.js CHANGED
@@ -1,13 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { defineCommand, runMain } from "citty";
3
- import { readFileSync } from "node:fs";
4
- import { dirname, join } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
3
  import { buildDocs, buildSiteDocs } from "./index.js";
7
4
  import { loadConfig } from "./config.js";
8
5
  import { init } from "./init.js";
9
- const __dirname = dirname(fileURLToPath(import.meta.url));
10
- const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8"));
6
+ import pkg from "../package.json" with { type: "json" };
11
7
  const build = defineCommand({
12
8
  meta: {
13
9
  name: "build",
@@ -74,10 +74,17 @@
74
74
  }
75
75
  }
76
76
 
77
- // Scroll to element with header offset
77
+ // Scroll to element with header offset.
78
+ // For the first traverse target, scroll to the very top of the page
79
+ // so the title and all top padding are visible.
78
80
  function scrollToId(id, behavior) {
79
81
  var el = document.getElementById(id);
80
82
  if (!el) return;
83
+ var firstTarget = targets.length ? targets[0].getAttribute('data-traverse-target') : null;
84
+ if (id === firstTarget) {
85
+ window.scrollTo({ top: 0, behavior: behavior });
86
+ return;
87
+ }
81
88
  var offset = (navbar ? navbar.offsetHeight : 0) - 1;
82
89
  window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - offset, behavior: behavior });
83
90
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Head.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Head.tsx"],"names":[],"mappings":"AAIA,wBAAgB,IAAI,iCA6EnB"}
1
+ {"version":3,"file":"Head.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Head.tsx"],"names":[],"mappings":"AAKA,wBAAgB,IAAI,iCAqFnB"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "preact/jsx-ru
2
2
  import { useContext } from "preact/hooks";
3
3
  import { SpecContext, OptionsContext, PageContext, SiteContext, NavigationContext } from "../../renderer/context.js";
4
4
  import { langIconCSS } from "../../utils/lang-icons.js";
5
+ import pkg from "../../../package.json" with { type: "json" };
5
6
  export function Head() {
6
7
  const site = useContext(SiteContext);
7
8
  const spec = useContext(SpecContext);
@@ -51,5 +52,5 @@ export function Head() {
51
52
  body { margin: 0; background: rgb(var(--color-background-light)); }
52
53
  .dark body { background: rgb(var(--color-background-dark)); }
53
54
  `;
54
- return (_jsxs("head", { children: [_jsx("meta", { charset: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { children: pageTitle }), _jsx("meta", { name: "description", content: pageDescription }), _jsx("meta", { name: "sourcey-search", content: `${options.assetBase}search-index.json` }), _jsx("style", { dangerouslySetInnerHTML: { __html: themeCSS } }), _jsx("style", { dangerouslySetInnerHTML: { __html: langIconCSS() } }), site.customCSS && _jsx("style", { dangerouslySetInnerHTML: { __html: site.customCSS } }), _jsx("script", { dangerouslySetInnerHTML: { __html: `(function(){var t=localStorage.getItem('sourcey-theme');if(t==='dark')document.documentElement.classList.add('dark')})()` } }), googleFontsUrl && (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }), _jsx("link", { rel: "stylesheet", href: googleFontsUrl })] })), _jsx("link", { rel: "stylesheet", href: `${options.assetBase}sourcey.css` }), site.favicon && _jsx("link", { rel: "icon", href: site.favicon })] }));
55
+ return (_jsxs("head", { children: [_jsx("meta", { charset: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { children: pageTitle }), _jsx("meta", { name: "description", content: pageDescription }), _jsx("meta", { name: "generator", content: `Sourcey ${pkg.version}` }), _jsx("meta", { property: "og:title", content: pageTitle }), _jsx("meta", { property: "og:description", content: pageDescription }), _jsx("meta", { property: "og:type", content: "website" }), siteName && _jsx("meta", { property: "og:site_name", content: siteName }), _jsx("meta", { name: "twitter:card", content: "summary" }), _jsx("meta", { name: "twitter:title", content: pageTitle }), _jsx("meta", { name: "twitter:description", content: pageDescription }), _jsx("meta", { name: "sourcey-search", content: `${options.assetBase}search-index.json` }), _jsx("style", { dangerouslySetInnerHTML: { __html: themeCSS } }), _jsx("style", { dangerouslySetInnerHTML: { __html: langIconCSS() } }), site.customCSS && _jsx("style", { dangerouslySetInnerHTML: { __html: site.customCSS } }), _jsx("script", { dangerouslySetInnerHTML: { __html: `(function(){var t=localStorage.getItem('sourcey-theme');if(t==='dark')document.documentElement.classList.add('dark')})()` } }), googleFontsUrl && (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }), _jsx("link", { rel: "stylesheet", href: googleFontsUrl })] })), _jsx("link", { rel: "stylesheet", href: `${options.assetBase}sourcey.css` }), site.favicon && _jsx("link", { rel: "icon", href: site.favicon })] }));
55
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Page.tsx"],"names":[],"mappings":"AA8OA,wBAAgB,IAAI,iCAqCnB"}
1
+ {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Page.tsx"],"names":[],"mappings":"AAkPA,wBAAgB,IAAI,iCAqCnB"}
@@ -10,6 +10,7 @@ import { SecurityDefinitions } from "../openapi/Security.js";
10
10
  import { Tags } from "../openapi/Tags.js";
11
11
  import { Definition } from "../openapi/Definition.js";
12
12
  import { SocialIcon } from "../ui/SocialIcon.js";
13
+ import { McpConnection } from "../mcp/McpConnection.js";
13
14
  /**
14
15
  * Markdown page content with prose typography.
15
16
  */
@@ -27,7 +28,7 @@ function MarkdownPageContent({ page, className = "" }) {
27
28
  function SpecPageContent({ className = "" }) {
28
29
  const spec = useContext(SpecContext);
29
30
  const serverUrl = spec.servers[0]?.url ?? "/";
30
- return (_jsxs("div", { class: `relative grow box-border flex-col w-full mx-auto px-1 min-w-0 ${className}`, id: "content-area", children: [_jsxs("article", { children: [_jsx("header", { class: "mb-8", children: _jsxs("div", { class: "flex items-baseline gap-3", children: [_jsx("h1", { class: "text-2xl sm:text-3xl font-bold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))] tracking-tight", children: spec.info.title }), _jsxs("span", { class: "text-sm text-[rgb(var(--color-gray-400))]", children: ["v", spec.info.version] })] }) }), _jsx(Introduction, {}), _jsx(SecurityDefinitions, {}), _jsx(Tags, { tags: spec.tags, serverUrl: serverUrl }), Object.keys(spec.schemas).length > 0 && (_jsxs("div", { class: "mt-12", children: [_jsx("div", { class: "mb-6", children: _jsx("h1", { class: "text-xl font-bold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))]", children: "Models" }) }), Object.entries(spec.schemas).map(([name, schema]) => (_jsx(Definition, { name: name, schema: schema }, name)))] }))] }), _jsx(ContentFooter, {})] }));
31
+ return (_jsxs("div", { class: `relative grow box-border flex-col w-full mx-auto px-1 min-w-0 ${className}`, id: "content-area", children: [_jsxs("article", { children: [_jsx("header", { class: "mb-8", children: _jsxs("div", { class: "flex items-baseline gap-3", children: [_jsx("h1", { class: "text-2xl sm:text-3xl font-bold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))] tracking-tight", children: spec.info.title }), _jsxs("span", { class: "text-sm text-[rgb(var(--color-gray-400))]", children: ["v", spec.info.version] })] }) }), _jsx(Introduction, {}), spec.operations[0]?.mcpExtras?.connection && (_jsx(McpConnection, { connection: spec.operations[0].mcpExtras.connection })), _jsx(SecurityDefinitions, {}), _jsx(Tags, { tags: spec.tags, serverUrl: serverUrl }), Object.keys(spec.schemas).length > 0 && (_jsxs("div", { class: "mt-12", children: [_jsx("div", { class: "mb-6", children: _jsx("h1", { class: "text-xl font-bold text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))]", children: "Models" }) }), Object.entries(spec.schemas).map(([name, schema]) => (_jsx(Definition, { name: name, schema: schema }, name)))] }))] }), _jsx(ContentFooter, {})] }));
31
32
  }
32
33
  function PageNavigation() {
33
34
  const nav = useContext(NavigationContext);
@@ -1 +1 @@
1
- {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Sidebar.tsx"],"names":[],"mappings":"AA+EA;;GAEG;AACH,wBAAgB,OAAO,wCAuGtB"}
1
+ {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Sidebar.tsx"],"names":[],"mappings":"AAoFA;;GAEG;AACH,wBAAgB,OAAO,wCAuGtB"}
@@ -8,7 +8,7 @@ import { Logo } from "../ui/Logo.js";
8
8
  */
9
9
  function MethodPill({ method }) {
10
10
  const m = method.toUpperCase();
11
- const label = m === "DELETE" ? "DEL" : m;
11
+ const label = m === "DELETE" ? "DEL" : m === "RESOURCE" ? "RES" : m === "PROMPT" ? "PRMT" : m;
12
12
  const colors = {
13
13
  GET: "bg-green-400/20 dark:bg-green-400/20 text-green-700 dark:text-green-400",
14
14
  POST: "bg-blue-400/20 dark:bg-blue-400/20 text-blue-700 dark:text-blue-400",
@@ -16,6 +16,11 @@ function MethodPill({ method }) {
16
16
  DELETE: "bg-red-400/20 dark:bg-red-400/20 text-red-700 dark:text-red-400",
17
17
  DEL: "bg-red-400/20 dark:bg-red-400/20 text-red-700 dark:text-red-400",
18
18
  PATCH: "bg-orange-400/20 dark:bg-orange-400/20 text-orange-700 dark:text-orange-400",
19
+ TOOL: "bg-purple-400/20 dark:bg-purple-400/20 text-purple-700 dark:text-purple-400",
20
+ RESOURCE: "bg-green-400/20 dark:bg-green-400/20 text-green-700 dark:text-green-400",
21
+ RES: "bg-green-400/20 dark:bg-green-400/20 text-green-700 dark:text-green-400",
22
+ PROMPT: "bg-blue-400/20 dark:bg-blue-400/20 text-blue-700 dark:text-blue-400",
23
+ PRMT: "bg-blue-400/20 dark:bg-blue-400/20 text-blue-700 dark:text-blue-400",
19
24
  };
20
25
  return (_jsx("span", { class: "flex items-center w-8 h-[1lh] shrink-0", children: _jsx("span", { class: `px-1 py-0.5 rounded-md text-[0.55rem] leading-tight font-bold ${colors[m] ?? "bg-gray-400/20 text-gray-700"}`, children: label }) }));
21
26
  }
@@ -16,7 +16,7 @@ function TocList({ headings }) {
16
16
  groups[groups.length - 1].children.push(h);
17
17
  }
18
18
  }
19
- return (_jsx("ul", { class: "space-y-0.5", children: groups.map((g) => (_jsxs("li", { children: [_jsx("a", { href: `#${g.root.id}`, class: `${tocLink} py-1`, children: g.root.text }), g.children.length > 0 && (_jsx("ul", { class: "mb-1.5", children: g.children.map((c) => (_jsx("li", { children: _jsx("a", { href: `#${c.id}`, class: `${tocLink} pl-3 text-[13px] py-0.5`, children: c.text }) }, c.id))) }))] }, g.root.id))) }));
19
+ return (_jsx("ul", { children: groups.map((g) => (_jsxs("li", { children: [_jsx("a", { href: `#${g.root.id}`, class: `${tocLink} py-1`, children: g.root.text }), g.children.length > 0 && (_jsx("ul", { children: g.children.map((c) => (_jsx("li", { children: _jsx("a", { href: `#${c.id}`, class: `${tocLink} pl-3 text-[13px] py-0.5`, children: c.text }) }, c.id))) }))] }, g.root.id))) }));
20
20
  }
21
21
  export function TableOfContents({ headings }) {
22
22
  if (headings.length === 0)
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Renders MCP tool annotation badges inline with the operation title.
3
+ * Same visual pattern as DeprecatedBadge / RequiredBadge / ReadOnlyBadge.
4
+ */
5
+ interface Annotations {
6
+ readOnlyHint?: boolean;
7
+ destructiveHint?: boolean;
8
+ idempotentHint?: boolean;
9
+ openWorldHint?: boolean;
10
+ }
11
+ export declare function AnnotationBadges({ annotations }: {
12
+ annotations: Annotations;
13
+ }): import("preact").JSX.Element;
14
+ export {};
15
+ //# sourceMappingURL=AnnotationBadges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnotationBadges.d.ts","sourceRoot":"","sources":["../../../src/components/mcp/AnnotationBadges.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,WAAW;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AASD,wBAAgB,gBAAgB,CAAC,EAAE,WAAW,EAAE,EAAE;IAAE,WAAW,EAAE,WAAW,CAAA;CAAE,gCAa7E"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "preact/jsx-runtime";
2
+ const badges = [
3
+ { key: "readOnlyHint", label: "read-only", className: "bg-green-100/50 text-green-600 dark:bg-green-400/10 dark:text-green-300" },
4
+ { key: "destructiveHint", label: "destructive", className: "bg-red-100/50 text-red-600 dark:bg-red-400/10 dark:text-red-300" },
5
+ { key: "idempotentHint", label: "idempotent", className: "bg-blue-100/50 text-blue-600 dark:bg-blue-400/10 dark:text-blue-300" },
6
+ { key: "openWorldHint", label: "open-world", className: "bg-amber-100/50 text-amber-600 dark:bg-amber-400/10 dark:text-amber-300" },
7
+ ];
8
+ export function AnnotationBadges({ annotations }) {
9
+ return (_jsx(_Fragment, { children: badges.map(({ key, label, className }) => annotations[key] && (_jsx("span", { class: `whitespace-nowrap rounded-md px-2 py-0.5 text-xs font-medium ${className}`, children: label }, key))) }));
10
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Connection config card for MCP docs.
3
+ * Rendered below Introduction in SpecPageContent.
4
+ * Uses the same bordered card pattern as Introduction's Base URLs table.
5
+ */
6
+ import type { McpConnectionInfo } from "../../core/types.js";
7
+ export declare function McpConnection({ connection }: {
8
+ connection: McpConnectionInfo;
9
+ }): import("preact").JSX.Element | null;
10
+ //# sourceMappingURL=McpConnection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpConnection.d.ts","sourceRoot":"","sources":["../../../src/components/mcp/McpConnection.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,wBAAgB,aAAa,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,iBAAiB,CAAA;CAAE,uCAwD9E"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ export function McpConnection({ connection }) {
3
+ const transport = connection.transport;
4
+ if (!transport)
5
+ return null;
6
+ // Build the config JSON snippet
7
+ const serverEntry = {};
8
+ if (transport.type === "stdio") {
9
+ if (transport.command)
10
+ serverEntry.command = transport.command;
11
+ if (transport.args?.length)
12
+ serverEntry.args = transport.args;
13
+ }
14
+ else {
15
+ if (transport.url)
16
+ serverEntry.url = transport.url;
17
+ }
18
+ const configJson = JSON.stringify({ mcpServers: { [connection.serverName]: serverEntry } }, null, 2);
19
+ // Capabilities summary
20
+ const caps = [];
21
+ if (connection.capabilities) {
22
+ if (connection.capabilities.tools)
23
+ caps.push("tools");
24
+ if (connection.capabilities.resources)
25
+ caps.push("resources");
26
+ if (connection.capabilities.prompts)
27
+ caps.push("prompts");
28
+ if (connection.capabilities.logging)
29
+ caps.push("logging");
30
+ }
31
+ return (_jsxs("div", { class: "mb-8 rounded-[var(--radius)] border border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-border-dark-subtle)/0.1)] overflow-hidden", children: [_jsx("div", { class: "px-4 py-2.5 text-xs font-semibold text-[rgb(var(--color-gray-600))] dark:text-[rgb(var(--color-gray-300))] border-b border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-border-dark-subtle)/0.1)]", children: "Connect" }), _jsxs("div", { class: "px-4 py-3", children: [_jsx("p", { class: "text-sm text-[rgb(var(--color-gray-500))] mb-3", children: "Add to your MCP client configuration:" }), _jsx("div", { class: "code-group not-prose", children: _jsx("div", { class: "relative w-full px-4 py-3.5 text-sm leading-6 bg-[rgb(var(--color-code-block-light))] dark:bg-[rgb(var(--color-code-block-dark))] overflow-x-auto rounded-[var(--radius)]", style: "font-variant-ligatures: none", children: _jsx("div", { class: "font-mono whitespace-pre text-xs leading-[1.35rem] text-[rgb(var(--color-gray-800))] dark:text-[rgb(var(--color-gray-200))]", children: configJson }) }) }), _jsxs("div", { class: "mt-3 flex flex-wrap gap-x-6 gap-y-1 text-xs text-[rgb(var(--color-gray-500))]", children: [connection.mcpVersion && (_jsxs("span", { children: ["Protocol ", _jsxs("span", { class: "font-medium text-[rgb(var(--color-gray-700))] dark:text-[rgb(var(--color-gray-300))]", children: ["MCP ", connection.mcpVersion] })] })), _jsxs("span", { children: ["Transport ", _jsx("span", { class: "font-medium text-[rgb(var(--color-gray-700))] dark:text-[rgb(var(--color-gray-300))]", children: transport.type })] }), caps.length > 0 && (_jsxs("span", { children: ["Capabilities ", _jsx("span", { class: "font-medium text-[rgb(var(--color-gray-700))] dark:text-[rgb(var(--color-gray-300))]", children: caps.join(", ") })] }))] })] })] }));
32
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MCP equivalent of EndpointBar. Shows method pill + tool name or resource URI.
3
+ */
4
+ export declare function McpEndpointBar({ method, path }: {
5
+ method: string;
6
+ path: string;
7
+ }): import("preact").JSX.Element;
8
+ //# sourceMappingURL=McpEndpointBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpEndpointBar.d.ts","sourceRoot":"","sources":["../../../src/components/mcp/McpEndpointBar.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAQH,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,gCAuBhF"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ /**
3
+ * MCP equivalent of EndpointBar. Shows method pill + tool name or resource URI.
4
+ */
5
+ const methodColors = {
6
+ tool: "bg-purple-400/20 dark:bg-purple-400/20 text-purple-700 dark:text-purple-400",
7
+ resource: "bg-green-400/20 dark:bg-green-400/20 text-green-700 dark:text-green-400",
8
+ prompt: "bg-blue-400/20 dark:bg-blue-400/20 text-blue-700 dark:text-blue-400",
9
+ };
10
+ export function McpEndpointBar({ method, path }) {
11
+ const colorClass = methodColors[method] ?? "bg-gray-400/20 text-gray-700";
12
+ const label = method.toUpperCase();
13
+ // Split path on {param} segments for dimmed rendering
14
+ const segments = path.split(/(\{[^}]+\})/);
15
+ return (_jsxs("div", { class: "flex items-center gap-2 rounded-[var(--radius)] border border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-border-dark-subtle)/0.1)] px-3 py-2.5 mb-6 overflow-hidden", children: [_jsx("span", { class: `rounded-lg font-bold px-1.5 py-0.5 text-sm leading-5 shrink-0 ${colorClass}`, children: label }), _jsx("span", { class: "flex items-center overflow-x-auto flex-1 no-scrollbar font-mono text-sm text-[rgb(var(--color-gray-800))] dark:text-[rgb(var(--color-gray-200))]", children: segments.map((seg, i) => seg.startsWith("{") ? (_jsx("span", { class: "text-[rgb(var(--color-gray-400))] dark:text-[rgb(var(--color-gray-500))]", children: seg }, i)) : (_jsx("span", { children: seg }, i))) })] }));
16
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * MCP Returns section — replaces Responses for MCP operations.
3
+ * Renders output schema as a schema view instead of status code tables.
4
+ */
5
+ import type { NormalizedSchema } from "../../core/types.js";
6
+ /**
7
+ * Left column: "Returns" section label + schema view or fallback text.
8
+ */
9
+ export declare function McpReturnsCopy({ schema }: {
10
+ schema?: NormalizedSchema;
11
+ }): import("preact").JSX.Element;
12
+ /**
13
+ * Right column (sticky panel): example JSON for the output schema.
14
+ */
15
+ export declare function McpReturnsExample({ schema }: {
16
+ schema?: NormalizedSchema;
17
+ }): import("preact").JSX.Element;
18
+ //# sourceMappingURL=McpReturns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpReturns.d.ts","sourceRoot":"","sources":["../../../src/components/mcp/McpReturns.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAK5D;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAAE,gCAavE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAAE,gCAyB1E"}
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ import { SchemaView } from "../schema/SchemaView.js";
3
+ import { ExampleView } from "../schema/ExampleView.js";
4
+ import { SectionLabel } from "../ui/SectionLabel.js";
5
+ /**
6
+ * Left column: "Returns" section label + schema view or fallback text.
7
+ */
8
+ export function McpReturnsCopy({ schema }) {
9
+ return (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { children: "Returns" }), schema ? (_jsx(SchemaView, { schema: schema })) : (_jsx("p", { class: "text-sm text-[rgb(var(--color-gray-500))]", children: "Returns MCP content array (text, image, or embedded resource)." }))] }));
10
+ }
11
+ /**
12
+ * Right column (sticky panel): example JSON for the output schema.
13
+ */
14
+ export function McpReturnsExample({ schema }) {
15
+ if (!schema) {
16
+ return (_jsx(ExampleView, { schema: {
17
+ type: "object",
18
+ properties: {
19
+ content: {
20
+ type: "array",
21
+ items: {
22
+ type: "object",
23
+ properties: {
24
+ type: { type: "string", enum: ["text", "image", "resource"] },
25
+ text: { type: "string", example: "..." },
26
+ },
27
+ },
28
+ },
29
+ },
30
+ }, title: "Response" }));
31
+ }
32
+ return _jsx(ExampleView, { schema: schema, title: "Response" });
33
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Operation.d.ts","sourceRoot":"","sources":["../../../src/components/openapi/Operation.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAyB,MAAM,qBAAqB,CAAC;AAatF,UAAU,cAAc;IACtB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,cAAc,gCAsErE"}
1
+ {"version":3,"file":"Operation.d.ts","sourceRoot":"","sources":["../../../src/components/openapi/Operation.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAyB,MAAM,qBAAqB,CAAC;AAgBtF,UAAU,cAAc;IACtB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,cAAc,gCA0FrE"}
@@ -11,6 +11,9 @@ import { ResponsesCopy, ResponsesExamples } from "./Responses.js";
11
11
  import { SecurityCopy } from "./Security.js";
12
12
  import { CodeSamplesExamples } from "./CodeSamples.js";
13
13
  import { EndpointBar } from "./EndpointBar.js";
14
+ import { McpEndpointBar } from "../mcp/McpEndpointBar.js";
15
+ import { AnnotationBadges } from "../mcp/AnnotationBadges.js";
16
+ import { McpReturnsCopy, McpReturnsExample } from "../mcp/McpReturns.js";
14
17
  /**
15
18
  * Single operation with sticky code panel:
16
19
  * - Endpoint bar at top
@@ -22,7 +25,8 @@ export function Operation({ operation: op, serverUrl }) {
22
25
  const id = `operation-${htmlId(op.path)}-${htmlId(op.method)}`;
23
26
  const hasParams = op.parameters.length > 0;
24
27
  const hasBody = !!op.requestBody;
25
- return (_jsxs("div", { id: id, class: "py-8 border-t border-[rgb(var(--color-gray-100))] dark:border-[rgb(var(--color-gray-800))]", "data-traverse-target": id, children: [_jsxs("header", { class: "mb-6", children: [op.summary && (_jsx("h2", { class: "text-2xl sm:text-3xl text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))] tracking-tight font-bold mb-2", children: _jsx(Markdown, { content: op.summary, inline: true }) })), op.deprecated && _jsx(DeprecatedBadge, {})] }), _jsx(EndpointBar, { method: op.method, path: op.path, serverUrl: serverUrl }), _jsxs("div", { class: `flex flex-col ${apiFirst ? "lg:flex-row" : "xl:flex-row"} gap-8`, children: [_jsxs("div", { class: "flex-1 min-w-0", children: [op.description && (_jsx(Markdown, { content: op.description, class: "mb-6" })), hasBody && (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { meta: bodyMediaType(op.requestBody), children: "Body" }), _jsx(RequestBody, { body: op.requestBody })] })), hasParams && (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { children: "Parameters" }), _jsx(Parameters, { parameters: op.parameters })] })), op.responses.length > 0 && (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { children: "Response" }), _jsx(ResponsesCopy, { responses: op.responses })] })), _jsx(SecurityCopy, { security: op.security })] }), _jsxs("aside", { class: `hidden ${apiFirst ? "lg:block" : "xl:block"} w-[28rem] shrink-0 sticky self-start overflow-y-auto space-y-4`, style: "top: calc(var(--header-height) + 2.5rem); max-height: calc(100vh - var(--header-height) - 5rem)", children: [_jsx(CodeSamplesExamples, { operation: op, serverUrl: serverUrl, codeSampleLangs: site.codeSamples }), hasBody && _jsx(RequestBodyExample, { body: op.requestBody }), _jsx(ResponsesExamples, { responses: op.responses })] })] }), _jsxs("div", { class: `${apiFirst ? "lg:hidden" : "xl:hidden"} mt-8 space-y-4`, children: [_jsx(CodeSamplesExamples, { operation: op, serverUrl: serverUrl, codeSampleLangs: site.codeSamples }), hasBody && _jsx(RequestBodyExample, { body: op.requestBody }), _jsx(ResponsesExamples, { responses: op.responses })] })] }));
28
+ const mcp = op.mcpExtras;
29
+ return (_jsxs("div", { id: id, class: "py-8 border-t border-[rgb(var(--color-gray-100))] dark:border-[rgb(var(--color-gray-800))]", "data-traverse-target": id, children: [_jsx("header", { class: "mb-6", children: op.summary && (_jsxs("div", { class: "flex items-baseline gap-2 flex-wrap", children: [_jsx("h2", { class: "text-2xl sm:text-3xl text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-200))] tracking-tight font-bold mb-2", children: _jsx(Markdown, { content: op.summary, inline: true }) }), op.deprecated && _jsx(DeprecatedBadge, {}), mcp?.annotations && _jsx(AnnotationBadges, { annotations: mcp.annotations })] })) }), mcp ? (_jsx(McpEndpointBar, { method: op.method, path: op.path })) : (_jsx(EndpointBar, { method: op.method, path: op.path, serverUrl: serverUrl })), _jsxs("div", { class: `flex flex-col ${apiFirst ? "lg:flex-row" : "xl:flex-row"} gap-8`, children: [_jsxs("div", { class: "flex-1 min-w-0", children: [op.description && (_jsx(Markdown, { content: op.description, class: "mb-6" })), hasBody && (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { meta: bodyMediaType(op.requestBody), children: "Body" }), _jsx(RequestBody, { body: op.requestBody })] })), hasParams && (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { children: "Parameters" }), _jsx(Parameters, { parameters: op.parameters })] })), mcp ? (_jsx(McpReturnsCopy, { schema: mcp.outputSchema })) : (op.responses.length > 0 && (_jsxs("div", { class: "mt-6", children: [_jsx(SectionLabel, { children: "Response" }), _jsx(ResponsesCopy, { responses: op.responses })] }))), !mcp && _jsx(SecurityCopy, { security: op.security })] }), _jsxs("aside", { class: `hidden ${apiFirst ? "lg:block" : "xl:block"} w-[28rem] shrink-0 sticky self-start overflow-y-auto space-y-4`, style: "top: calc(var(--header-height) + 2.5rem); max-height: calc(100vh - var(--header-height) - 5rem)", children: [_jsx(CodeSamplesExamples, { operation: op, serverUrl: serverUrl, codeSampleLangs: site.codeSamples }), hasBody && _jsx(RequestBodyExample, { body: op.requestBody }), mcp ? (_jsx(McpReturnsExample, { schema: mcp.outputSchema })) : (_jsx(ResponsesExamples, { responses: op.responses }))] })] }), _jsxs("div", { class: `${apiFirst ? "lg:hidden" : "xl:hidden"} mt-8 space-y-4`, children: [_jsx(CodeSamplesExamples, { operation: op, serverUrl: serverUrl, codeSampleLangs: site.codeSamples }), hasBody && _jsx(RequestBodyExample, { body: op.requestBody }), mcp ? (_jsx(McpReturnsExample, { schema: mcp.outputSchema })) : (_jsx(ResponsesExamples, { responses: op.responses }))] })] }));
26
30
  }
27
31
  function bodyMediaType(body) {
28
32
  const types = Object.keys(body.content);
package/dist/config.d.ts CHANGED
@@ -78,6 +78,8 @@ export interface TabConfig {
78
78
  openapi?: string;
79
79
  groups?: GroupConfig[];
80
80
  doxygen?: DoxygenConfig;
81
+ /** Path to an mcp.json file (MCP server snapshot). */
82
+ mcp?: string;
81
83
  }
82
84
  export interface GroupConfig {
83
85
  group: string;
@@ -146,6 +148,7 @@ export interface ResolvedTab {
146
148
  openapi?: string;
147
149
  groups?: ResolvedGroup[];
148
150
  doxygen?: ResolvedDoxygenConfig;
151
+ mcp?: string;
149
152
  }
150
153
  export interface ResolvedPage {
151
154
  /** Original config slug (e.g. "run/index") */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -137,18 +137,23 @@ async function resolveTabs(tabs, configDir) {
137
137
  if (slugs.has(slug))
138
138
  throw new Error(`Duplicate tab slug "${slug}" (from "${tab.tab}")`);
139
139
  slugs.add(slug);
140
- const sources = [tab.openapi, tab.groups, tab.doxygen].filter(Boolean).length;
140
+ const sources = [tab.openapi, tab.groups, tab.doxygen, tab.mcp].filter(Boolean).length;
141
141
  if (sources > 1) {
142
- throw new Error(`Tab "${tab.tab}" has multiple sources; use only one of "openapi", "groups", or "doxygen"`);
142
+ throw new Error(`Tab "${tab.tab}" has multiple sources; use only one of "openapi", "groups", "doxygen", or "mcp"`);
143
143
  }
144
144
  if (sources === 0) {
145
- throw new Error(`Tab "${tab.tab}" needs one of "openapi", "groups", or "doxygen"`);
145
+ throw new Error(`Tab "${tab.tab}" needs one of "openapi", "groups", "doxygen", or "mcp"`);
146
146
  }
147
147
  if (tab.openapi) {
148
148
  const absPath = resolve(configDir, tab.openapi);
149
149
  await assertExists(absPath, `OpenAPI spec "${tab.openapi}" in tab "${tab.tab}"`);
150
150
  resolved.push({ label: tab.tab, slug, openapi: absPath });
151
151
  }
152
+ else if (tab.mcp) {
153
+ const absPath = resolve(configDir, tab.mcp);
154
+ await assertExists(absPath, `MCP spec "${tab.mcp}" in tab "${tab.tab}"`);
155
+ resolved.push({ label: tab.tab, slug, mcp: absPath });
156
+ }
152
157
  else if (tab.doxygen) {
153
158
  const absXml = resolve(configDir, tab.doxygen.xml);
154
159
  await assertExists(absXml, `Doxygen XML directory "${tab.doxygen.xml}" in tab "${tab.tab}"`);
@@ -108,18 +108,18 @@ function resolveIndexStyle(configured, groupMap, pages) {
108
108
  /**
109
109
  * Build index page HTML using sourcey's existing component markup.
110
110
  */
111
- function buildIndexHtml(style, tabSlug, _tabLabel, groupMap, pages) {
111
+ function buildIndexHtml(style, _tabSlug, _tabLabel, groupMap, pages) {
112
112
  if (style === "rich")
113
- return buildRichIndex(tabSlug, groupMap, pages);
113
+ return buildRichIndex(groupMap, pages);
114
114
  if (style === "structured")
115
- return buildStructuredIndex(tabSlug, groupMap, pages);
116
- return buildFlatIndex(tabSlug, groupMap);
115
+ return buildStructuredIndex(groupMap, pages);
116
+ return buildFlatIndex(groupMap);
117
117
  }
118
118
  /**
119
119
  * Rich: card grid with module name, description, and type count.
120
120
  * Uses sourcey's card-group/card-item CSS.
121
121
  */
122
- function buildRichIndex(tabSlug, groupMap, pages) {
122
+ function buildRichIndex(groupMap, pages) {
123
123
  const cards = [];
124
124
  for (const [, items] of groupMap) {
125
125
  const groupEntry = items.find((i) => i.kind === "group");
@@ -129,7 +129,7 @@ function buildRichIndex(tabSlug, groupMap, pages) {
129
129
  if (!page)
130
130
  continue;
131
131
  const typeCount = items.filter((i) => i.kind !== "group" && i.kind !== "namespace").length;
132
- const href = `${tabSlug}/${groupEntry.slug}.html`;
132
+ const href = `${groupEntry.slug}.html`;
133
133
  const desc = page.description || "";
134
134
  const meta = typeCount > 0
135
135
  ? `<p style="margin:0.5rem 0 0;font-size:0.8rem;opacity:0.5">${typeCount} type${typeCount !== 1 ? "s" : ""}</p>`
@@ -149,7 +149,7 @@ function buildRichIndex(tabSlug, groupMap, pages) {
149
149
  if (typeCount === 0)
150
150
  continue;
151
151
  const firstItem = items[0];
152
- const href = `${tabSlug}/${firstItem.slug}.html`;
152
+ const href = `${firstItem.slug}.html`;
153
153
  cards.push(`<a href="${href}" class="card-item">` +
154
154
  `<div class="card-item-inner">` +
155
155
  `<h3 class="card-item-title">${escHtml(key)}</h3>` +
@@ -165,7 +165,7 @@ function buildRichIndex(tabSlug, groupMap, pages) {
165
165
  * Structured: grouped list of types by module/namespace.
166
166
  * Rendered as markdown headings with link lists.
167
167
  */
168
- function buildStructuredIndex(tabSlug, groupMap, pages) {
168
+ function buildStructuredIndex(groupMap, pages) {
169
169
  const sections = [];
170
170
  for (const [key, items] of groupMap) {
171
171
  const groupEntry = items.find((i) => i.kind === "group");
@@ -175,10 +175,10 @@ function buildStructuredIndex(tabSlug, groupMap, pages) {
175
175
  continue;
176
176
  const links = [];
177
177
  if (groupEntry) {
178
- links.push(`- [Overview](${tabSlug}/${groupEntry.slug}.html)`);
178
+ links.push(`- [Overview](${groupEntry.slug}.html)`);
179
179
  }
180
180
  for (const t of types) {
181
- links.push(`- [${t.title}](${tabSlug}/${t.slug}.html)`);
181
+ links.push(`- [${t.title}](${t.slug}.html)`);
182
182
  }
183
183
  sections.push(`### ${title}\n\n${links.join("\n")}`);
184
184
  }
@@ -187,7 +187,7 @@ function buildStructuredIndex(tabSlug, groupMap, pages) {
187
187
  /**
188
188
  * Flat: alphabetical list categorized by kind.
189
189
  */
190
- function buildFlatIndex(tabSlug, groupMap) {
190
+ function buildFlatIndex(groupMap) {
191
191
  const byKind = new Map();
192
192
  for (const [, items] of groupMap) {
193
193
  for (const item of items) {
@@ -202,7 +202,7 @@ function buildFlatIndex(tabSlug, groupMap) {
202
202
  const sections = [];
203
203
  for (const [label, items] of byKind) {
204
204
  const sorted = items.sort((a, b) => a.title.localeCompare(b.title));
205
- const links = sorted.map((i) => `- [${i.title}](${tabSlug}/${i.slug}.html)`).join("\n");
205
+ const links = sorted.map((i) => `- [${i.title}](${i.slug}.html)`).join("\n");
206
206
  sections.push(`### ${label}\n\n${links}`);
207
207
  }
208
208
  return renderMarkdown(sections.join("\n\n"));
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Convert an McpSpec (from mcp-parser) into a NormalizedSpec for rendering.
3
+ *
4
+ * This is the bridge between the MCP snapshot format and sourcey's
5
+ * format-agnostic rendering pipeline. Everything downstream (components,
6
+ * search, navigation, themes) works unchanged.
7
+ */
8
+ import type { McpSpec } from "mcp-parser";
9
+ import type { NormalizedSpec } from "./types.js";
10
+ export declare function normalizeMcpSpec(spec: McpSpec): NormalizedSpec;
11
+ //# sourceMappingURL=mcp-normalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-normalizer.d.ts","sourceRoot":"","sources":["../../src/core/mcp-normalizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAoE,MAAM,YAAY,CAAC;AAC5G,OAAO,KAAK,EACV,cAAc,EAUf,MAAM,YAAY,CAAC;AAKpB,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CA+C9D"}