@wix/mcp 1.0.93 → 1.0.95
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.
- package/README.md +2 -2
- package/build/bin-standalone.js +1200 -455
- package/build/cjs/index.cjs +3237 -1264
- package/build/cjs/toolkit.cjs +2177 -469
- package/build/dts/api-call/headless-release.d.ts +56 -0
- package/build/dts/api-call/headless-release.js +135 -0
- package/build/dts/api-call/index.d.ts +9 -1
- package/build/dts/api-call/index.js +19 -10
- package/build/dts/api-call/site-files.d.ts +42 -0
- package/build/dts/api-call/site-files.js +290 -0
- package/build/dts/api-call/upload-headless-website-files.d.ts +118 -0
- package/build/dts/api-call/upload-headless-website-files.js +624 -0
- package/build/dts/api-call/upload-image-tool.d.ts +2 -0
- package/build/dts/api-call/upload-image-tool.js +8 -4
- package/build/dts/bin.d.ts +1 -1
- package/build/dts/bin.js +4 -5
- package/build/dts/code-mode/attachments.js +1 -1
- package/build/dts/code-mode/index.d.ts +6 -1
- package/build/dts/code-mode/index.js +47 -13
- package/build/dts/code-mode/truncate-response.js +5 -1
- package/build/dts/config/default-config.d.ts +35 -9
- package/build/dts/config/default-config.js +348 -207
- package/build/dts/config/file-params.d.ts +22 -0
- package/build/dts/config/file-params.js +24 -0
- package/build/dts/config/param-descriptions.d.ts +14 -2
- package/build/dts/config/param-descriptions.js +34 -15
- package/build/dts/constants.d.ts +1 -0
- package/build/dts/constants.js +1 -0
- package/build/dts/docs/docs.d.ts +16 -3
- package/build/dts/docs/docs.js +211 -39
- package/build/dts/docs/fetch-article.d.ts +21 -0
- package/build/dts/docs/fetch-article.js +70 -5
- package/build/dts/docs/get-to-know.d.ts +7 -2
- package/build/dts/docs/get-to-know.js +37 -15
- package/build/dts/docs/mintlify-docs.d.ts +121 -0
- package/build/dts/docs/mintlify-docs.js +391 -0
- package/build/dts/docs/semanticSearch.d.ts +2 -1
- package/build/dts/docs/semanticSearch.js +14 -7
- package/build/dts/docs/start-deploy-website.d.ts +7 -6
- package/build/dts/docs/start-deploy-website.js +13 -8
- package/build/dts/docs/start-headless-build.d.ts +17 -0
- package/build/dts/docs/start-headless-build.js +60 -0
- package/build/dts/graphql/index.js +3 -1
- package/build/dts/import-claude-design-tool/index.js +2 -2
- package/build/dts/index.d.ts +3 -2
- package/build/dts/index.js +3 -2
- package/build/dts/infra/redact-personal-data.d.ts +4 -0
- package/build/dts/infra/redact-personal-data.js +79 -0
- package/build/dts/site-widget-tools/constants.d.ts +49 -1
- package/build/dts/site-widget-tools/constants.js +64 -7
- package/build/dts/site-widget-tools/index.d.ts +1 -0
- package/build/dts/site-widget-tools/index.js +1 -0
- package/build/dts/site-widget-tools/pick-images-tool/index.d.ts +14 -0
- package/build/dts/site-widget-tools/pick-images-tool/index.js +138 -0
- package/build/dts/site-widget-tools/search-site-templates-tool/index.js +33 -9
- package/build/dts/site-widget-tools/site-builder-tool/index.js +22 -2
- package/build/dts/site-widget-tools/site-creation-tool/index.d.ts +7 -1
- package/build/dts/site-widget-tools/site-creation-tool/index.js +22 -51
- package/build/dts/site-widget-tools/suggested-domain-tool/index.js +6 -3
- package/build/dts/support/index.d.ts +4 -0
- package/build/dts/support/index.js +13 -7
- package/build/dts/toolkit-entry.d.cts +19 -12
- package/build/dts/toolkit-entry.d.ts +19 -12
- package/build/dts/toolkit.d.ts +2 -2
- package/build/dts/toolkit.js +23 -7
- package/build/dts/wix-mcp-server.d.ts +11 -0
- package/build/dts/wix-mcp-server.js +28 -6
- package/build/dts/wixel/constants.d.ts +8 -1
- package/build/dts/wixel/constants.js +8 -1
- package/build/dts/wixel/index.d.ts +1 -1
- package/build/dts/wixel/index.js +2 -2
- package/build/dts/wixel/wixel-a2a-client.d.ts +83 -0
- package/build/dts/wixel/wixel-a2a-client.js +166 -0
- package/build/dts/wixel/wixel-bi.d.ts +2 -1
- package/build/dts/wixel/wixel-bi.js +2 -1
- package/build/dts/wixel/{external-agent-api.d.ts → wixel-session-entries.d.ts} +11 -33
- package/build/dts/wixel/{external-agent-api.js → wixel-session-entries.js} +33 -54
- package/build/dts/wixel/wixel-session-tools.d.ts +21 -26
- package/build/dts/wixel/wixel-session-tools.js +494 -599
- package/build/esm/index.js +3335 -1376
- package/build/esm/toolkit.js +2273 -565
- package/package.json +4 -4
- package/build/dts/docs/create-site-guide.d.ts +0 -3
- package/build/dts/docs/create-site-guide.js +0 -109
package/build/dts/docs/docs.js
CHANGED
|
@@ -2,15 +2,16 @@ import { z } from 'zod';
|
|
|
2
2
|
import { runSemanticSearchAndFormat } from './semanticSearch.js';
|
|
3
3
|
import { logger } from '../infra/logger.js';
|
|
4
4
|
import { captureException } from '@sentry/node';
|
|
5
|
-
import { fetchArticleContent, isSkillsRegistryUrl } from './fetch-article.js';
|
|
5
|
+
import { fetchArticleContent, fetchSourceContent, isSkillsRegistryUrl, parseSourceContentUrl } from './fetch-article.js';
|
|
6
6
|
import { normalizeMenuContent, summarizeLargeMenu, fetchMenuContent, MENU_CONTENT_THRESHOLD } from './normalize-menu-content.js';
|
|
7
7
|
import { fetchPlatformizedMenu, MenuNotFoundError } from './browse-menu.js';
|
|
8
8
|
import { isQueryOrSearchEndpoint, QUERY_CAPABILITY_MARKER } from './searchFormatting.js';
|
|
9
9
|
import { addGetToKnowTools, addGetSiteContextTool } from './get-to-know.js';
|
|
10
|
-
import {
|
|
10
|
+
import { addStartHeadlessBuildTool } from './start-headless-build.js';
|
|
11
11
|
import { addStartDeployWebsiteTool } from './start-deploy-website.js';
|
|
12
|
-
import { defaultToolDescriptions } from '../config/default-config.js';
|
|
13
|
-
import { desc } from '../config/param-descriptions.js';
|
|
12
|
+
import { defaultToolDescriptions, HELP_CENTER_IS_FOR_PEOPLE } from '../config/default-config.js';
|
|
13
|
+
import { desc as paramDescriptionsOf } from '../config/param-descriptions.js';
|
|
14
|
+
import { isMintlifyDocsSite, isMintlifyUrl, MINTLIFY_URL_PREFIXES, mintlifyDocumentTypes, readMintlifyMarkdown, rewriteDocsLinks, toDevWixUrl, toMintlifyHostText } from './mintlify-docs.js';
|
|
14
15
|
import dedent from 'dedent';
|
|
15
16
|
export const VALID_DOCS_TOOLS = [
|
|
16
17
|
'WDS',
|
|
@@ -21,7 +22,8 @@ export const VALID_DOCS_TOOLS = [
|
|
|
21
22
|
'VELO',
|
|
22
23
|
'BUSINESS_SOLUTIONS',
|
|
23
24
|
'CLI',
|
|
24
|
-
'OVERVIEW'
|
|
25
|
+
'OVERVIEW',
|
|
26
|
+
'HELP_CENTER'
|
|
25
27
|
];
|
|
26
28
|
const REST_SEARCH_API_GROUNDING_REMINDER = dedent `
|
|
27
29
|
# Before calling a Wix API
|
|
@@ -66,18 +68,59 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
66
68
|
'WIX_HEADLESS',
|
|
67
69
|
'BUSINESS_SOLUTIONS',
|
|
68
70
|
'CLI',
|
|
69
|
-
'OVERVIEW'
|
|
71
|
+
'OVERVIEW',
|
|
72
|
+
'HELP_CENTER'
|
|
70
73
|
], options = {}) => {
|
|
71
|
-
const { getToKnowWixEnabled = false,
|
|
74
|
+
const { getToKnowWixEnabled = false, startDeployWebsiteEnabled = true, startHeadlessBuildEnabled = true, disableTools, toolDescriptions, readmeDocs, authStrategy, skillsPortalUrl, skillsRepo, repo, skillsPr, commitHash, skillsTags, readmeRecipesIndexEnabled, dynamicContextEnabled, includeCompanionApp, usePlatformizedSearch = true, usePlatformizedBrowse = true, docsSite } = options;
|
|
72
75
|
const effectiveRepo = repo ?? skillsRepo;
|
|
73
76
|
const effectiveCommitHash = commitHash ?? skillsPr;
|
|
77
|
+
// Mintlify docs: search as today, then resolve the links in the results.
|
|
78
|
+
const mintlifyDocs = isMintlifyDocsSite(docsSite);
|
|
79
|
+
const runSearch = mintlifyDocs
|
|
80
|
+
? async (params) => {
|
|
81
|
+
// Stage 2 (docsSite=mintlify): REST and SDK search the Mintlify KBs.
|
|
82
|
+
const documentTypes = mintlifyDocumentTypes(docsSite, params.toolName);
|
|
83
|
+
const result = await runSemanticSearchAndFormat(documentTypes ? { ...params, documentTypes } : params);
|
|
84
|
+
return (await rewriteDocsLinks(result, { label: `search ${params.toolName}` })).text;
|
|
85
|
+
}
|
|
86
|
+
: runSemanticSearchAndFormat;
|
|
87
|
+
const docsUrlPrefixes = mintlifyDocs
|
|
88
|
+
? ['https://dev.wix.com/docs/', ...MINTLIFY_URL_PREFIXES]
|
|
89
|
+
: ['https://dev.wix.com/docs/'];
|
|
90
|
+
// The backends only know dev.wix.com; Mintlify paths map back one to one.
|
|
91
|
+
const toBackendUrl = (url) => mintlifyDocs && isMintlifyUrl(url) ? toDevWixUrl(url) : url;
|
|
92
|
+
// Mintlify docs: a separate text block naming where a read's content came from.
|
|
93
|
+
const sourceNote = (source) => mintlifyDocs
|
|
94
|
+
? [{ type: 'text', text: `[docs source] ${source}` }]
|
|
95
|
+
: [];
|
|
96
|
+
// Mintlify docs: tool and parameter texts show docs URLs on the Mintlify host, or
|
|
97
|
+
// the model cites dev.wix.com (it copies the examples' host into answers).
|
|
98
|
+
const docsText = (text) => mintlifyDocs ? toMintlifyHostText(text) : text;
|
|
99
|
+
const desc = (toolName) => {
|
|
100
|
+
const descriptions = paramDescriptionsOf(toolName);
|
|
101
|
+
if (!mintlifyDocs)
|
|
102
|
+
return descriptions;
|
|
103
|
+
return Object.fromEntries(Object.entries(descriptions).map(([param, text]) => [
|
|
104
|
+
param,
|
|
105
|
+
docsText(text)
|
|
106
|
+
]));
|
|
107
|
+
};
|
|
74
108
|
// Helper to get description (custom or default)
|
|
75
|
-
const getDescription = (toolName, defaultDesc) => toolDescriptions?.[toolName] ?? defaultDesc;
|
|
109
|
+
const getDescription = (toolName, defaultDesc) => docsText(toolDescriptions?.[toolName] ?? defaultDesc);
|
|
76
110
|
// Menu text for a docs URL, shared by BrowseWixRESTDocsMenu and the
|
|
77
111
|
// ReadFullDocs* category fallbacks. Platformized browse first — its 404 is a
|
|
78
112
|
// real answer (null, no such menu); any other failure falls back to the
|
|
79
113
|
// legacy get-menu-content scrape, which keeps its original thresholding.
|
|
80
114
|
const fetchMenuTextForUrl = async (httpClient, url) => {
|
|
115
|
+
const text = await fetchMenuTextForBackendUrl(httpClient, toBackendUrl(url));
|
|
116
|
+
if (!text || !mintlifyDocs)
|
|
117
|
+
return text;
|
|
118
|
+
// Menu links are Portal Service nodes, the same tree the Mintlify
|
|
119
|
+
// navigation is built from, so they map by rule without a page check.
|
|
120
|
+
return (await rewriteDocsLinks(text, { verify: false, label: 'menu' }))
|
|
121
|
+
.text;
|
|
122
|
+
};
|
|
123
|
+
const fetchMenuTextForBackendUrl = async (httpClient, url) => {
|
|
81
124
|
if (usePlatformizedBrowse) {
|
|
82
125
|
try {
|
|
83
126
|
return await fetchPlatformizedMenu(url);
|
|
@@ -96,16 +139,36 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
96
139
|
? summarizeLargeMenu(menuContent, url)
|
|
97
140
|
: normalizeMenuContent(menuContent);
|
|
98
141
|
};
|
|
142
|
+
// The two site-creation guides register first, so they head the tool list: an agent that
|
|
143
|
+
// loads every definition at once and gets a cut-down copy keeps the start and the end.
|
|
144
|
+
// On by default: they are routing slots, not docs sources.
|
|
145
|
+
if (startDeployWebsiteEnabled) {
|
|
146
|
+
addStartDeployWebsiteTool(server, disableTools || [], toolDescriptions, {
|
|
147
|
+
skillsPortalUrl,
|
|
148
|
+
repo: effectiveRepo,
|
|
149
|
+
commitHash: effectiveCommitHash
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Same reach as StartDeployWebsite: the slot for a site that needs Wix business features.
|
|
153
|
+
if (startHeadlessBuildEnabled) {
|
|
154
|
+
addStartHeadlessBuildTool(server, disableTools || [], toolDescriptions, {
|
|
155
|
+
skillsPortalUrl,
|
|
156
|
+
repo: effectiveRepo,
|
|
157
|
+
commitHash: effectiveCommitHash
|
|
158
|
+
});
|
|
159
|
+
}
|
|
99
160
|
if (dynamicContextEnabled &&
|
|
100
161
|
authStrategy &&
|
|
101
162
|
!disableTools?.includes('GetSiteContext')) {
|
|
102
163
|
addGetSiteContextTool({
|
|
103
164
|
server,
|
|
104
165
|
authStrategy,
|
|
166
|
+
includeCompanionApp,
|
|
105
167
|
toolDescriptions,
|
|
106
168
|
disableTools: disableTools || []
|
|
107
169
|
});
|
|
108
170
|
}
|
|
171
|
+
// Named in SERVER_INSTRUCTIONS (config/default-config.ts): when this tool's name or what it is for changes, update them to match.
|
|
109
172
|
if (getToKnowWixEnabled && !disableTools?.includes('WixREADME')) {
|
|
110
173
|
addGetToKnowTools({
|
|
111
174
|
server,
|
|
@@ -117,20 +180,9 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
117
180
|
dynamicContextEnabled,
|
|
118
181
|
repo: effectiveRepo,
|
|
119
182
|
commitHash: effectiveCommitHash,
|
|
120
|
-
skillsTags
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (createWixBusinessGuideEnabled &&
|
|
124
|
-
!disableTools?.includes('CreateWixBusinessGuide')) {
|
|
125
|
-
addCreateWixBusinessGuideTools(server, disableTools || [], toolDescriptions, cliEnabled);
|
|
126
|
-
}
|
|
127
|
-
// On by default: it is a routing slot, not a docs source — the agent with
|
|
128
|
-
// ready-made site files must find it next to the site-creation tools.
|
|
129
|
-
if (startDeployWebsiteEnabled) {
|
|
130
|
-
addStartDeployWebsiteTool(server, disableTools || [], toolDescriptions, {
|
|
131
|
-
skillsPortalUrl,
|
|
132
|
-
repo: effectiveRepo,
|
|
133
|
-
commitHash: effectiveCommitHash
|
|
183
|
+
skillsTags,
|
|
184
|
+
readmeRecipesIndexEnabled,
|
|
185
|
+
docsSite
|
|
134
186
|
});
|
|
135
187
|
}
|
|
136
188
|
// WDS Documentation
|
|
@@ -151,7 +203,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
151
203
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
152
204
|
try {
|
|
153
205
|
logger.log(`Searching for ${searchTerm} in Wix WDS`);
|
|
154
|
-
const result = await
|
|
206
|
+
const result = await runSearch({
|
|
155
207
|
toolName: 'WDS',
|
|
156
208
|
toolParams: {
|
|
157
209
|
searchTerm: searchTerm
|
|
@@ -203,7 +255,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
203
255
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults, reason }, { panorama }) => {
|
|
204
256
|
try {
|
|
205
257
|
logger.log(`[SearchWixRESTDocumentation] searchTerm="${searchTerm}", reason="${reason}"`);
|
|
206
|
-
const result = await
|
|
258
|
+
const result = await runSearch({
|
|
207
259
|
toolName: 'REST',
|
|
208
260
|
toolParams: {
|
|
209
261
|
searchTerm: searchTerm
|
|
@@ -266,7 +318,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
266
318
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
267
319
|
try {
|
|
268
320
|
logger.log(`Searching for ${searchTerm} in Wix Sample Flows`);
|
|
269
|
-
const result = await
|
|
321
|
+
const result = await runSearch({
|
|
270
322
|
toolName: 'BUSINESS_SOLUTIONS',
|
|
271
323
|
toolParams: {
|
|
272
324
|
searchTerm: '**RECIPE**: Business Recipes - full setup flow for::: ' +
|
|
@@ -324,7 +376,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
324
376
|
panorama
|
|
325
377
|
.transaction('SearchWixSDKDocumentation')
|
|
326
378
|
.start({ maxResults });
|
|
327
|
-
const result = await
|
|
379
|
+
const result = await runSearch({
|
|
328
380
|
toolName: 'SDK',
|
|
329
381
|
toolParams: {
|
|
330
382
|
searchTerm: searchTerm
|
|
@@ -382,7 +434,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
382
434
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
383
435
|
try {
|
|
384
436
|
logger.log(`Searching for ${searchTerm} in Build Apps`);
|
|
385
|
-
const result = await
|
|
437
|
+
const result = await runSearch({
|
|
386
438
|
toolName: 'BUILD_APPS',
|
|
387
439
|
toolParams: {
|
|
388
440
|
searchTerm: `wix cli docs for ${searchTerm}`
|
|
@@ -432,7 +484,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
432
484
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
433
485
|
try {
|
|
434
486
|
logger.log(`Searching for ${searchTerm} in Wix Overview`);
|
|
435
|
-
const result = await
|
|
487
|
+
const result = await runSearch({
|
|
436
488
|
toolName: 'OVERVIEW',
|
|
437
489
|
toolParams: {
|
|
438
490
|
searchTerm: searchTerm
|
|
@@ -482,7 +534,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
482
534
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults }, { panorama }) => {
|
|
483
535
|
try {
|
|
484
536
|
logger.log(`Searching for ${searchTerm} in Headless`);
|
|
485
|
-
const result = await
|
|
537
|
+
const result = await runSearch({
|
|
486
538
|
toolName: 'WIX_HEADLESS',
|
|
487
539
|
toolParams: {
|
|
488
540
|
searchTerm: searchTerm
|
|
@@ -538,7 +590,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
538
590
|
panorama
|
|
539
591
|
.transaction('SearchWixVeloDocumentation')
|
|
540
592
|
.start({ maxResults });
|
|
541
|
-
const result = await
|
|
593
|
+
const result = await runSearch({
|
|
542
594
|
toolName: 'VELO',
|
|
543
595
|
toolParams: {
|
|
544
596
|
searchTerm: searchTerm
|
|
@@ -579,6 +631,66 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
579
631
|
});
|
|
580
632
|
}
|
|
581
633
|
// CLI Documentation
|
|
634
|
+
// Help Center (support.wix.com): how site owners do things in the Wix
|
|
635
|
+
// dashboard and editors. Articles are long and prose-only, so fewer results
|
|
636
|
+
// with a larger line budget than the developer docs tools.
|
|
637
|
+
if (allowedTools.includes('HELP_CENTER') &&
|
|
638
|
+
!disableTools?.includes('SearchWixHelpCenter')) {
|
|
639
|
+
server.tool('SearchWixHelpCenter', getDescription('SearchWixHelpCenter', defaultToolDescriptions.SearchWixHelpCenter ?? ''), (() => {
|
|
640
|
+
const d = desc('SearchWixHelpCenter');
|
|
641
|
+
return {
|
|
642
|
+
searchTerm: z.string().describe(d.searchTerm),
|
|
643
|
+
maxResults: z
|
|
644
|
+
.number()
|
|
645
|
+
.describe(d.maxResults)
|
|
646
|
+
.min(1)
|
|
647
|
+
.max(15)
|
|
648
|
+
.optional()
|
|
649
|
+
.default(15),
|
|
650
|
+
reason: z.string().describe(d.reason)
|
|
651
|
+
};
|
|
652
|
+
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults, reason }, { panorama }) => {
|
|
653
|
+
try {
|
|
654
|
+
logger.log(`[SearchWixHelpCenter] searchTerm="${searchTerm}", reason="${reason}"`);
|
|
655
|
+
const result = await runSemanticSearchAndFormat({
|
|
656
|
+
toolName: 'HELP_CENTER',
|
|
657
|
+
toolParams: {
|
|
658
|
+
searchTerm: searchTerm
|
|
659
|
+
},
|
|
660
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 15, 15)),
|
|
661
|
+
linesInEachResult: 60,
|
|
662
|
+
usePlatformizedSearch
|
|
663
|
+
});
|
|
664
|
+
return {
|
|
665
|
+
content: [
|
|
666
|
+
{
|
|
667
|
+
type: 'text',
|
|
668
|
+
text: `${HELP_CENTER_IS_FOR_PEOPLE}\n\n${result}`
|
|
669
|
+
}
|
|
670
|
+
]
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
catch (error) {
|
|
674
|
+
panorama.errorMonitor().reportError(error);
|
|
675
|
+
captureException(error, {
|
|
676
|
+
tags: {
|
|
677
|
+
componentId: 'SearchWixHelpCenter',
|
|
678
|
+
toolName: 'SearchWixHelpCenter'
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
logger.error(`Error searching for ${searchTerm} in the Wix Help Center: ${error}`);
|
|
682
|
+
return {
|
|
683
|
+
isError: true,
|
|
684
|
+
content: [
|
|
685
|
+
{
|
|
686
|
+
type: 'text',
|
|
687
|
+
text: `Error: ${error.message}\n\n${HELP_CENTER_IS_FOR_PEOPLE}`
|
|
688
|
+
}
|
|
689
|
+
]
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
582
694
|
if (allowedTools.includes('CLI') &&
|
|
583
695
|
!disableTools?.includes('SearchWixCLIDocumentation')) {
|
|
584
696
|
server.tool('SearchWixCLIDocumentation', getDescription('SearchWixCLIDocumentation', defaultToolDescriptions.SearchWixCLIDocumentation ?? ''), (() => {
|
|
@@ -597,7 +709,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
597
709
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ searchTerm, maxResults, reason }, { panorama }) => {
|
|
598
710
|
try {
|
|
599
711
|
logger.log(`[SearchWixCLIDocumentation] searchTerm="${searchTerm}", reason="${reason}"`);
|
|
600
|
-
const result = await
|
|
712
|
+
const result = await runSearch({
|
|
601
713
|
toolName: 'CLI',
|
|
602
714
|
toolParams: {
|
|
603
715
|
searchTerm: searchTerm
|
|
@@ -638,9 +750,32 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
638
750
|
articleUrl: z.string().url().describe(d.articleUrl)
|
|
639
751
|
};
|
|
640
752
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ articleUrl }, { httpClient }) => {
|
|
641
|
-
//
|
|
753
|
+
// A file with no docs page, such as a skill kept out of the public
|
|
754
|
+
// mirror, is linked as get-source-content and read from its repository.
|
|
755
|
+
const source = parseSourceContentUrl(articleUrl);
|
|
756
|
+
if (source) {
|
|
757
|
+
try {
|
|
758
|
+
const text = await fetchSourceContent(httpClient, source.repo, source.path, source.commitHash);
|
|
759
|
+
return { content: [{ type: 'text', text }] };
|
|
760
|
+
}
|
|
761
|
+
catch (error) {
|
|
762
|
+
logger.error(`Error fetching source content for ${articleUrl}: ${error}`);
|
|
763
|
+
return {
|
|
764
|
+
isError: true,
|
|
765
|
+
content: [
|
|
766
|
+
{
|
|
767
|
+
type: 'text',
|
|
768
|
+
text: formatDocsReadError('source content', error)
|
|
769
|
+
}
|
|
770
|
+
]
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
// URL validation: known docs prefixes, a Help Center article
|
|
775
|
+
// (get-article-content reads support.wix.com/<locale>/article/<slug>),
|
|
776
|
+
// or a Wix skills registry page
|
|
642
777
|
// (https://www.wix.com/skills/..., https://dev.wix.com/docs/skills/...).
|
|
643
|
-
const validPrefixes = ['https://
|
|
778
|
+
const validPrefixes = [...docsUrlPrefixes, 'https://support.wix.com/'];
|
|
644
779
|
if (skillsPortalUrl)
|
|
645
780
|
validPrefixes.push(skillsPortalUrl);
|
|
646
781
|
const isSkillsPage = isSkillsRegistryUrl(articleUrl);
|
|
@@ -651,7 +786,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
651
786
|
content: [
|
|
652
787
|
{
|
|
653
788
|
type: 'text',
|
|
654
|
-
text: `Invalid article URL: must start with https://dev.wix.com/docs/, or be a Wix skills page (https://www.wix.com/skills
|
|
789
|
+
text: `Invalid article URL: must start with https://dev.wix.com/docs/ or https://support.wix.com/, or be a Wix skills page (https://www.wix.com/skills/..., https://www.wix.com/headless/..., or that file's github.com/wix/skills source). Got: "${articleUrl}"`
|
|
655
790
|
}
|
|
656
791
|
]
|
|
657
792
|
};
|
|
@@ -664,6 +799,30 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
664
799
|
articleUrl.startsWith('https://dev.wix.com/docs/')) {
|
|
665
800
|
articleUrl = articleUrl.replace(/\.md$/, '');
|
|
666
801
|
}
|
|
802
|
+
// Mintlify docs: read the page from the Mintlify site when it has one,
|
|
803
|
+
// else fall through to today's backend with the dev.wix.com URL.
|
|
804
|
+
if (mintlifyDocs && !isSkillsPage) {
|
|
805
|
+
try {
|
|
806
|
+
const page = await readMintlifyMarkdown(articleUrl);
|
|
807
|
+
if (page) {
|
|
808
|
+
return {
|
|
809
|
+
content: [
|
|
810
|
+
{
|
|
811
|
+
type: 'text',
|
|
812
|
+
text: isQueryOrSearchEndpoint(page.url)
|
|
813
|
+
? [page.markdown, ARTICLE_CAPABILITY_NOTE].join('\n\n')
|
|
814
|
+
: page.markdown
|
|
815
|
+
},
|
|
816
|
+
...sourceNote(`Mintlify site: ${page.url}.md`)
|
|
817
|
+
]
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
catch (error) {
|
|
822
|
+
logger.error(`[mintlify] reading ${articleUrl} from Mintlify failed, falling back: ${error}`);
|
|
823
|
+
}
|
|
824
|
+
articleUrl = toBackendUrl(articleUrl);
|
|
825
|
+
}
|
|
667
826
|
try {
|
|
668
827
|
const articleContent = await fetchArticleContent(httpClient, articleUrl, 'article', false, skillsPortalUrl, effectiveRepo, effectiveCommitHash);
|
|
669
828
|
if (!articleContent) {
|
|
@@ -678,7 +837,10 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
678
837
|
text: isQueryOrSearchEndpoint(articleUrl)
|
|
679
838
|
? [articleContent, ARTICLE_CAPABILITY_NOTE].join('\n\n')
|
|
680
839
|
: articleContent
|
|
681
|
-
}
|
|
840
|
+
},
|
|
841
|
+
...sourceNote(isSkillsPage
|
|
842
|
+
? `skills registry: ${articleUrl}`
|
|
843
|
+
: `today's backend (dev.wix.com/rawdocs, ingvar), not on the Mintlify site: ${articleUrl}`)
|
|
682
844
|
]
|
|
683
845
|
};
|
|
684
846
|
}
|
|
@@ -724,7 +886,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
724
886
|
};
|
|
725
887
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ articleUrl, reason }, { httpClient }) => {
|
|
726
888
|
// URL validation: only allow known docs prefixes
|
|
727
|
-
const validPrefixes = [
|
|
889
|
+
const validPrefixes = [...docsUrlPrefixes];
|
|
728
890
|
if (skillsPortalUrl)
|
|
729
891
|
validPrefixes.push(skillsPortalUrl);
|
|
730
892
|
if (!validPrefixes.some((p) => articleUrl.startsWith(p))) {
|
|
@@ -742,18 +904,28 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
742
904
|
if (articleUrl.startsWith('https://dev.wix.com/docs/')) {
|
|
743
905
|
articleUrl = articleUrl.replace(/\.md$/, '');
|
|
744
906
|
}
|
|
907
|
+
// Mintlify docs: schemas stay on PAPI through ingvar, by dev.wix.com URL.
|
|
908
|
+
articleUrl = toBackendUrl(articleUrl);
|
|
745
909
|
try {
|
|
746
910
|
logger.log(`[ReadFullDocsMethodSchema] url="${articleUrl}", reason="${reason}"`);
|
|
747
911
|
const articleContent = await fetchArticleContent(httpClient, articleUrl, 'methodSchema', false, skillsPortalUrl, effectiveRepo, effectiveCommitHash, true);
|
|
748
912
|
if (!articleContent) {
|
|
749
913
|
throw new Error('Method schema is empty');
|
|
750
914
|
}
|
|
915
|
+
// Mintlify docs: the schema text links other methods on dev.wix.com;
|
|
916
|
+
// resolve those to their Mintlify pages, as in search results.
|
|
917
|
+
const schemaText = mintlifyDocs
|
|
918
|
+
? (await rewriteDocsLinks(articleContent, {
|
|
919
|
+
label: 'schema ReadFullDocsMethodSchema'
|
|
920
|
+
})).text
|
|
921
|
+
: articleContent;
|
|
751
922
|
return {
|
|
752
923
|
content: [
|
|
753
924
|
{
|
|
754
925
|
type: 'text',
|
|
755
|
-
text:
|
|
756
|
-
}
|
|
926
|
+
text: schemaText
|
|
927
|
+
},
|
|
928
|
+
...sourceNote(`PAPI, through today's backend (dev.wix.com/rawdocs, ingvar): ${articleUrl}`)
|
|
757
929
|
]
|
|
758
930
|
};
|
|
759
931
|
}
|
|
@@ -799,7 +971,7 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
799
971
|
};
|
|
800
972
|
})(), { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, async ({ menuUrl, reason }, { httpClient }) => {
|
|
801
973
|
try {
|
|
802
|
-
if (menuUrl && !menuUrl.startsWith(
|
|
974
|
+
if (menuUrl && !docsUrlPrefixes.some((p) => menuUrl.startsWith(p))) {
|
|
803
975
|
return {
|
|
804
976
|
content: [
|
|
805
977
|
{
|
|
@@ -36,5 +36,26 @@ export declare function fetchRecipesIndex(): Promise<string>;
|
|
|
36
36
|
*/
|
|
37
37
|
export declare function fetchArticle(articleUrl: string): Promise<string>;
|
|
38
38
|
export declare function isSkillsRegistryUrl(url: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* The forms of a skills URL agents hold that the registry serves under another
|
|
41
|
+
* name: wix.com without www (a 301 the fetch client does not follow), and the
|
|
42
|
+
* GitHub source of the same file. Both map to the www.wix.com/skills page.
|
|
43
|
+
*/
|
|
44
|
+
export declare function normalizeSkillsUrl(url: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* A file read from its source repository rather than the published docs, via
|
|
47
|
+
* the rawdocs get-source-content API (e.g. the management index as authored in
|
|
48
|
+
* wix-private/ax-skills). The API serves only the files it allows.
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* The repo and path a get-source-content URL names: what a file served from its
|
|
52
|
+
* source repository links a file that has no docs page to.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseSourceContentUrl(url: string): {
|
|
55
|
+
repo: string;
|
|
56
|
+
path: string;
|
|
57
|
+
commitHash?: string;
|
|
58
|
+
} | undefined;
|
|
59
|
+
export declare function fetchSourceContent(httpClient: HttpClient, repo: string, path: string, commitHash?: string): Promise<string>;
|
|
39
60
|
export declare function fetchArticleContent(httpClient: HttpClient, articleUrl: string, mode: 'article' | 'methodSchema' | 'raw', stripHeader?: boolean, skillsPortalUrl?: string, repo?: string, commitHash?: string, fetchMcpWhiteList?: boolean): Promise<string>;
|
|
40
61
|
//# sourceMappingURL=fetch-article.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HttpClient } from '@wix/http-client';
|
|
2
2
|
import { logger } from '../infra/logger.js';
|
|
3
|
-
import { GET_ARTICLE_CONTENT_URL } from '../constants.js';
|
|
3
|
+
import { GET_ARTICLE_CONTENT_URL, GET_SOURCE_CONTENT_URL } from '../constants.js';
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
5
|
// Public constants and utilities
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
@@ -57,9 +57,27 @@ const DOCS_URL_PREFIX = 'https://dev.wix.com/docs/';
|
|
|
57
57
|
* get-article-content API does not know them, and `.md` is a real path, so
|
|
58
58
|
* they are fetched as-is.
|
|
59
59
|
*/
|
|
60
|
-
const SKILLS_REGISTRY_URL = new RegExp('^https://(?:dev\\.wix\\.com(?:/docs)?|www\\.wix\\.com(?:/velo/reference)?)/skills(?:[/.?#]|$)'
|
|
60
|
+
const SKILLS_REGISTRY_URL = new RegExp('^https://(?:dev\\.wix\\.com(?:/docs)?|www\\.wix\\.com(?:/velo/reference)?)/skills(?:[/.?#]|$)' +
|
|
61
|
+
// Anything under www.wix.com/headless/ (e.g. the landing page's skill.md) is
|
|
62
|
+
// served as raw markdown like the registry, and read the same way.
|
|
63
|
+
'|^https://www\\.wix\\.com/headless/');
|
|
61
64
|
export function isSkillsRegistryUrl(url) {
|
|
62
|
-
return SKILLS_REGISTRY_URL.test(url
|
|
65
|
+
return SKILLS_REGISTRY_URL.test(normalizeSkillsUrl(url));
|
|
66
|
+
}
|
|
67
|
+
// A GitHub view of the skills repository, as an installed plugin cross-references it:
|
|
68
|
+
// github.com/wix/skills/blob/<ref>/skills/<skill>/<path>, with or without a line anchor.
|
|
69
|
+
const GITHUB_SKILLS_URL = /^https:\/\/(?:www\.)?github\.com\/wix\/skills\/(?:blob|raw|tree)\/[^/]+\/skills\/([^#?]+)/;
|
|
70
|
+
/**
|
|
71
|
+
* The forms of a skills URL agents hold that the registry serves under another
|
|
72
|
+
* name: wix.com without www (a 301 the fetch client does not follow), and the
|
|
73
|
+
* GitHub source of the same file. Both map to the www.wix.com/skills page.
|
|
74
|
+
*/
|
|
75
|
+
export function normalizeSkillsUrl(url) {
|
|
76
|
+
const apex = url
|
|
77
|
+
.trim()
|
|
78
|
+
.replace(/^https:\/\/wix\.com\//, 'https://www.wix.com/');
|
|
79
|
+
const gh = apex.match(GITHUB_SKILLS_URL);
|
|
80
|
+
return gh ? `https://www.wix.com/skills/${gh[1]}` : apex;
|
|
63
81
|
}
|
|
64
82
|
async function fetchSkillsRegistryPage(httpClient, url) {
|
|
65
83
|
let data;
|
|
@@ -170,6 +188,53 @@ async function fetchArticleContentFromDigor(httpClient, articleUrl, mode, stripH
|
|
|
170
188
|
}
|
|
171
189
|
return articleContent;
|
|
172
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* A file read from its source repository rather than the published docs, via
|
|
193
|
+
* the rawdocs get-source-content API (e.g. the management index as authored in
|
|
194
|
+
* wix-private/ax-skills). The API serves only the files it allows.
|
|
195
|
+
*/
|
|
196
|
+
/**
|
|
197
|
+
* The repo and path a get-source-content URL names: what a file served from its
|
|
198
|
+
* source repository links a file that has no docs page to.
|
|
199
|
+
*/
|
|
200
|
+
export function parseSourceContentUrl(url) {
|
|
201
|
+
let parsed;
|
|
202
|
+
try {
|
|
203
|
+
parsed = new URL(url);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
if (`${parsed.origin}${parsed.pathname}` !== GET_SOURCE_CONTENT_URL) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
const repo = parsed.searchParams.get('repo');
|
|
212
|
+
const path = parsed.searchParams.get('path');
|
|
213
|
+
const commitHash = parsed.searchParams.get('commitHash');
|
|
214
|
+
if (!repo || !path)
|
|
215
|
+
return undefined;
|
|
216
|
+
return commitHash ? { repo, path, commitHash } : { repo, path };
|
|
217
|
+
}
|
|
218
|
+
export async function fetchSourceContent(httpClient, repo, path, commitHash) {
|
|
219
|
+
const url = new URL(GET_SOURCE_CONTENT_URL);
|
|
220
|
+
url.searchParams.set('repo', repo);
|
|
221
|
+
url.searchParams.set('path', path);
|
|
222
|
+
if (commitHash)
|
|
223
|
+
url.searchParams.set('commitHash', commitHash);
|
|
224
|
+
let data;
|
|
225
|
+
try {
|
|
226
|
+
({ data } = await httpClient.get(url.toString()));
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
const { message, status } = getHttpErrorDetails(error);
|
|
230
|
+
const statusSuffix = status ? ` (status ${status})` : '';
|
|
231
|
+
throw new Error(`${message}${statusSuffix}`);
|
|
232
|
+
}
|
|
233
|
+
if (!data?.content) {
|
|
234
|
+
throw new Error('Source content is empty');
|
|
235
|
+
}
|
|
236
|
+
return data.content;
|
|
237
|
+
}
|
|
173
238
|
export async function fetchArticleContent(httpClient, articleUrl, mode, stripHeader = false, skillsPortalUrl, repo, commitHash, fetchMcpWhiteList) {
|
|
174
239
|
// Apply portal URL override if configured
|
|
175
240
|
const effectiveUrl = applyPortalUrlOverride(articleUrl, skillsPortalUrl);
|
|
@@ -187,12 +252,12 @@ export async function fetchArticleContent(httpClient, articleUrl, mode, stripHea
|
|
|
187
252
|
// Fall through to the normal fetch for this URL: the registry for a
|
|
188
253
|
// skills page (rawdocs cannot serve those), rawdocs otherwise.
|
|
189
254
|
content = isSkillsRegistryUrl(articleUrl)
|
|
190
|
-
? await fetchSkillsRegistryPage(httpClient, articleUrl)
|
|
255
|
+
? await fetchSkillsRegistryPage(httpClient, normalizeSkillsUrl(articleUrl))
|
|
191
256
|
: await fetchArticleContentFromDigor(httpClient, articleUrl, mode, stripHeader);
|
|
192
257
|
}
|
|
193
258
|
}
|
|
194
259
|
else if (isSkillsRegistryUrl(articleUrl)) {
|
|
195
|
-
content = await fetchSkillsRegistryPage(httpClient, articleUrl);
|
|
260
|
+
content = await fetchSkillsRegistryPage(httpClient, normalizeSkillsUrl(articleUrl));
|
|
196
261
|
}
|
|
197
262
|
else if (mode === 'raw') {
|
|
198
263
|
let parsedUrl;
|
|
@@ -28,14 +28,19 @@ export interface AddGetToKnowTools {
|
|
|
28
28
|
repo?: string;
|
|
29
29
|
commitHash?: string;
|
|
30
30
|
skillsTags?: string[];
|
|
31
|
+
readmeRecipesIndexEnabled?: boolean;
|
|
32
|
+
/** The connection's docsSite (see ./mintlify-docs.ts): a Mintlify mode resolves the README's docs links. */
|
|
33
|
+
docsSite?: string;
|
|
31
34
|
}
|
|
32
35
|
interface AddGetSiteContextTool {
|
|
33
36
|
server: WixMcpServer;
|
|
34
37
|
authStrategy: McpAuthenticationStrategy;
|
|
35
38
|
partnerContextEnabled?: boolean;
|
|
39
|
+
/** Render the site's companion app. Off by default: only Aria (via the toolkit) needs it. */
|
|
40
|
+
includeCompanionApp?: boolean;
|
|
36
41
|
toolDescriptions?: Record<string, string>;
|
|
37
42
|
disableTools?: string[];
|
|
38
43
|
}
|
|
39
|
-
export declare function addGetSiteContextTool({ server, authStrategy, toolDescriptions }: AddGetSiteContextTool): void;
|
|
40
|
-
export declare function addGetToKnowTools({ server, disableTools, toolDescriptions, readmeDocs, authStrategy, skillsPortalUrl, dynamicContextEnabled, repo, commitHash, skillsTags }: AddGetToKnowTools): Promise<void>;
|
|
44
|
+
export declare function addGetSiteContextTool({ server, authStrategy, includeCompanionApp, toolDescriptions }: AddGetSiteContextTool): void;
|
|
45
|
+
export declare function addGetToKnowTools({ server, disableTools, toolDescriptions, readmeDocs, authStrategy, skillsPortalUrl, dynamicContextEnabled, repo, commitHash, skillsTags, readmeRecipesIndexEnabled, docsSite }: AddGetToKnowTools): Promise<void>;
|
|
41
46
|
//# sourceMappingURL=get-to-know.d.ts.map
|