@assistant-ui/mcp-docs-server 0.1.38 → 0.2.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 (258) hide show
  1. package/.docs/organized/code-examples/waterfall.md +11 -12
  2. package/.docs/organized/code-examples/with-a2a.md +18 -13
  3. package/.docs/organized/code-examples/with-ag-ui.md +19 -14
  4. package/.docs/organized/code-examples/{with-ai-sdk-v6.md → with-ai-sdk-v7.md} +34 -23
  5. package/.docs/organized/code-examples/with-artifacts.md +473 -141
  6. package/.docs/organized/code-examples/with-assistant-transport.md +17 -10
  7. package/.docs/organized/code-examples/with-browser-extension.md +17 -10
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +21 -14
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +12 -11
  10. package/.docs/organized/code-examples/with-cloud.md +20 -15
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +19 -12
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +22 -15
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +22 -15
  14. package/.docs/organized/code-examples/with-eve.md +18 -11
  15. package/.docs/organized/code-examples/with-expo.md +35 -52
  16. package/.docs/organized/code-examples/with-external-store.md +18 -13
  17. package/.docs/organized/code-examples/with-ffmpeg.md +20 -15
  18. package/.docs/organized/code-examples/with-generative-ui.md +22 -17
  19. package/.docs/organized/code-examples/with-google-adk.md +18 -11
  20. package/.docs/organized/code-examples/with-heat-graph.md +10 -11
  21. package/.docs/organized/code-examples/with-image-generation.md +19 -12
  22. package/.docs/organized/code-examples/with-interactables.md +21 -17
  23. package/.docs/organized/code-examples/with-langchain.md +19 -12
  24. package/.docs/organized/code-examples/with-langgraph.md +19 -12
  25. package/.docs/organized/code-examples/with-livekit.md +23 -16
  26. package/.docs/organized/code-examples/with-mcp.md +46 -28
  27. package/.docs/organized/code-examples/with-opencode.md +25 -23
  28. package/.docs/organized/code-examples/with-pi.md +54 -19
  29. package/.docs/organized/code-examples/with-react-hook-form.md +21 -16
  30. package/.docs/organized/code-examples/with-react-ink-web.md +9 -9
  31. package/.docs/organized/code-examples/with-react-ink.md +4 -4
  32. package/.docs/organized/code-examples/with-react-router.md +22 -17
  33. package/.docs/organized/code-examples/with-resumable-stream.md +21 -14
  34. package/.docs/organized/code-examples/with-store.md +10 -11
  35. package/.docs/organized/code-examples/with-tanstack.md +19 -13
  36. package/.docs/organized/code-examples/with-tap-runtime.md +18 -13
  37. package/.docs/organized/code-examples/with-virtualized-thread.md +19 -14
  38. package/.docs/raw/docs/(docs)/base-ui.mdx +39 -0
  39. package/.docs/raw/docs/(docs)/cli.mdx +19 -1
  40. package/.docs/raw/docs/(docs)/devtools.mdx +7 -2
  41. package/.docs/raw/docs/(docs)/installation.mdx +15 -1
  42. package/.docs/raw/docs/(docs)/rtl.mdx +2 -4
  43. package/.docs/raw/docs/(reference)/api-reference/generative-ui/a2ui.mdx +40 -0
  44. package/.docs/raw/docs/(reference)/api-reference/generative-ui/actions.mdx +56 -0
  45. package/.docs/raw/docs/(reference)/api-reference/generative-ui/components.mdx +86 -0
  46. package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +22 -1
  47. package/.docs/raw/docs/(reference)/api-reference/generative-ui/json-generative-ui.mdx +42 -0
  48. package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +53 -2
  49. package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +81 -0
  50. package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +86 -0
  51. package/.docs/raw/docs/(reference)/api-reference/generative-ui/tokens.mdx +62 -0
  52. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +19 -420
  53. package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +4 -1
  54. package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +4 -1
  55. package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +25 -2
  56. package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +37 -0
  57. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -9
  58. package/.docs/raw/docs/(reference)/api-reference/overview.mdx +1 -0
  59. package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +14 -31
  60. package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +1 -0
  61. package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +3 -0
  62. package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +2 -0
  63. package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +0 -2
  64. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +12 -9
  65. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +4 -0
  66. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +7 -1
  67. package/.docs/raw/docs/cloud/langgraph.mdx +4 -2
  68. package/.docs/raw/docs/copilots/model-context.mdx +1 -1
  69. package/.docs/raw/docs/copilots/motivation.mdx +1 -1
  70. package/.docs/raw/docs/guides/attachments.mdx +3 -3
  71. package/.docs/raw/docs/guides/branching.mdx +2 -2
  72. package/.docs/raw/docs/guides/chatgpt-subscription.mdx +108 -0
  73. package/.docs/raw/docs/guides/context-api.mdx +89 -111
  74. package/.docs/raw/docs/guides/dictation.mdx +185 -257
  75. package/.docs/raw/docs/guides/editing.mdx +5 -5
  76. package/.docs/raw/docs/guides/electron.mdx +369 -0
  77. package/.docs/raw/docs/guides/index.mdx +20 -0
  78. package/.docs/raw/docs/guides/mentions.mdx +31 -3
  79. package/.docs/raw/docs/guides/quoting.mdx +3 -3
  80. package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +2 -2
  81. package/.docs/raw/docs/guides/resumable-streams.mdx +12 -1
  82. package/.docs/raw/docs/guides/speech.mdx +47 -29
  83. package/.docs/raw/docs/guides/suggestions.mdx +70 -1
  84. package/.docs/raw/docs/guides/voice.mdx +197 -267
  85. package/.docs/raw/docs/ink/hooks.mdx +3 -3
  86. package/.docs/raw/docs/ink/primitives.mdx +49 -8
  87. package/.docs/raw/docs/integrations/auth/better-auth.mdx +2 -2
  88. package/.docs/raw/docs/integrations/auth/clerk.mdx +2 -2
  89. package/.docs/raw/docs/integrations/auth/next-auth.mdx +3 -3
  90. package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +10 -4
  91. package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +3 -3
  92. package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +1 -1
  93. package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +3 -3
  94. package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
  95. package/.docs/raw/docs/integrations/gateways/index.mdx +2 -2
  96. package/.docs/raw/docs/integrations/observability/helicone.mdx +1 -1
  97. package/.docs/raw/docs/integrations/observability/langfuse.mdx +1 -1
  98. package/.docs/raw/docs/integrations/observability/langsmith.mdx +2 -2
  99. package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +36 -9
  100. package/.docs/raw/docs/migrations/index.mdx +50 -0
  101. package/.docs/raw/docs/migrations/toolkit-tools.mdx +4 -2
  102. package/.docs/raw/docs/migrations/v0-15.mdx +156 -0
  103. package/.docs/raw/docs/primitives/chain-of-thought.mdx +6 -1
  104. package/.docs/raw/docs/primitives/composer.mdx +17 -1
  105. package/.docs/raw/docs/primitives/selection-toolbar.mdx +25 -0
  106. package/.docs/raw/docs/primitives/thread-list.mdx +2 -2
  107. package/.docs/raw/docs/react-native/hooks.mdx +3 -3
  108. package/.docs/raw/docs/react-native/index.mdx +2 -2
  109. package/.docs/raw/docs/react-native/primitives.mdx +62 -5
  110. package/.docs/raw/docs/runtimes/ag-ui/agent-state.mdx +124 -0
  111. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +10 -1
  112. package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +14 -5
  113. package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +15 -15
  114. package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +8 -8
  115. package/.docs/raw/docs/runtimes/ai-sdk/{v6.mdx → v6-legacy.mdx} +11 -9
  116. package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +717 -0
  117. package/.docs/raw/docs/runtimes/concepts/adapters.mdx +1 -1
  118. package/.docs/raw/docs/runtimes/concepts/architecture.mdx +1 -1
  119. package/.docs/raw/docs/runtimes/concepts/threads.mdx +10 -10
  120. package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +2 -2
  121. package/.docs/raw/docs/runtimes/custom/data-stream.mdx +10 -19
  122. package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -2
  123. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +5 -3
  124. package/.docs/raw/docs/runtimes/eve/overview.mdx +1 -1
  125. package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
  126. package/.docs/raw/docs/runtimes/langgraph/agent-state.mdx +181 -0
  127. package/.docs/raw/docs/runtimes/langgraph/overview.mdx +1 -1
  128. package/.docs/raw/docs/runtimes/opencode/hooks.mdx +3 -1
  129. package/.docs/raw/docs/tools/a2ui.mdx +107 -0
  130. package/.docs/raw/docs/tools/backend.mdx +6 -3
  131. package/.docs/raw/docs/tools/defining-tools.mdx +7 -1
  132. package/.docs/raw/docs/tools/generative-ui.mdx +60 -2
  133. package/.docs/raw/docs/tools/interactables-legacy.mdx +4 -4
  134. package/.docs/raw/docs/tools/interactables.mdx +3 -3
  135. package/.docs/raw/docs/tools/mcp-apps.mdx +90 -13
  136. package/.docs/raw/docs/tools/mcp.mdx +100 -3
  137. package/.docs/raw/docs/tools/tool-ui.mdx +6 -4
  138. package/.docs/raw/docs/tools/user-managed-mcp.mdx +77 -9
  139. package/.docs/raw/docs/ui/accordion.mdx +16 -10
  140. package/.docs/raw/docs/ui/assistant-modal.mdx +8 -4
  141. package/.docs/raw/docs/ui/attachment.mdx +5 -1
  142. package/.docs/raw/docs/ui/badge.mdx +23 -12
  143. package/.docs/raw/docs/ui/follow-up-suggestions.mdx +4 -2
  144. package/.docs/raw/docs/ui/model-selector.mdx +33 -3
  145. package/.docs/raw/docs/ui/part-grouping.mdx +0 -4
  146. package/.docs/raw/docs/ui/reasoning.mdx +1 -1
  147. package/.docs/raw/docs/ui/select.mdx +22 -14
  148. package/.docs/raw/docs/ui/sources.mdx +1 -1
  149. package/.docs/raw/docs/ui/tabs.mdx +25 -14
  150. package/.docs/raw/docs/utilities/heat-graph.mdx +2 -2
  151. package/dist/constants.d.ts.map +1 -1
  152. package/dist/index.d.ts +1 -2
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.js +41 -2
  155. package/dist/index.js.map +1 -1
  156. package/dist/prepare-docs/code-examples.d.ts.map +1 -1
  157. package/dist/prepare-docs/code-examples.js.map +1 -1
  158. package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
  159. package/dist/prepare-docs/prepare.d.ts +1 -1
  160. package/dist/prompts/xulux-playground.d.ts +12 -0
  161. package/dist/prompts/xulux-playground.d.ts.map +1 -0
  162. package/dist/prompts/xulux-playground.js +33 -0
  163. package/dist/prompts/xulux-playground.js.map +1 -0
  164. package/dist/stdio.d.ts +1 -1
  165. package/dist/tools/docs.d.ts +8 -14
  166. package/dist/tools/docs.d.ts.map +1 -1
  167. package/dist/tools/docs.js +26 -10
  168. package/dist/tools/docs.js.map +1 -1
  169. package/dist/tools/examples.d.ts +6 -12
  170. package/dist/tools/examples.d.ts.map +1 -1
  171. package/dist/tools/examples.js +11 -8
  172. package/dist/tools/examples.js.map +1 -1
  173. package/dist/tools/resources.d.ts +1 -2
  174. package/dist/tools/resources.d.ts.map +1 -1
  175. package/dist/tools/resources.js +1 -1
  176. package/dist/tools/resources.js.map +1 -1
  177. package/dist/tools/search.d.ts +6 -15
  178. package/dist/tools/search.d.ts.map +1 -1
  179. package/dist/tools/search.js +2 -2
  180. package/dist/tools/search.js.map +1 -1
  181. package/dist/tools/tests/mcp-test-client.d.ts +15 -0
  182. package/dist/tools/tests/mcp-test-client.d.ts.map +1 -0
  183. package/dist/tools/tests/mcp-test-client.js +68 -0
  184. package/dist/tools/tests/mcp-test-client.js.map +1 -0
  185. package/dist/tools/tests/test-setup.d.ts.map +1 -1
  186. package/dist/tools/tests/test-setup.js +5 -1
  187. package/dist/tools/tests/test-setup.js.map +1 -1
  188. package/dist/tools/xulux-templates.d.ts +58 -0
  189. package/dist/tools/xulux-templates.d.ts.map +1 -0
  190. package/dist/tools/xulux-templates.js +82 -0
  191. package/dist/tools/xulux-templates.js.map +1 -0
  192. package/dist/utils/cache.d.ts +5 -0
  193. package/dist/utils/cache.d.ts.map +1 -0
  194. package/dist/utils/cache.js +18 -0
  195. package/dist/utils/cache.js.map +1 -0
  196. package/dist/utils/logger.d.ts.map +1 -1
  197. package/dist/utils/mcp-format.d.ts +1 -0
  198. package/dist/utils/mcp-format.d.ts.map +1 -1
  199. package/dist/utils/mcp-format.js +7 -4
  200. package/dist/utils/mcp-format.js.map +1 -1
  201. package/dist/utils/mdx.d.ts.map +1 -1
  202. package/dist/utils/paths.d.ts +1 -1
  203. package/dist/utils/paths.d.ts.map +1 -1
  204. package/dist/utils/paths.js +3 -1
  205. package/dist/utils/paths.js.map +1 -1
  206. package/dist/utils/search.d.ts.map +1 -1
  207. package/dist/utils/security.d.ts.map +1 -1
  208. package/dist/utils/security.js.map +1 -1
  209. package/dist/xulux/catalog-client.d.ts +14 -0
  210. package/dist/xulux/catalog-client.d.ts.map +1 -0
  211. package/dist/xulux/catalog-client.js +67 -0
  212. package/dist/xulux/catalog-client.js.map +1 -0
  213. package/dist/xulux/fallback-catalog.d.ts +7 -0
  214. package/dist/xulux/fallback-catalog.d.ts.map +1 -0
  215. package/dist/xulux/fallback-catalog.js +47 -0
  216. package/dist/xulux/fallback-catalog.js.map +1 -0
  217. package/dist/xulux/fetch-sandbox.d.ts +5 -0
  218. package/dist/xulux/fetch-sandbox.d.ts.map +1 -0
  219. package/dist/xulux/fetch-sandbox.js +40 -0
  220. package/dist/xulux/fetch-sandbox.js.map +1 -0
  221. package/dist/xulux/template-service.d.ts +84 -0
  222. package/dist/xulux/template-service.d.ts.map +1 -0
  223. package/dist/xulux/template-service.js +223 -0
  224. package/dist/xulux/template-service.js.map +1 -0
  225. package/dist/xulux/types.d.ts +55 -0
  226. package/dist/xulux/types.d.ts.map +1 -0
  227. package/dist/xulux/types.js +6 -0
  228. package/dist/xulux/types.js.map +1 -0
  229. package/package.json +7 -6
  230. package/src/index.ts +55 -2
  231. package/src/prompts/xulux-playground.ts +36 -0
  232. package/src/tools/docs.ts +27 -5
  233. package/src/tools/examples.ts +17 -12
  234. package/src/tools/resources.ts +1 -4
  235. package/src/tools/search.ts +2 -2
  236. package/src/tools/tests/completions.test.ts +40 -26
  237. package/src/tools/tests/docs.test.ts +20 -0
  238. package/src/tools/tests/examples.test.ts +5 -5
  239. package/src/tools/tests/integration.test.ts +3 -4
  240. package/src/tools/tests/listings-cache.test.ts +19 -0
  241. package/src/tools/tests/mcp-protocol.test.ts +173 -108
  242. package/src/tools/tests/mcp-test-client.ts +111 -0
  243. package/src/tools/tests/resources.test.ts +97 -66
  244. package/src/tools/tests/test-setup.ts +8 -0
  245. package/src/tools/tests/xulux-templates.test.ts +262 -0
  246. package/src/tools/xulux-templates.ts +141 -0
  247. package/src/utils/cache.ts +20 -0
  248. package/src/utils/mcp-format.ts +8 -6
  249. package/src/utils/paths.ts +4 -1
  250. package/src/utils/tests/cache.test.ts +51 -0
  251. package/src/utils/tests/mcp-format.test.ts +22 -0
  252. package/src/utils/tests/security.test.ts +1 -1
  253. package/src/xulux/catalog-client.ts +105 -0
  254. package/src/xulux/fallback-catalog.ts +63 -0
  255. package/src/xulux/fetch-sandbox.ts +56 -0
  256. package/src/xulux/template-service.ts +406 -0
  257. package/src/xulux/types.ts +60 -0
  258. package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +0 -464
@@ -0,0 +1,68 @@
1
+ import { InMemoryTransport } from "@modelcontextprotocol/server";
2
+ //#region src/tools/tests/mcp-test-client.ts
3
+ function isJsonRpcResponse(message) {
4
+ return typeof message === "object" && message !== null && "id" in message && typeof message.id === "number" && ("result" in message || "error" in message);
5
+ }
6
+ async function createMcpTestClient(server) {
7
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
8
+ const pendingRequests = /* @__PURE__ */ new Map();
9
+ let nextRequestId = 1;
10
+ clientTransport.onmessage = (message) => {
11
+ if (!isJsonRpcResponse(message)) return;
12
+ const pendingRequest = pendingRequests.get(message.id);
13
+ if (!pendingRequest) return;
14
+ pendingRequests.delete(message.id);
15
+ if (message.error) {
16
+ pendingRequest.reject(/* @__PURE__ */ new Error(`MCP request failed (${message.error.code}): ${message.error.message}`));
17
+ return;
18
+ }
19
+ pendingRequest.resolve(message.result);
20
+ };
21
+ await clientTransport.start();
22
+ await server.connect(serverTransport);
23
+ const request = (rawRequest) => {
24
+ const id = nextRequestId++;
25
+ return new Promise((resolve, reject) => {
26
+ pendingRequests.set(id, {
27
+ resolve,
28
+ reject
29
+ });
30
+ clientTransport.send({
31
+ jsonrpc: "2.0",
32
+ id,
33
+ ...rawRequest
34
+ }).catch((error) => {
35
+ pendingRequests.delete(id);
36
+ reject(error instanceof Error ? error : new Error(String(error)));
37
+ });
38
+ });
39
+ };
40
+ return {
41
+ initialize: async () => {
42
+ const result = await request({
43
+ method: "initialize",
44
+ params: {
45
+ protocolVersion: "2025-11-25",
46
+ capabilities: {},
47
+ clientInfo: {
48
+ name: "mcp-docs-server-tests",
49
+ version: "1.0.0"
50
+ }
51
+ }
52
+ });
53
+ await clientTransport.send({
54
+ jsonrpc: "2.0",
55
+ method: "notifications/initialized"
56
+ });
57
+ return result;
58
+ },
59
+ request,
60
+ close: async () => {
61
+ await clientTransport.close();
62
+ }
63
+ };
64
+ }
65
+ //#endregion
66
+ export { createMcpTestClient };
67
+
68
+ //# sourceMappingURL=mcp-test-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-test-client.js","names":[],"sources":["../../../src/tools/tests/mcp-test-client.ts"],"sourcesContent":["import {\n InMemoryTransport,\n type McpServer,\n} from \"@modelcontextprotocol/server\";\n\ntype RawMcpRequest = {\n method: string;\n params?: unknown;\n};\n\ntype JsonRpcResponse = {\n id: number;\n result?: unknown;\n error?: {\n code: number;\n message: string;\n };\n};\n\ntype PendingRequest = {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n};\n\nexport type McpTestClient = {\n initialize: () => Promise<unknown>;\n request: <Result>(request: RawMcpRequest) => Promise<Result>;\n close: () => Promise<void>;\n};\n\nfunction isJsonRpcResponse(message: unknown): message is JsonRpcResponse {\n return (\n typeof message === \"object\" &&\n message !== null &&\n \"id\" in message &&\n typeof message.id === \"number\" &&\n (\"result\" in message || \"error\" in message)\n );\n}\n\nexport async function createMcpTestClient(\n server: McpServer,\n): Promise<McpTestClient> {\n const [clientTransport, serverTransport] =\n InMemoryTransport.createLinkedPair();\n const pendingRequests = new Map<number, PendingRequest>();\n let nextRequestId = 1;\n\n clientTransport.onmessage = (message) => {\n if (!isJsonRpcResponse(message)) return;\n\n const pendingRequest = pendingRequests.get(message.id);\n if (!pendingRequest) return;\n\n pendingRequests.delete(message.id);\n if (message.error) {\n pendingRequest.reject(\n new Error(\n `MCP request failed (${message.error.code}): ${message.error.message}`,\n ),\n );\n return;\n }\n\n pendingRequest.resolve(message.result);\n };\n\n await clientTransport.start();\n await server.connect(serverTransport);\n\n const request = <Result>(rawRequest: RawMcpRequest): Promise<Result> => {\n const id = nextRequestId++;\n\n return new Promise((resolve, reject) => {\n pendingRequests.set(id, { resolve, reject });\n void clientTransport\n .send({ jsonrpc: \"2.0\", id, ...rawRequest })\n .catch((error: unknown) => {\n pendingRequests.delete(id);\n reject(error instanceof Error ? error : new Error(String(error)));\n });\n }) as Promise<Result>;\n };\n\n return {\n initialize: async () => {\n const result = await request({\n method: \"initialize\",\n params: {\n protocolVersion: \"2025-11-25\",\n capabilities: {},\n clientInfo: {\n name: \"mcp-docs-server-tests\",\n version: \"1.0.0\",\n },\n },\n });\n\n await clientTransport.send({\n jsonrpc: \"2.0\",\n method: \"notifications/initialized\",\n });\n\n return result;\n },\n request,\n close: async () => {\n await clientTransport.close();\n },\n };\n}\n"],"mappings":";;AA8BA,SAAS,kBAAkB,SAA8C;CACvE,OACE,OAAO,YAAY,YACnB,YAAY,QACZ,QAAQ,WACR,OAAO,QAAQ,OAAO,aACrB,YAAY,WAAW,WAAW;AAEvC;AAEA,eAAsB,oBACpB,QACwB;CACxB,MAAM,CAAC,iBAAiB,mBACtB,kBAAkB,iBAAiB;CACrC,MAAM,kCAAkB,IAAI,IAA4B;CACxD,IAAI,gBAAgB;CAEpB,gBAAgB,aAAa,YAAY;EACvC,IAAI,CAAC,kBAAkB,OAAO,GAAG;EAEjC,MAAM,iBAAiB,gBAAgB,IAAI,QAAQ,EAAE;EACrD,IAAI,CAAC,gBAAgB;EAErB,gBAAgB,OAAO,QAAQ,EAAE;EACjC,IAAI,QAAQ,OAAO;GACjB,eAAe,uBACb,IAAI,MACF,uBAAuB,QAAQ,MAAM,KAAK,KAAK,QAAQ,MAAM,SAC/D,CACF;GACA;EACF;EAEA,eAAe,QAAQ,QAAQ,MAAM;CACvC;CAEA,MAAM,gBAAgB,MAAM;CAC5B,MAAM,OAAO,QAAQ,eAAe;CAEpC,MAAM,WAAmB,eAA+C;EACtE,MAAM,KAAK;EAEX,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,gBAAgB,IAAI,IAAI;IAAE;IAAS;GAAO,CAAC;GAC3C,gBACG,KAAK;IAAE,SAAS;IAAO;IAAI,GAAG;GAAW,CAAC,CAAC,CAC3C,OAAO,UAAmB;IACzB,gBAAgB,OAAO,EAAE;IACzB,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;GAClE,CAAC;EACL,CAAC;CACH;CAEA,OAAO;EACL,YAAY,YAAY;GACtB,MAAM,SAAS,MAAM,QAAQ;IAC3B,QAAQ;IACR,QAAQ;KACN,iBAAiB;KACjB,cAAc,CAAC;KACf,YAAY;MACV,MAAM;MACN,SAAS;KACX;IACF;GACF,CAAC;GAED,MAAM,gBAAgB,KAAK;IACzB,SAAS;IACT,QAAQ;GACV,CAAC;GAED,OAAO;EACT;EACA;EACA,OAAO,YAAY;GACjB,MAAM,gBAAgB,MAAM;EAC9B;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"test-setup.d.ts","names":[],"sources":["../../../src/tools/tests/test-setup.ts"],"mappings":";cAca,WAAA;2BACkB,IAAA,UAAW,OAAA;AAAA"}
1
+ {"version":3,"file":"test-setup.d.ts","names":[],"sources":["../../../src/tools/tests/test-setup.ts"],"mappings":";cAsBa;EACY,WAAA,cAAM,cAAW"}
@@ -2,6 +2,7 @@ import { PACKAGE_DIR } from "../../constants.js";
2
2
  import { docsTools } from "../docs.js";
3
3
  import { examplesTools } from "../examples.js";
4
4
  import { searchTools } from "../search.js";
5
+ import { xuluxTemplateDetailsTool, xuluxTemplatePreviewTool, xuluxTemplatesListTool } from "../xulux-templates.js";
5
6
  import { join } from "node:path";
6
7
  import { existsSync } from "node:fs";
7
8
  import { beforeAll } from "vitest";
@@ -9,7 +10,10 @@ import { beforeAll } from "vitest";
9
10
  const tools = {
10
11
  assistantUIDocs: docsTools,
11
12
  assistantUIExamples: examplesTools,
12
- assistantUISearch: searchTools
13
+ assistantUISearch: searchTools,
14
+ assistantUITemplates: xuluxTemplatesListTool,
15
+ assistantUITemplateDetails: xuluxTemplateDetailsTool,
16
+ assistantUITemplatePreview: xuluxTemplatePreviewTool
13
17
  };
14
18
  const testContext = { callTool: async (name, args) => {
15
19
  const tool = tools[name];
@@ -1 +1 @@
1
- {"version":3,"file":"test-setup.js","names":[],"sources":["../../../src/tools/tests/test-setup.ts"],"sourcesContent":["import { beforeAll } from \"vitest\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { PACKAGE_DIR } from \"../../constants.js\";\nimport { docsTools } from \"../docs.js\";\nimport { examplesTools } from \"../examples.js\";\nimport { searchTools } from \"../search.js\";\n\nconst tools = {\n assistantUIDocs: docsTools,\n assistantUIExamples: examplesTools,\n assistantUISearch: searchTools,\n};\n\nexport const testContext = {\n callTool: async (name: string, args: any) => {\n const tool = tools[name as keyof typeof tools];\n if (!tool) {\n throw new Error(`Tool ${name} not found`);\n }\n const result = await tool.execute(args);\n\n const text = result.content?.[0]?.text;\n if (text === undefined) {\n throw new Error(`Tool ${name} returned no content`);\n }\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new Error(\n `Tool ${name} returned invalid JSON. Output: ${text}\\nParse error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n};\n\nbeforeAll(() => {\n const docsPath = join(PACKAGE_DIR, \".docs\");\n if (!existsSync(docsPath)) {\n throw new Error(\"Documentation not prepared. Run: pnpm build\");\n }\n});\n"],"mappings":";;;;;;;;AAQA,MAAM,QAAQ;CACZ,iBAAiB;CACjB,qBAAqB;CACrB,mBAAmB;AACrB;AAEA,MAAa,cAAc,EACzB,UAAU,OAAO,MAAc,SAAc;CAC3C,MAAM,OAAO,MAAM;CACnB,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,QAAQ,KAAK,WAAW;CAI1C,MAAM,QAAO,MAFQ,KAAK,QAAQ,IAAI,EAAA,CAElB,UAAU,EAAE,EAAE;CAClC,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,QAAQ,KAAK,qBAAqB;CAEpD,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,MACR,QAAQ,KAAK,kCAAkC,KAAK,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAC5H;CACF;AACF,EACF;AAEA,gBAAgB;CAEd,IAAI,CAAC,WADY,KAAK,aAAa,OACZ,CAAC,GACtB,MAAM,IAAI,MAAM,6CAA6C;AAEjE,CAAC"}
1
+ {"version":3,"file":"test-setup.js","names":[],"sources":["../../../src/tools/tests/test-setup.ts"],"sourcesContent":["import { beforeAll } from \"vitest\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { PACKAGE_DIR } from \"../../constants.js\";\nimport { docsTools } from \"../docs.js\";\nimport { examplesTools } from \"../examples.js\";\nimport { searchTools } from \"../search.js\";\nimport {\n xuluxTemplatesListTool,\n xuluxTemplateDetailsTool,\n xuluxTemplatePreviewTool,\n} from \"../xulux-templates.js\";\n\nconst tools = {\n assistantUIDocs: docsTools,\n assistantUIExamples: examplesTools,\n assistantUISearch: searchTools,\n assistantUITemplates: xuluxTemplatesListTool,\n assistantUITemplateDetails: xuluxTemplateDetailsTool,\n assistantUITemplatePreview: xuluxTemplatePreviewTool,\n};\n\nexport const testContext = {\n callTool: async (name: string, args: any) => {\n const tool = tools[name as keyof typeof tools];\n if (!tool) {\n throw new Error(`Tool ${name} not found`);\n }\n const result = await tool.execute(args);\n\n const text = result.content?.[0]?.text;\n if (text === undefined) {\n throw new Error(`Tool ${name} returned no content`);\n }\n try {\n return JSON.parse(text);\n } catch (error) {\n throw new Error(\n `Tool ${name} returned invalid JSON. Output: ${text}\\nParse error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n};\n\nbeforeAll(() => {\n const docsPath = join(PACKAGE_DIR, \".docs\");\n if (!existsSync(docsPath)) {\n throw new Error(\"Documentation not prepared. Run: pnpm build\");\n }\n});\n"],"mappings":";;;;;;;;;AAaA,MAAM,QAAQ;CACZ,iBAAiB;CACjB,qBAAqB;CACrB,mBAAmB;CACnB,sBAAsB;CACtB,4BAA4B;CAC5B,4BAA4B;AAC9B;AAEA,MAAa,cAAc,EACzB,UAAU,OAAO,MAAc,SAAc;CAC3C,MAAM,OAAO,MAAM;CACnB,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,QAAQ,KAAK,WAAW;CAI1C,MAAM,QAAO,MAFQ,KAAK,QAAQ,IAAI,EAAA,CAElB,UAAU,EAAE,EAAE;CAClC,IAAI,SAAS,KAAA,GACX,MAAM,IAAI,MAAM,QAAQ,KAAK,qBAAqB;CAEpD,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,MACR,QAAQ,KAAK,kCAAkC,KAAK,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAC5H;CACF;AACF,EACF;AAEA,gBAAgB;CAEd,IAAI,CAAC,WADY,KAAK,aAAa,OACZ,CAAC,GACtB,MAAM,IAAI,MAAM,6CAA6C;AAEjE,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ //#region src/tools/xulux-templates.d.ts
3
+ declare const emptyInputSchema: z.ZodObject<{}, z.core.$strip>;
4
+ declare const detailsInputSchema: z.ZodObject<{
5
+ templateId: z.ZodString;
6
+ versionId: z.ZodOptional<z.ZodString>;
7
+ }, z.core.$strip>;
8
+ declare const previewInputSchema: z.ZodObject<{
9
+ templateId: z.ZodString;
10
+ versionId: z.ZodOptional<z.ZodString>;
11
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
12
+ }, z.core.$strip>;
13
+ declare const xuluxTemplatesListTool: {
14
+ name: string;
15
+ description: string;
16
+ parameters: z.ZodObject<{}, z.core.$strip>;
17
+ execute: (_args: z.infer<typeof emptyInputSchema>) => Promise<{
18
+ content: Array<{
19
+ type: "text";
20
+ text: string;
21
+ }>;
22
+ structuredContent?: Record<string, unknown>;
23
+ }>;
24
+ };
25
+ declare const xuluxTemplateDetailsTool: {
26
+ name: string;
27
+ description: string;
28
+ parameters: z.ZodObject<{
29
+ templateId: z.ZodString;
30
+ versionId: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>;
32
+ execute: (args: z.infer<typeof detailsInputSchema>) => Promise<{
33
+ content: Array<{
34
+ type: "text";
35
+ text: string;
36
+ }>;
37
+ structuredContent?: Record<string, unknown>;
38
+ }>;
39
+ };
40
+ declare const xuluxTemplatePreviewTool: {
41
+ name: string;
42
+ description: string;
43
+ parameters: z.ZodObject<{
44
+ templateId: z.ZodString;
45
+ versionId: z.ZodOptional<z.ZodString>;
46
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
47
+ }, z.core.$strip>;
48
+ execute: (args: z.infer<typeof previewInputSchema>) => Promise<{
49
+ content: Array<{
50
+ type: "text";
51
+ text: string;
52
+ }>;
53
+ structuredContent?: Record<string, unknown>;
54
+ }>;
55
+ };
56
+ //#endregion
57
+ export { xuluxTemplateDetailsTool, xuluxTemplatePreviewTool, xuluxTemplatesListTool };
58
+ //# sourceMappingURL=xulux-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xulux-templates.d.ts","names":[],"sources":["../../src/tools/xulux-templates.ts"],"mappings":";;cAUM,kBAAgB,EAAA,cAAA,EAAA,KAAA;cAEhB,oBAAkB,EAAA;;;GAQtB,EAAA,KAAA;cAEI,oBAAkB,EAAA;;;;GActB,EAAA,KAAA;cAeW;;;;EAQY,UAAA,OAAA,EAAE,aAAa,sBAAiB;;;;;;;;cAiB5C;;;;;;;EASW,UAAA,MAAA,EAAE,aAAa,wBAAmB;;;;;;;;cAwB7C;;;;;;;;EASW,UAAA,MAAA,EAAE,aAAa,wBAAmB"}
@@ -0,0 +1,82 @@
1
+ import { logger } from "../utils/logger.js";
2
+ import { formatMCPResponse } from "../utils/mcp-format.js";
3
+ import { getXuluxCatalog } from "../xulux/catalog-client.js";
4
+ import { createTemplatePreview, getTemplateDetails, listTemplates } from "../xulux/template-service.js";
5
+ import { z } from "zod";
6
+ //#region src/tools/xulux-templates.ts
7
+ const emptyInputSchema = z.object({});
8
+ const detailsInputSchema = z.object({
9
+ templateId: z.string().describe("The template id from assistantUITemplates"),
10
+ versionId: z.string().optional().describe("Optional version id. When provided, exampleConfig reflects that version's resolved defaults.")
11
+ });
12
+ const previewInputSchema = z.object({
13
+ templateId: z.string().describe("The template id from assistantUITemplates"),
14
+ versionId: z.string().optional().describe("Version id to use. Uses the template default if omitted."),
15
+ config: z.record(z.string(), z.unknown()).optional().describe("Customization config for the preview. Must contain only the top-level keys: hostUi, assistant, and brandTheme. Use the schemas from assistantUITemplateDetails.configRoots as the source of truth for each root. Do not pass any other root keys.")
16
+ });
17
+ function withDegradedNote(payload, degraded, degradedReason) {
18
+ if (!degraded) return payload;
19
+ return {
20
+ ...payload,
21
+ catalogDegraded: true,
22
+ ...degradedReason ? { catalogDegradedReason: degradedReason } : {}
23
+ };
24
+ }
25
+ const xuluxTemplatesListTool = {
26
+ name: "assistantUITemplates",
27
+ description: "List the available assistant-ui hosted app templates and fixed demos with their features, customizable surfaces, and versions. Call this first for any assistant-ui app-building request. Use the features and customizable fields to decide which template fits. If customizable is empty, the entry is a fixed demo that should be used as-is rather than configured. Call assistantUITemplateDetails on the chosen template before requesting a preview.",
28
+ parameters: emptyInputSchema,
29
+ execute: async (_args) => {
30
+ logger.info("Listing assistant-ui templates");
31
+ try {
32
+ const { catalog, degraded, degradedReason } = await getXuluxCatalog();
33
+ return formatMCPResponse(withDegradedNote(listTemplates(catalog), degraded, degradedReason));
34
+ } catch (error) {
35
+ logger.error("Failed to list assistant-ui templates", error);
36
+ return formatMCPResponse({
37
+ error: "Failed to list assistant-ui templates",
38
+ message: error instanceof Error ? error.message : String(error)
39
+ });
40
+ }
41
+ }
42
+ };
43
+ const xuluxTemplateDetailsTool = {
44
+ name: "assistantUITemplateDetails",
45
+ description: "Get the full authoring surface for a specific assistant-ui hosted template. Returns configRoots schemas (with types, defaults, and enums), rules, built-in tool input/outputShape, renderer contracts, and an exampleConfig. Fixed demos return no configRoots; use those as-is without config. Use this before calling assistantUITemplatePreview to understand exactly what config to write. If assistantUITemplatePreview returns validationWarnings, call this again and cross-reference configRoots to correct the config.",
46
+ parameters: detailsInputSchema,
47
+ execute: async (args) => {
48
+ logger.info(`Getting assistant-ui template details for: ${args.templateId}`);
49
+ try {
50
+ const { catalog, degraded, degradedReason } = await getXuluxCatalog();
51
+ return formatMCPResponse(withDegradedNote(await getTemplateDetails(catalog, args), degraded, degradedReason));
52
+ } catch (error) {
53
+ logger.error("Failed to get assistant-ui template details", error);
54
+ return formatMCPResponse({
55
+ error: "Failed to get assistant-ui template details",
56
+ message: error instanceof Error ? error.message : String(error)
57
+ });
58
+ }
59
+ }
60
+ };
61
+ const xuluxTemplatePreviewTool = {
62
+ name: "assistantUITemplatePreview",
63
+ description: "Return preview and download URLs for a selected assistant-ui hosted template. The previewUrl is a hosted app URL; show it to the user first, or open it with an available browser/in-app-browser tool if your client provides one. If you pass config, a preview session is created on the hosted template sandbox and the returned URLs reflect that configuration. Do not pass config for fixed demos that have no configRoots in assistantUITemplateDetails. This tool only returns URLs.",
64
+ parameters: previewInputSchema,
65
+ execute: async (args) => {
66
+ logger.info(`Creating assistant-ui template preview for: ${args.templateId}`);
67
+ try {
68
+ const { catalog, degraded, degradedReason } = await getXuluxCatalog();
69
+ return formatMCPResponse(withDegradedNote(await createTemplatePreview(catalog, args), degraded, degradedReason));
70
+ } catch (error) {
71
+ logger.error("Failed to create assistant-ui template preview", error);
72
+ return formatMCPResponse({
73
+ error: "Failed to create assistant-ui template preview",
74
+ message: error instanceof Error ? error.message : String(error)
75
+ });
76
+ }
77
+ }
78
+ };
79
+ //#endregion
80
+ export { xuluxTemplateDetailsTool, xuluxTemplatePreviewTool, xuluxTemplatesListTool };
81
+
82
+ //# sourceMappingURL=xulux-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xulux-templates.js","names":[],"sources":["../../src/tools/xulux-templates.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { logger } from \"../utils/logger.js\";\nimport { formatMCPResponse } from \"../utils/mcp-format.js\";\nimport { getXuluxCatalog } from \"../xulux/catalog-client.js\";\nimport {\n createTemplatePreview,\n getTemplateDetails,\n listTemplates,\n} from \"../xulux/template-service.js\";\n\nconst emptyInputSchema = z.object({});\n\nconst detailsInputSchema = z.object({\n templateId: z.string().describe(\"The template id from assistantUITemplates\"),\n versionId: z\n .string()\n .optional()\n .describe(\n \"Optional version id. When provided, exampleConfig reflects that version's resolved defaults.\",\n ),\n});\n\nconst previewInputSchema = z.object({\n templateId: z.string().describe(\"The template id from assistantUITemplates\"),\n versionId: z\n .string()\n .optional()\n .describe(\"Version id to use. Uses the template default if omitted.\"),\n config: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"Customization config for the preview. Must contain only the top-level keys: hostUi, assistant, and brandTheme. \" +\n \"Use the schemas from assistantUITemplateDetails.configRoots as the source of truth for each root. \" +\n \"Do not pass any other root keys.\",\n ),\n});\n\nfunction withDegradedNote<T extends Record<string, unknown>>(\n payload: T,\n degraded: boolean,\n degradedReason?: string,\n): T & { catalogDegraded?: true; catalogDegradedReason?: string } {\n if (!degraded) return payload;\n return {\n ...payload,\n catalogDegraded: true,\n ...(degradedReason ? { catalogDegradedReason: degradedReason } : {}),\n };\n}\n\nexport const xuluxTemplatesListTool = {\n name: \"assistantUITemplates\",\n description:\n \"List the available assistant-ui hosted app templates and fixed demos with their features, customizable surfaces, and versions. \" +\n \"Call this first for any assistant-ui app-building request. Use the features and customizable fields to decide which template fits. \" +\n \"If customizable is empty, the entry is a fixed demo that should be used as-is rather than configured. \" +\n \"Call assistantUITemplateDetails on the chosen template before requesting a preview.\",\n parameters: emptyInputSchema,\n execute: async (_args: z.infer<typeof emptyInputSchema>) => {\n logger.info(\"Listing assistant-ui templates\");\n try {\n const { catalog, degraded, degradedReason } = await getXuluxCatalog();\n return formatMCPResponse(\n withDegradedNote(listTemplates(catalog), degraded, degradedReason),\n );\n } catch (error) {\n logger.error(\"Failed to list assistant-ui templates\", error);\n return formatMCPResponse({\n error: \"Failed to list assistant-ui templates\",\n message: error instanceof Error ? error.message : String(error),\n });\n }\n },\n};\n\nexport const xuluxTemplateDetailsTool = {\n name: \"assistantUITemplateDetails\",\n description:\n \"Get the full authoring surface for a specific assistant-ui hosted template. \" +\n \"Returns configRoots schemas (with types, defaults, and enums), rules, built-in tool input/outputShape, renderer contracts, and an exampleConfig. \" +\n \"Fixed demos return no configRoots; use those as-is without config. \" +\n \"Use this before calling assistantUITemplatePreview to understand exactly what config to write. \" +\n \"If assistantUITemplatePreview returns validationWarnings, call this again and cross-reference configRoots to correct the config.\",\n parameters: detailsInputSchema,\n execute: async (args: z.infer<typeof detailsInputSchema>) => {\n logger.info(\n `Getting assistant-ui template details for: ${args.templateId}`,\n );\n try {\n const { catalog, degraded, degradedReason } = await getXuluxCatalog();\n const details = await getTemplateDetails(catalog, args);\n return formatMCPResponse(\n withDegradedNote(\n details as unknown as Record<string, unknown>,\n degraded,\n degradedReason,\n ),\n );\n } catch (error) {\n logger.error(\"Failed to get assistant-ui template details\", error);\n return formatMCPResponse({\n error: \"Failed to get assistant-ui template details\",\n message: error instanceof Error ? error.message : String(error),\n });\n }\n },\n};\n\nexport const xuluxTemplatePreviewTool = {\n name: \"assistantUITemplatePreview\",\n description:\n \"Return preview and download URLs for a selected assistant-ui hosted template. \" +\n \"The previewUrl is a hosted app URL; show it to the user first, or open it with an available browser/in-app-browser tool if your client provides one. \" +\n \"If you pass config, a preview session is created on the hosted template sandbox and the returned URLs reflect that configuration. \" +\n \"Do not pass config for fixed demos that have no configRoots in assistantUITemplateDetails. \" +\n \"This tool only returns URLs.\",\n parameters: previewInputSchema,\n execute: async (args: z.infer<typeof previewInputSchema>) => {\n logger.info(\n `Creating assistant-ui template preview for: ${args.templateId}`,\n );\n try {\n const { catalog, degraded, degradedReason } = await getXuluxCatalog();\n const result = await createTemplatePreview(catalog, args);\n return formatMCPResponse(\n withDegradedNote(\n result as unknown as Record<string, unknown>,\n degraded,\n degradedReason,\n ),\n );\n } catch (error) {\n logger.error(\"Failed to create assistant-ui template preview\", error);\n return formatMCPResponse({\n error: \"Failed to create assistant-ui template preview\",\n message: error instanceof Error ? error.message : String(error),\n });\n }\n },\n};\n"],"mappings":";;;;;;AAUA,MAAM,mBAAmB,EAAE,OAAO,CAAC,CAAC;AAEpC,MAAM,qBAAqB,EAAE,OAAO;CAClC,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS,2CAA2C;CAC3E,WAAW,EACR,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SACC,8FACF;AACJ,CAAC;AAED,MAAM,qBAAqB,EAAE,OAAO;CAClC,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS,2CAA2C;CAC3E,WAAW,EACR,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,0DAA0D;CACtE,QAAQ,EACL,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAC/B,SAAS,CAAC,CACV,SACC,mPAGF;AACJ,CAAC;AAED,SAAS,iBACP,SACA,UACA,gBACgE;CAChE,IAAI,CAAC,UAAU,OAAO;CACtB,OAAO;EACL,GAAG;EACH,iBAAiB;EACjB,GAAI,iBAAiB,EAAE,uBAAuB,eAAe,IAAI,CAAC;CACpE;AACF;AAEA,MAAa,yBAAyB;CACpC,MAAM;CACN,aACE;CAIF,YAAY;CACZ,SAAS,OAAO,UAA4C;EAC1D,OAAO,KAAK,gCAAgC;EAC5C,IAAI;GACF,MAAM,EAAE,SAAS,UAAU,mBAAmB,MAAM,gBAAgB;GACpE,OAAO,kBACL,iBAAiB,cAAc,OAAO,GAAG,UAAU,cAAc,CACnE;EACF,SAAS,OAAO;GACd,OAAO,MAAM,yCAAyC,KAAK;GAC3D,OAAO,kBAAkB;IACvB,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAChE,CAAC;EACH;CACF;AACF;AAEA,MAAa,2BAA2B;CACtC,MAAM;CACN,aACE;CAKF,YAAY;CACZ,SAAS,OAAO,SAA6C;EAC3D,OAAO,KACL,8CAA8C,KAAK,YACrD;EACA,IAAI;GACF,MAAM,EAAE,SAAS,UAAU,mBAAmB,MAAM,gBAAgB;GAEpE,OAAO,kBACL,iBACE,MAHkB,mBAAmB,SAAS,IAAI,GAIlD,UACA,cACF,CACF;EACF,SAAS,OAAO;GACd,OAAO,MAAM,+CAA+C,KAAK;GACjE,OAAO,kBAAkB;IACvB,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAChE,CAAC;EACH;CACF;AACF;AAEA,MAAa,2BAA2B;CACtC,MAAM;CACN,aACE;CAKF,YAAY;CACZ,SAAS,OAAO,SAA6C;EAC3D,OAAO,KACL,+CAA+C,KAAK,YACtD;EACA,IAAI;GACF,MAAM,EAAE,SAAS,UAAU,mBAAmB,MAAM,gBAAgB;GAEpE,OAAO,kBACL,iBACE,MAHiB,sBAAsB,SAAS,IAAI,GAIpD,UACA,cACF,CACF;EACF,SAAS,OAAO;GACd,OAAO,MAAM,kDAAkD,KAAK;GACpE,OAAO,kBAAkB;IACvB,OAAO;IACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAChE,CAAC;EACH;CACF;AACF"}
@@ -0,0 +1,5 @@
1
+ //#region src/utils/cache.d.ts
2
+ declare function cacheListing(scan: () => Promise<string[]>): () => Promise<string[]>;
3
+ //#endregion
4
+ export { cacheListing };
5
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","names":[],"sources":["../../src/utils/cache.ts"],"mappings":";iBAAgB,aACd,YAAY,0BACL"}
@@ -0,0 +1,18 @@
1
+ //#region src/utils/cache.ts
2
+ function cacheListing(scan) {
3
+ let cache = null;
4
+ return () => {
5
+ if (!cache) cache = scan().then((result) => {
6
+ if (result.length === 0) cache = null;
7
+ return result;
8
+ }, (error) => {
9
+ cache = null;
10
+ throw error;
11
+ });
12
+ return cache;
13
+ };
14
+ }
15
+ //#endregion
16
+ export { cacheListing };
17
+
18
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","names":[],"sources":["../../src/utils/cache.ts"],"sourcesContent":["export function cacheListing(\n scan: () => Promise<string[]>,\n): () => Promise<string[]> {\n let cache: Promise<string[]> | null = null;\n return () => {\n if (!cache) {\n cache = scan().then(\n (result) => {\n if (result.length === 0) cache = null;\n return result;\n },\n (error) => {\n cache = null;\n throw error;\n },\n );\n }\n return cache;\n };\n}\n"],"mappings":";AAAA,SAAgB,aACd,MACyB;CACzB,IAAI,QAAkC;CACtC,aAAa;EACX,IAAI,CAAC,OACH,QAAQ,KAAK,CAAC,CAAC,MACZ,WAAW;GACV,IAAI,OAAO,WAAW,GAAG,QAAQ;GACjC,OAAO;EACT,IACC,UAAU;GACT,QAAQ;GACR,MAAM;EACR,CACF;EAEF,OAAO;CACT;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","names":[],"sources":["../../src/utils/logger.ts"],"mappings":";cAEa,MAAA;8BACY,IAAA;6BAKD,IAAA;8BAKC,IAAA;6BAGD,IAAA;AAAA"}
1
+ {"version":3,"file":"logger.d.ts","names":[],"sources":["../../src/utils/logger.ts"],"mappings":";cAEa;EACM,QAAA,oBAAM;EAKP,OAAA,oBAAM;EAKL,QAAA,oBAAM;EAGP,OAAA,oBAAM"}
@@ -4,6 +4,7 @@ declare function formatMCPResponse(data: any): {
4
4
  type: "text";
5
5
  text: string;
6
6
  }>;
7
+ structuredContent?: Record<string, unknown>;
7
8
  };
8
9
  //#endregion
9
10
  export { formatMCPResponse };
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-format.d.ts","names":[],"sources":["../../src/utils/mcp-format.ts"],"mappings":";iBAAgB,iBAAA,CAAkB,IAAA;EAChC,OAAA,EAAS,KAAK;IAAG,IAAA;IAAc,IAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"mcp-format.d.ts","names":[],"sources":["../../src/utils/mcp-format.ts"],"mappings":";iBAAgB,kBAAkB;EAChC,SAAS;IAAQ;IAAc;;EAC/B,oBAAoB"}
@@ -1,9 +1,12 @@
1
1
  //#region src/utils/mcp-format.ts
2
2
  function formatMCPResponse(data) {
3
- return { content: [{
4
- type: "text",
5
- text: typeof data === "string" ? data : JSON.stringify(data, null, 2)
6
- }] };
3
+ return {
4
+ content: [{
5
+ type: "text",
6
+ text: typeof data === "string" ? data : JSON.stringify(data, null, 2)
7
+ }],
8
+ ...typeof data === "object" && data !== null && !Array.isArray(data) && { structuredContent: data }
9
+ };
7
10
  }
8
11
  //#endregion
9
12
  export { formatMCPResponse };
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-format.js","names":[],"sources":["../../src/utils/mcp-format.ts"],"sourcesContent":["export function formatMCPResponse(data: any): {\n content: Array<{ type: \"text\"; text: string }>;\n} {\n return {\n content: [\n {\n type: \"text\",\n text: typeof data === \"string\" ? data : JSON.stringify(data, null, 2),\n },\n ],\n };\n}\n"],"mappings":";AAAA,SAAgB,kBAAkB,MAEhC;CACA,OAAO,EACL,SAAS,CACP;EACE,MAAM;EACN,MAAM,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;CACtE,CACF,EACF;AACF"}
1
+ {"version":3,"file":"mcp-format.js","names":[],"sources":["../../src/utils/mcp-format.ts"],"sourcesContent":["export function formatMCPResponse(data: any): {\n content: Array<{ type: \"text\"; text: string }>;\n structuredContent?: Record<string, unknown>;\n} {\n const text = typeof data === \"string\" ? data : JSON.stringify(data, null, 2);\n const isStructured =\n typeof data === \"object\" && data !== null && !Array.isArray(data);\n return {\n content: [{ type: \"text\", text }],\n ...(isStructured && {\n structuredContent: data as Record<string, unknown>,\n }),\n };\n}\n"],"mappings":";AAAA,SAAgB,kBAAkB,MAGhC;CAIA,OAAO;EACL,SAAS,CAAC;GAAE,MAAM;GAAQ,MAJf,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;EAI1C,CAAC;EAChC,GAHA,OAAO,SAAS,YAAY,SAAS,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAG5C,EAClB,mBAAmB,KACrB;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"mdx.d.ts","names":[],"sources":["../../src/utils/mdx.ts"],"mappings":";UAKU,UAAA;EACR,OAAA;EACA,WAAA,EAAa,MAAM;EACnB,OAAA;AAAA;AAAA,iBAGoB,WAAA,CACpB,QAAA,WACC,OAAO,CAAC,UAAA;AAAA,iBAsBW,eAAA,CACpB,QAAA,WACC,OAAO,CAAC,UAAA;AAAA,iBAiBK,gBAAA,CAAiB,UAAsB,EAAV,UAAU"}
1
+ {"version":3,"file":"mdx.d.ts","names":[],"sources":["../../src/utils/mdx.ts"],"mappings":";UAKU;EACR;EACA,aAAa;EACb;;iBAGoB,YACpB,mBACC,QAAQ;iBAsBW,gBACpB,mBACC,QAAQ;iBAiBK,iBAAiB,YAAY"}
@@ -4,7 +4,7 @@ declare function listDirContents(dirPath: string): Promise<{
4
4
  files: string[];
5
5
  }>;
6
6
  declare function getAvailablePaths(): Promise<string[]>;
7
- declare function getAvailableDocFiles(): Promise<string[]>;
7
+ declare const getAvailableDocFiles: () => Promise<string[]>;
8
8
  declare function findNearestPaths(requestedPath: string, availablePaths: string[]): string[];
9
9
  declare function pathExists(path: string): Promise<boolean>;
10
10
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","names":[],"sources":["../../src/utils/paths.ts"],"mappings":";iBAYsB,eAAA,CAAgB,OAAA,WAAkB,OAAO;EAC7D,WAAA;EACA,KAAA;AAAA;AAAA,iBA4BoB,iBAAA,IAAqB,OAAO;AAAA,iBA0B5B,oBAAA,IAAwB,OAAO;AAAA,iBAsBrC,gBAAA,CACd,aAAA,UACA,cAAwB;AAAA,iBAoCJ,UAAA,CAAW,IAAA,WAAe,OAAO"}
1
+ {"version":3,"file":"paths.d.ts","names":[],"sources":["../../src/utils/paths.ts"],"mappings":";iBAasB,gBAAgB,kBAAkB;EACtD;EACA;;iBA4BoB,qBAAqB;cA0B9B,4BAAoB;iBAwBjB,iBACd,uBACA;iBAoCoB,WAAW,eAAe"}
@@ -1,5 +1,6 @@
1
1
  import { DOCS_PATH, MDX_EXTENSION } from "../constants.js";
2
2
  import { logger } from "./logger.js";
3
+ import { cacheListing } from "./cache.js";
3
4
  import { extname, join } from "node:path";
4
5
  import { readdir, stat } from "node:fs/promises";
5
6
  //#region src/utils/paths.ts
@@ -42,7 +43,8 @@ async function getAvailablePaths() {
42
43
  await scanDirectory(DOCS_PATH);
43
44
  return paths.sort();
44
45
  }
45
- async function getAvailableDocFiles() {
46
+ const getAvailableDocFiles = cacheListing(scanDocFiles);
47
+ async function scanDocFiles() {
46
48
  const files = [];
47
49
  async function scanDirectory(dir, prefix = "") {
48
50
  const { directories, files: dirFiles } = await listDirContents(dir);
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","names":[],"sources":["../../src/utils/paths.ts"],"sourcesContent":["import { readdir, stat } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\nimport { DOCS_PATH, MDX_EXTENSION, MD_EXTENSION } from \"../constants.js\";\nimport { logger } from \"./logger.js\";\n\nconst SIMILARITY_THRESHOLDS = {\n EXACT_MATCH: 1,\n CONTAINS_MATCH: 0.8,\n PARTIAL_MATCH: 0.5,\n MIN_SUGGESTION: 0.3,\n} as const;\n\nexport async function listDirContents(dirPath: string): Promise<{\n directories: string[];\n files: string[];\n}> {\n try {\n const items = await readdir(dirPath, { withFileTypes: true });\n\n const directories = items\n .filter((item) => item.isDirectory())\n .map((item) => item.name)\n .filter((name) => !name.startsWith(\".\"))\n .sort();\n\n const files = items\n .filter(\n (item) =>\n item.isFile() &&\n (extname(item.name) === MDX_EXTENSION ||\n extname(item.name) === MD_EXTENSION),\n )\n .map((item) => item.name)\n .sort();\n\n return { directories, files };\n } catch (error) {\n logger.error(`Failed to list directory contents: ${dirPath}`, error);\n return { directories: [], files: [] };\n }\n}\n\nexport async function getAvailablePaths(): Promise<string[]> {\n const paths: string[] = [];\n\n async function scanDirectory(\n dir: string,\n prefix: string = \"\",\n ): Promise<void> {\n const { directories, files } = await listDirContents(dir);\n\n for (const file of files) {\n const name = file.replace(MDX_EXTENSION, \"\").replace(MD_EXTENSION, \"\");\n paths.push(prefix ? `${prefix}/${name}` : name);\n }\n\n for (const subdir of directories) {\n const subdirPath = join(dir, subdir);\n const newPrefix = prefix ? `${prefix}/${subdir}` : subdir;\n paths.push(newPrefix);\n await scanDirectory(subdirPath, newPrefix);\n }\n }\n\n await scanDirectory(DOCS_PATH);\n return paths.sort();\n}\n\nexport async function getAvailableDocFiles(): Promise<string[]> {\n const files: string[] = [];\n\n async function scanDirectory(dir: string, prefix = \"\"): Promise<void> {\n const { directories, files: dirFiles } = await listDirContents(dir);\n\n for (const file of dirFiles) {\n if (extname(file) !== MDX_EXTENSION) continue;\n const name = file.replace(MDX_EXTENSION, \"\");\n files.push(prefix ? `${prefix}/${name}` : name);\n }\n\n for (const subdir of directories) {\n const newPrefix = prefix ? `${prefix}/${subdir}` : subdir;\n await scanDirectory(join(dir, subdir), newPrefix);\n }\n }\n\n await scanDirectory(DOCS_PATH);\n return files.sort();\n}\n\nexport function findNearestPaths(\n requestedPath: string,\n availablePaths: string[],\n): string[] {\n const normalizedRequest = requestedPath\n .toLowerCase()\n .replace(/[^a-z0-9]/g, \"\");\n\n const scored = availablePaths.map((path) => {\n const normalizedPath = path.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\n if (normalizedPath.includes(normalizedRequest)) {\n return { path, score: SIMILARITY_THRESHOLDS.EXACT_MATCH };\n }\n\n if (normalizedRequest.includes(normalizedPath)) {\n return { path, score: SIMILARITY_THRESHOLDS.CONTAINS_MATCH };\n }\n\n const overlap = [...normalizedRequest].filter((char) =>\n normalizedPath.includes(char),\n ).length;\n\n return {\n path,\n score:\n (overlap / normalizedRequest.length) *\n SIMILARITY_THRESHOLDS.PARTIAL_MATCH,\n };\n });\n\n return scored\n .filter((item) => item.score > SIMILARITY_THRESHOLDS.MIN_SUGGESTION)\n .sort((a, b) => b.score - a.score)\n .slice(0, 3)\n .map((item) => item.path);\n}\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","names":[],"sources":["../../src/utils/paths.ts"],"sourcesContent":["import { readdir, stat } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\nimport { DOCS_PATH, MDX_EXTENSION, MD_EXTENSION } from \"../constants.js\";\nimport { cacheListing } from \"./cache.js\";\nimport { logger } from \"./logger.js\";\n\nconst SIMILARITY_THRESHOLDS = {\n EXACT_MATCH: 1,\n CONTAINS_MATCH: 0.8,\n PARTIAL_MATCH: 0.5,\n MIN_SUGGESTION: 0.3,\n} as const;\n\nexport async function listDirContents(dirPath: string): Promise<{\n directories: string[];\n files: string[];\n}> {\n try {\n const items = await readdir(dirPath, { withFileTypes: true });\n\n const directories = items\n .filter((item) => item.isDirectory())\n .map((item) => item.name)\n .filter((name) => !name.startsWith(\".\"))\n .sort();\n\n const files = items\n .filter(\n (item) =>\n item.isFile() &&\n (extname(item.name) === MDX_EXTENSION ||\n extname(item.name) === MD_EXTENSION),\n )\n .map((item) => item.name)\n .sort();\n\n return { directories, files };\n } catch (error) {\n logger.error(`Failed to list directory contents: ${dirPath}`, error);\n return { directories: [], files: [] };\n }\n}\n\nexport async function getAvailablePaths(): Promise<string[]> {\n const paths: string[] = [];\n\n async function scanDirectory(\n dir: string,\n prefix: string = \"\",\n ): Promise<void> {\n const { directories, files } = await listDirContents(dir);\n\n for (const file of files) {\n const name = file.replace(MDX_EXTENSION, \"\").replace(MD_EXTENSION, \"\");\n paths.push(prefix ? `${prefix}/${name}` : name);\n }\n\n for (const subdir of directories) {\n const subdirPath = join(dir, subdir);\n const newPrefix = prefix ? `${prefix}/${subdir}` : subdir;\n paths.push(newPrefix);\n await scanDirectory(subdirPath, newPrefix);\n }\n }\n\n await scanDirectory(DOCS_PATH);\n return paths.sort();\n}\n\nexport const getAvailableDocFiles = cacheListing(scanDocFiles);\n\nasync function scanDocFiles(): Promise<string[]> {\n const files: string[] = [];\n\n async function scanDirectory(dir: string, prefix = \"\"): Promise<void> {\n const { directories, files: dirFiles } = await listDirContents(dir);\n\n for (const file of dirFiles) {\n if (extname(file) !== MDX_EXTENSION) continue;\n const name = file.replace(MDX_EXTENSION, \"\");\n files.push(prefix ? `${prefix}/${name}` : name);\n }\n\n for (const subdir of directories) {\n const newPrefix = prefix ? `${prefix}/${subdir}` : subdir;\n await scanDirectory(join(dir, subdir), newPrefix);\n }\n }\n\n await scanDirectory(DOCS_PATH);\n return files.sort();\n}\n\nexport function findNearestPaths(\n requestedPath: string,\n availablePaths: string[],\n): string[] {\n const normalizedRequest = requestedPath\n .toLowerCase()\n .replace(/[^a-z0-9]/g, \"\");\n\n const scored = availablePaths.map((path) => {\n const normalizedPath = path.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\n if (normalizedPath.includes(normalizedRequest)) {\n return { path, score: SIMILARITY_THRESHOLDS.EXACT_MATCH };\n }\n\n if (normalizedRequest.includes(normalizedPath)) {\n return { path, score: SIMILARITY_THRESHOLDS.CONTAINS_MATCH };\n }\n\n const overlap = [...normalizedRequest].filter((char) =>\n normalizedPath.includes(char),\n ).length;\n\n return {\n path,\n score:\n (overlap / normalizedRequest.length) *\n SIMILARITY_THRESHOLDS.PARTIAL_MATCH,\n };\n });\n\n return scored\n .filter((item) => item.score > SIMILARITY_THRESHOLDS.MIN_SUGGESTION)\n .sort((a, b) => b.score - a.score)\n .slice(0, 3)\n .map((item) => item.path);\n}\n\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","names":[],"sources":["../../src/utils/search.ts"],"mappings":";UAkBiB,YAAA;EACf,IAAA;EACA,KAAA;EACA,OAAA;AAAA;AAAA,iBA0FoB,UAAA,CACpB,KAAA,UACA,KAAA,YACC,OAAO,CAAC,YAAA"}
1
+ {"version":3,"file":"search.d.ts","names":[],"sources":["../../src/utils/search.ts"],"mappings":";UAkBiB;EACf;EACA;EACA;;iBA0FoB,WACpB,eACA,iBACC,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","names":[],"sources":["../../src/utils/security.ts"],"mappings":";iBAEgB,YAAA,CAAa,QAAgB"}
1
+ {"version":3,"file":"security.d.ts","names":[],"sources":["../../src/utils/security.ts"],"mappings":";iBAEgB,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","names":[],"sources":["../../src/utils/security.ts"],"sourcesContent":["import path from \"node:path\";\n\nexport function sanitizePath(userPath: string): string {\n if (!userPath || typeof userPath !== \"string\") {\n throw new Error(\"Invalid path: Path must be a non-empty string\");\n }\n\n // Check for traversal patterns before normalization - defense in depth\n if (userPath.includes(\"../\") || userPath.includes(\"..\\\\\")) {\n throw new Error(\"Invalid path: Directory traversal attempt detected\");\n }\n\n const normalized = path.normalize(userPath);\n\n if (path.isAbsolute(normalized)) {\n throw new Error(\"Invalid path: Absolute paths are not allowed\");\n }\n\n const relativePath = path.relative(\"\", normalized);\n\n if (relativePath.startsWith(\"..\")) {\n throw new Error(\"Invalid path: Directory traversal attempt detected\");\n }\n\n if (relativePath.includes(\"..\")) {\n throw new Error(\"Invalid path: Path contains invalid traversal sequences\");\n }\n\n if (relativePath.includes(\"\\0\")) {\n throw new Error(\"Invalid path: Path contains null bytes\");\n }\n\n if (process.platform !== \"win32\") {\n if (normalized.includes(\"\\\\\")) {\n throw new Error(\"Invalid path: Backslashes not allowed\");\n }\n } else {\n if (normalized.includes(\":\") || normalized.startsWith(\"\\\\\\\\\")) {\n throw new Error(\"Invalid path: Path contains invalid Windows characters\");\n }\n }\n\n const segments = relativePath.split(path.sep);\n for (const segment of segments) {\n if (segment.startsWith(\".\") && segment !== \".\") {\n throw new Error(\"Invalid path: Hidden files are not allowed\");\n }\n }\n\n // Always return Unix-style paths for consistency across platforms\n return relativePath.replace(/\\\\/g, \"/\");\n}\n"],"mappings":";;AAEA,SAAgB,aAAa,UAA0B;CACrD,IAAI,CAAC,YAAY,OAAO,aAAa,UACnC,MAAM,IAAI,MAAM,+CAA+C;CAIjE,IAAI,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,MAAM,GACtD,MAAM,IAAI,MAAM,oDAAoD;CAGtE,MAAM,aAAa,KAAK,UAAU,QAAQ;CAE1C,IAAI,KAAK,WAAW,UAAU,GAC5B,MAAM,IAAI,MAAM,8CAA8C;CAGhE,MAAM,eAAe,KAAK,SAAS,IAAI,UAAU;CAEjD,IAAI,aAAa,WAAW,IAAI,GAC9B,MAAM,IAAI,MAAM,oDAAoD;CAGtE,IAAI,aAAa,SAAS,IAAI,GAC5B,MAAM,IAAI,MAAM,yDAAyD;CAG3E,IAAI,aAAa,SAAS,IAAI,GAC5B,MAAM,IAAI,MAAM,wCAAwC;CAG1D,IAAI,QAAQ,aAAa;MACnB,WAAW,SAAS,IAAI,GAC1B,MAAM,IAAI,MAAM,uCAAuC;CAAA,OAGzD,IAAI,WAAW,SAAS,GAAG,KAAK,WAAW,WAAW,MAAM,GAC1D,MAAM,IAAI,MAAM,wDAAwD;CAI5E,MAAM,WAAW,aAAa,MAAM,KAAK,GAAG;CAC5C,KAAK,MAAM,WAAW,UACpB,IAAI,QAAQ,WAAW,GAAG,KAAK,YAAY,KACzC,MAAM,IAAI,MAAM,4CAA4C;CAKhE,OAAO,aAAa,QAAQ,OAAO,GAAG;AACxC"}
1
+ {"version":3,"file":"security.js","names":[],"sources":["../../src/utils/security.ts"],"sourcesContent":["import path from \"node:path\";\n\nexport function sanitizePath(userPath: string): string {\n if (!userPath || typeof userPath !== \"string\") {\n throw new Error(\"Invalid path: Path must be a non-empty string\");\n }\n\n // Check for traversal patterns before normalization - defense in depth\n if (userPath.includes(\"../\") || userPath.includes(\"..\\\\\")) {\n throw new Error(\"Invalid path: Directory traversal attempt detected\");\n }\n\n const normalized = path.normalize(userPath);\n\n if (path.isAbsolute(normalized)) {\n throw new Error(\"Invalid path: Absolute paths are not allowed\");\n }\n\n const relativePath = path.relative(\"\", normalized);\n\n if (relativePath.startsWith(\"..\")) {\n throw new Error(\"Invalid path: Directory traversal attempt detected\");\n }\n\n if (relativePath.includes(\"..\")) {\n throw new Error(\"Invalid path: Path contains invalid traversal sequences\");\n }\n\n if (relativePath.includes(\"\\0\")) {\n throw new Error(\"Invalid path: Path contains null bytes\");\n }\n\n if (process.platform !== \"win32\") {\n if (normalized.includes(\"\\\\\")) {\n throw new Error(\"Invalid path: Backslashes not allowed\");\n }\n } else {\n if (normalized.includes(\":\") || normalized.startsWith(\"\\\\\\\\\")) {\n throw new Error(\"Invalid path: Path contains invalid Windows characters\");\n }\n }\n\n const segments = relativePath.split(path.sep);\n for (const segment of segments) {\n if (segment.startsWith(\".\") && segment !== \".\") {\n throw new Error(\"Invalid path: Hidden files are not allowed\");\n }\n }\n\n // Always return Unix-style paths for consistency across platforms\n return relativePath.replace(/\\\\/g, \"/\");\n}\n"],"mappings":";;AAEA,SAAgB,aAAa,UAA0B;CACrD,IAAI,CAAC,YAAY,OAAO,aAAa,UACnC,MAAM,IAAI,MAAM,+CAA+C;CAIjE,IAAI,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,MAAM,GACtD,MAAM,IAAI,MAAM,oDAAoD;CAGtE,MAAM,aAAa,KAAK,UAAU,QAAQ;CAE1C,IAAI,KAAK,WAAW,UAAU,GAC5B,MAAM,IAAI,MAAM,8CAA8C;CAGhE,MAAM,eAAe,KAAK,SAAS,IAAI,UAAU;CAEjD,IAAI,aAAa,WAAW,IAAI,GAC9B,MAAM,IAAI,MAAM,oDAAoD;CAGtE,IAAI,aAAa,SAAS,IAAI,GAC5B,MAAM,IAAI,MAAM,yDAAyD;CAG3E,IAAI,aAAa,SAAS,IAAI,GAC5B,MAAM,IAAI,MAAM,wCAAwC;CAG1D,IAAI,QAAQ,aAAa,SACnB;MAAA,WAAW,SAAS,IAAI,GAC1B,MAAM,IAAI,MAAM,uCAAuC;CAAA,OAGzD,IAAI,WAAW,SAAS,GAAG,KAAK,WAAW,WAAW,MAAM,GAC1D,MAAM,IAAI,MAAM,wDAAwD;CAI5E,MAAM,WAAW,aAAa,MAAM,KAAK,GAAG;CAC5C,KAAK,MAAM,WAAW,UACpB,IAAI,QAAQ,WAAW,GAAG,KAAK,YAAY,KACzC,MAAM,IAAI,MAAM,4CAA4C;CAKhE,OAAO,aAAa,QAAQ,OAAO,GAAG;AACxC"}
@@ -0,0 +1,14 @@
1
+ import { XuluxCatalogResult } from "./types.js";
2
+ //#region src/xulux/catalog-client.d.ts
3
+ declare const DEFAULT_CATALOG_URL = "https://www.assistant-ui.com/api/xulux/mcp-catalog";
4
+ declare function getCatalogUrl(): string;
5
+ declare function clearCatalogCache(): void;
6
+ /**
7
+ * Returns the assistant-ui template catalog. Uses an in-memory five-minute cache, and falls
8
+ * back to a minimal bundled catalog (marked degraded) when the live fetch
9
+ * fails and no cached copy exists.
10
+ */
11
+ declare function getXuluxCatalog(): Promise<XuluxCatalogResult>;
12
+ //#endregion
13
+ export { DEFAULT_CATALOG_URL, clearCatalogCache, getCatalogUrl, getXuluxCatalog };
14
+ //# sourceMappingURL=catalog-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-client.d.ts","names":[],"sources":["../../src/xulux/catalog-client.ts"],"mappings":";;cAIa;iBAKG;iBA0CA;;;;;;iBAoBM,mBAAmB,QAAQ"}
@@ -0,0 +1,67 @@
1
+ import { logger } from "../utils/logger.js";
2
+ import { FALLBACK_CATALOG, FALLBACK_NOTE } from "./fallback-catalog.js";
3
+ //#region src/xulux/catalog-client.ts
4
+ const DEFAULT_CATALOG_URL = "https://www.assistant-ui.com/api/xulux/mcp-catalog";
5
+ const CATALOG_TTL_MS = 300 * 1e3;
6
+ function getCatalogUrl() {
7
+ return process.env.XULUX_CATALOG_URL?.trim() || "https://www.assistant-ui.com/api/xulux/mcp-catalog";
8
+ }
9
+ function validateCatalog(data) {
10
+ if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error("Catalog response is not a JSON object.");
11
+ const catalog = data;
12
+ if (catalog.version !== 1) throw new Error(`Unsupported catalog version: ${String(catalog.version)}. Expected 1.`);
13
+ if (!Array.isArray(catalog.templates)) throw new Error("Catalog response has no templates array.");
14
+ for (const template of catalog.templates) if (!template || typeof template !== "object" || typeof template.id !== "string" || typeof template.templateId !== "string" || template.kind !== "template" && template.kind !== "example") throw new Error("Catalog response contains a malformed template entry (missing id/templateId/kind).");
15
+ return catalog;
16
+ }
17
+ let cache = null;
18
+ function clearCatalogCache() {
19
+ cache = null;
20
+ }
21
+ async function fetchCatalog(url) {
22
+ const res = await fetch(url, { headers: { Accept: "application/json" } });
23
+ if (!res.ok) throw new Error(`Catalog fetch failed: HTTP ${res.status}`);
24
+ return validateCatalog(await res.json());
25
+ }
26
+ /**
27
+ * Returns the assistant-ui template catalog. Uses an in-memory five-minute cache, and falls
28
+ * back to a minimal bundled catalog (marked degraded) when the live fetch
29
+ * fails and no cached copy exists.
30
+ */
31
+ async function getXuluxCatalog() {
32
+ const url = getCatalogUrl();
33
+ const now = Date.now();
34
+ if (cache && cache.url === url && now - cache.fetchedAt < CATALOG_TTL_MS) return {
35
+ catalog: cache.catalog,
36
+ degraded: false
37
+ };
38
+ try {
39
+ const catalog = await fetchCatalog(url);
40
+ cache = {
41
+ catalog,
42
+ fetchedAt: now,
43
+ url
44
+ };
45
+ return {
46
+ catalog,
47
+ degraded: false
48
+ };
49
+ } catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ logger.warn(`assistant-ui template catalog fetch failed (${url}): ${message}`);
52
+ if (cache && cache.url === url) return {
53
+ catalog: cache.catalog,
54
+ degraded: true,
55
+ degradedReason: `Live catalog refresh failed (${message}); using previously fetched catalog.`
56
+ };
57
+ return {
58
+ catalog: FALLBACK_CATALOG,
59
+ degraded: true,
60
+ degradedReason: `${message} ${FALLBACK_NOTE}`
61
+ };
62
+ }
63
+ }
64
+ //#endregion
65
+ export { DEFAULT_CATALOG_URL, clearCatalogCache, getCatalogUrl, getXuluxCatalog };
66
+
67
+ //# sourceMappingURL=catalog-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-client.js","names":[],"sources":["../../src/xulux/catalog-client.ts"],"sourcesContent":["import { logger } from \"../utils/logger.js\";\nimport { FALLBACK_CATALOG, FALLBACK_NOTE } from \"./fallback-catalog.js\";\nimport type { XuluxCatalog, XuluxCatalogResult } from \"./types.js\";\n\nexport const DEFAULT_CATALOG_URL =\n \"https://www.assistant-ui.com/api/xulux/mcp-catalog\";\n\nconst CATALOG_TTL_MS = 5 * 60 * 1000;\n\nexport function getCatalogUrl(): string {\n const override = process.env.XULUX_CATALOG_URL?.trim();\n return override || DEFAULT_CATALOG_URL;\n}\n\nfunction validateCatalog(data: unknown): XuluxCatalog {\n if (!data || typeof data !== \"object\" || Array.isArray(data)) {\n throw new Error(\"Catalog response is not a JSON object.\");\n }\n const catalog = data as XuluxCatalog;\n if (catalog.version !== 1) {\n throw new Error(\n `Unsupported catalog version: ${String(catalog.version)}. Expected 1.`,\n );\n }\n if (!Array.isArray(catalog.templates)) {\n throw new Error(\"Catalog response has no templates array.\");\n }\n for (const template of catalog.templates) {\n if (\n !template ||\n typeof template !== \"object\" ||\n typeof template.id !== \"string\" ||\n typeof template.templateId !== \"string\" ||\n (template.kind !== \"template\" && template.kind !== \"example\")\n ) {\n throw new Error(\n \"Catalog response contains a malformed template entry (missing id/templateId/kind).\",\n );\n }\n }\n return catalog;\n}\n\ninterface CacheEntry {\n catalog: XuluxCatalog;\n fetchedAt: number;\n url: string;\n}\n\nlet cache: CacheEntry | null = null;\n\nexport function clearCatalogCache(): void {\n cache = null;\n}\n\nasync function fetchCatalog(url: string): Promise<XuluxCatalog> {\n const res = await fetch(url, {\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) {\n throw new Error(`Catalog fetch failed: HTTP ${res.status}`);\n }\n const data: unknown = await res.json();\n return validateCatalog(data);\n}\n\n/**\n * Returns the assistant-ui template catalog. Uses an in-memory five-minute cache, and falls\n * back to a minimal bundled catalog (marked degraded) when the live fetch\n * fails and no cached copy exists.\n */\nexport async function getXuluxCatalog(): Promise<XuluxCatalogResult> {\n const url = getCatalogUrl();\n const now = Date.now();\n\n if (cache && cache.url === url && now - cache.fetchedAt < CATALOG_TTL_MS) {\n return { catalog: cache.catalog, degraded: false };\n }\n\n try {\n const catalog = await fetchCatalog(url);\n cache = { catalog, fetchedAt: now, url };\n return { catalog, degraded: false };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn(\n `assistant-ui template catalog fetch failed (${url}): ${message}`,\n );\n\n // Prefer a stale cached copy over the minimal fallback.\n if (cache && cache.url === url) {\n return {\n catalog: cache.catalog,\n degraded: true,\n degradedReason: `Live catalog refresh failed (${message}); using previously fetched catalog.`,\n };\n }\n\n return {\n catalog: FALLBACK_CATALOG,\n degraded: true,\n degradedReason: `${message} ${FALLBACK_NOTE}`,\n };\n }\n}\n"],"mappings":";;;AAIA,MAAa,sBACX;AAEF,MAAM,iBAAiB,MAAS;AAEhC,SAAgB,gBAAwB;CAEtC,OADiB,QAAQ,IAAI,mBAAmB,KAAK,KAAA;AAEvD;AAEA,SAAS,gBAAgB,MAA6B;CACpD,IAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GACzD,MAAM,IAAI,MAAM,wCAAwC;CAE1D,MAAM,UAAU;CAChB,IAAI,QAAQ,YAAY,GACtB,MAAM,IAAI,MACR,gCAAgC,OAAO,QAAQ,OAAO,EAAE,cAC1D;CAEF,IAAI,CAAC,MAAM,QAAQ,QAAQ,SAAS,GAClC,MAAM,IAAI,MAAM,0CAA0C;CAE5D,KAAK,MAAM,YAAY,QAAQ,WAC7B,IACE,CAAC,YACD,OAAO,aAAa,YACpB,OAAO,SAAS,OAAO,YACvB,OAAO,SAAS,eAAe,YAC9B,SAAS,SAAS,cAAc,SAAS,SAAS,WAEnD,MAAM,IAAI,MACR,oFACF;CAGJ,OAAO;AACT;AAQA,IAAI,QAA2B;AAE/B,SAAgB,oBAA0B;CACxC,QAAQ;AACV;AAEA,eAAe,aAAa,KAAoC;CAC9D,MAAM,MAAM,MAAM,MAAM,KAAK,EAC3B,SAAS,EAAE,QAAQ,mBAAmB,EACxC,CAAC;CACD,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,8BAA8B,IAAI,QAAQ;CAG5D,OAAO,gBAAgB,MADK,IAAI,KAAK,CACV;AAC7B;;;;;;AAOA,eAAsB,kBAA+C;CACnE,MAAM,MAAM,cAAc;CAC1B,MAAM,MAAM,KAAK,IAAI;CAErB,IAAI,SAAS,MAAM,QAAQ,OAAO,MAAM,MAAM,YAAY,gBACxD,OAAO;EAAE,SAAS,MAAM;EAAS,UAAU;CAAM;CAGnD,IAAI;EACF,MAAM,UAAU,MAAM,aAAa,GAAG;EACtC,QAAQ;GAAE;GAAS,WAAW;GAAK;EAAI;EACvC,OAAO;GAAE;GAAS,UAAU;EAAM;CACpC,SAAS,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,OAAO,KACL,+CAA+C,IAAI,KAAK,SAC1D;EAGA,IAAI,SAAS,MAAM,QAAQ,KACzB,OAAO;GACL,SAAS,MAAM;GACf,UAAU;GACV,gBAAgB,gCAAgC,QAAQ;EAC1D;EAGF,OAAO;GACL,SAAS;GACT,UAAU;GACV,gBAAgB,GAAG,QAAQ,GAAG;EAChC;CACF;AACF"}
@@ -0,0 +1,7 @@
1
+ import { XuluxCatalog } from "./types.js";
2
+ //#region src/xulux/fallback-catalog.d.ts
3
+ declare const FALLBACK_NOTE: string;
4
+ declare const FALLBACK_CATALOG: XuluxCatalog;
5
+ //#endregion
6
+ export { FALLBACK_CATALOG, FALLBACK_NOTE };
7
+ //# sourceMappingURL=fallback-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback-catalog.d.ts","names":[],"sources":["../../src/xulux/fallback-catalog.ts"],"mappings":";;cAWa;cAiBA,kBAAkB"}
@@ -0,0 +1,47 @@
1
+ import "./types.js";
2
+ //#region src/xulux/fallback-catalog.ts
3
+ const FALLBACK_NOTE = "The live assistant-ui template catalog could not be fetched, so this is minimal bundled fallback data. Template details, previews, and downloads require live catalog access. Check network access to the docs site or set XULUX_CATALOG_URL to a reachable catalog endpoint.";
4
+ const fallbackTemplate = (overrides) => ({
5
+ templateId: overrides.id,
6
+ versionId: null,
7
+ assistantPlacement: "unavailable in fallback mode",
8
+ features: [],
9
+ customizable: [],
10
+ versions: [],
11
+ ...overrides
12
+ });
13
+ const FALLBACK_CATALOG = {
14
+ version: 1,
15
+ generatedAt: "fallback",
16
+ docsOrigin: "https://www.assistant-ui.com",
17
+ templates: [
18
+ fallbackTemplate({
19
+ id: "base-assistant-ui",
20
+ kind: "template",
21
+ name: "Configurable Base Assistant UI",
22
+ summary: "Hosted configurable assistant-ui Base chat template with threads, composer, suggestions, and no-key demo flows."
23
+ }),
24
+ fallbackTemplate({
25
+ id: "webpage-assistant",
26
+ kind: "template",
27
+ name: "Webpage with Assistant",
28
+ summary: "Docs/website layout with a sidebar or modal assistant grounded in configurable pages."
29
+ }),
30
+ fallbackTemplate({
31
+ id: "product-page-assistant",
32
+ kind: "template",
33
+ name: "Product Page with Floating Assistant",
34
+ summary: "Mock product dashboard with a floating modal support assistant and analyze-then-handoff flow."
35
+ }),
36
+ fallbackTemplate({
37
+ id: "expo-react-native",
38
+ kind: "example",
39
+ name: "Expo React Native Assistant",
40
+ summary: "Mobile AI chat app built with Expo and assistant-ui React Native primitives."
41
+ })
42
+ ]
43
+ };
44
+ //#endregion
45
+ export { FALLBACK_CATALOG, FALLBACK_NOTE };
46
+
47
+ //# sourceMappingURL=fallback-catalog.js.map