@wix/mcp 1.0.95 → 1.0.96
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/build/bin-standalone.js +352 -22
- package/build/cjs/index.cjs +910 -530
- package/build/cjs/toolkit.cjs +405 -46
- package/build/dts/api-call/index.js +23 -1
- package/build/dts/api-call/upload-headless-website-files.d.ts +31 -2
- package/build/dts/api-call/upload-headless-website-files.js +107 -15
- package/build/dts/code-mode/attachments.d.ts +9 -6
- package/build/dts/code-mode/attachments.js +23 -16
- package/build/dts/code-mode/index.js +2 -2
- package/build/dts/config/default-config.d.ts +1 -1
- package/build/dts/config/default-config.js +17 -16
- package/build/dts/docs/docs.js +64 -1
- package/build/dts/docs/guessed-url.d.ts +41 -0
- package/build/dts/docs/guessed-url.js +185 -0
- package/build/dts/infra/redact-personal-data.d.ts +1 -1
- package/build/dts/infra/redact-personal-data.js +72 -3
- package/build/dts/site-widget-tools/constants.d.ts +3 -3
- package/build/dts/site-widget-tools/constants.js +3 -3
- package/build/dts/site-widget-tools/pull-site-creation-job-tool/index.js +1 -1
- package/build/dts/site-widget-tools/search-site-templates-tool/index.js +10 -1
- package/build/dts/site-widget-tools/site-builder-tool/index.js +14 -2
- package/build/dts/site-widget-tools/suggested-domain-tool/index.js +20 -9
- package/build/dts/tool-utils.d.ts +8 -1
- package/build/dts/tool-utils.js +26 -2
- package/build/dts/toolkit.js +7 -1
- package/build/esm/index.js +793 -413
- package/build/esm/toolkit.js +405 -46
- package/package.json +2 -2
|
@@ -26,7 +26,8 @@ function directRouteLines(includeReadme, includeImageUploadGuidance) {
|
|
|
26
26
|
return [
|
|
27
27
|
...(includeReadme
|
|
28
28
|
? [
|
|
29
|
-
`- **Creating a new site.** Skip the docs too. A site is written in code and uploaded: StartDeployWebsite returns the upload guide; StartHeadlessBuild returns the headless guide, for a site that needs Wix business features (${WIX_BUSINESS_FEATURES}). Call one right away, without asking the user anything first: StartHeadlessBuild when the site needs Wix business features, otherwise StartDeployWebsite.
|
|
29
|
+
`- **Creating a new site.** Skip the docs too. A site is written in code and uploaded: StartDeployWebsite returns the upload guide; StartHeadlessBuild returns the headless guide, for a site that needs Wix business features (${WIX_BUSINESS_FEATURES}). Call one right away, without asking the user anything first: StartHeadlessBuild when the site needs Wix business features, otherwise StartDeployWebsite. WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for Wix's editor, the Wix Harmony Editor, a template, Wix Studio or the Classic Editor. Never create a site through ManageWixSite, CallWixSiteAPI or ExecuteWixAPI.`,
|
|
30
|
+
'- **Suggesting domain names**: call GetSuggestedDomains directly, with the business or site name as the query.'
|
|
30
31
|
]
|
|
31
32
|
: []),
|
|
32
33
|
'- **Listing, showing or finding their Wix sites**: call ListWixSites directly.',
|
|
@@ -87,16 +88,17 @@ export const HELP_CENTER_IS_FOR_PEOPLE = "The Help Center is written for people
|
|
|
87
88
|
* Each tool named here carries a comment pointing back to this text. A change to any of them (a
|
|
88
89
|
* name, what it is for, a new site-creation tool) updates this text and that list with it.
|
|
89
90
|
*/
|
|
90
|
-
export const SERVER_INSTRUCTIONS = `Wix: build and manage Wix sites. A new site is written in code and uploaded: StartDeployWebsite returns the upload guide; StartHeadlessBuild returns the headless guide, for a site that needs Wix business features (forms, a store, bookings, a CMS, members, payments).
|
|
91
|
+
export const SERVER_INSTRUCTIONS = `Wix: build and manage Wix sites. A new site is written in code and uploaded: StartDeployWebsite returns the upload guide; StartHeadlessBuild returns the headless guide, for a site that needs Wix business features (forms, a store, bookings, a CMS, members, payments). WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for Wix's editor, the Wix Harmony Editor, a template, Wix Studio or the Classic Editor. Call WixREADME first, except ListWixSites, UploadImageToWixSite, GetSuggestedDomains.`;
|
|
91
92
|
/** The tools SERVER_INSTRUCTIONS names. */
|
|
92
93
|
export const SERVER_INSTRUCTIONS_TOOLS = [
|
|
93
94
|
'StartDeployWebsite',
|
|
94
95
|
'StartHeadlessBuild',
|
|
95
|
-
'
|
|
96
|
+
'WixHarmonyEditorBuild',
|
|
96
97
|
'SearchSiteTemplates',
|
|
97
98
|
'WixREADME',
|
|
98
99
|
'ListWixSites',
|
|
99
|
-
'UploadImageToWixSite'
|
|
100
|
+
'UploadImageToWixSite',
|
|
101
|
+
'GetSuggestedDomains'
|
|
100
102
|
];
|
|
101
103
|
export const SITE_CREATION_COPY = {
|
|
102
104
|
templatePick: {
|
|
@@ -115,7 +117,7 @@ export const toWidget = (text) => Object.values(SITE_CREATION_COPY).reduce((acc,
|
|
|
115
117
|
*/
|
|
116
118
|
// The data the Wix REST API covers, product by product (from the ax-skills capability map), named
|
|
117
119
|
// in the discovery tools' descriptions so a client's tool search finds them by what the user asks about.
|
|
118
|
-
const WIX_API_DATA = "products, inventory, carts, checkouts, orders, bookings, services, staff, time slots, rentals, restaurant menus, online orders, reservations, events, tickets, RSVPs, blog posts, CMS collections and items, pricing plans, subscriptions, portfolios, gift cards, coupons, donations, forms, form submissions, contacts, members, loyalty points, groups, reviews, inbox messages, CRM tasks, automations, email campaigns, payments, invoices, SEO, redirects, translations, locations, analytics, media files, site properties, installed apps, and the account's sites and domains";
|
|
120
|
+
const WIX_API_DATA = "products, inventory, carts, checkouts, orders, bookings, services, staff, time slots, rentals, restaurant menus, online orders, reservations, events, tickets, RSVPs, blog posts, CMS collections and items, pricing plans, subscriptions, portfolios, gift cards, coupons, donations, forms, form submissions, contacts, members, loyalty points, groups, reviews, inbox messages, CRM tasks, automations, email campaigns, payments, invoices, SEO, redirects, translations, locations, analytics, media files, site properties, installed apps, and the account's sites and domains (searching whether a domain is available, buying one, and connecting one bought elsewhere)";
|
|
119
121
|
const EXECUTE_WIX_API_INTRO = dedent `
|
|
120
122
|
Reads and changes the data of a Wix site or account: query, list, count, create, update and delete it with one JavaScript function over the Wix REST API.
|
|
121
123
|
One function holds the whole task: chained calls, pagination, loops, branching, and the reads that feed its writes.
|
|
@@ -432,8 +434,7 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
|
|
|
432
434
|
${reminder}
|
|
433
435
|
`,
|
|
434
436
|
ManageWixSite: dedent `
|
|
435
|
-
|
|
436
|
-
Account-level only: this tool acts on the account itself, or on sites as objects within it, and sends no site context. Anything that reads or writes inside a site is site-level and does not belong here — use a site-level tool with that site's \`siteId\`.
|
|
437
|
+
Calls an account-level Wix API: one that acts on the account itself (its sites list, domains, account settings) or on sites as objects in it (create, rename, duplicate, delete a site). It sends no site, so an API that reads or writes inside a site (its products, data, bookings, members, pages, publishing) fails here: call that through ExecuteWixAPI with the site's \`siteId\`.
|
|
437
438
|
For POST/PATCH/PUT requests, pass the request body as a JSON object or array in the "body" parameter with all the required fields and values as described in the API schema, code examples, or docs you retrieved (e.g. body: {"name": "value", "nested": {"key": "value"}} or body: [{"key": "value"}]).
|
|
438
439
|
The API endpoint url param MUST ALWAYS be taken from the conversation context.
|
|
439
440
|
By conversation context we mean the endpoint url was given in the user prompt or got into the conversation context ${includeReadme ? 'by the "WixREADME" tool or ' : ''}by the "SearchWixRESTDocumentation" tool or by the "BrowseWixRESTDocsMenu" tool or by the "ReadFullDocsArticle" tool.
|
|
@@ -503,7 +504,7 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
|
|
|
503
504
|
${reminder}
|
|
504
505
|
`,
|
|
505
506
|
WixSiteCreation: dedent `
|
|
506
|
-
|
|
507
|
+
Returns which Wix tool creates a new site, and creates nothing itself. A new site is written in code and uploaded: StartDeployWebsite returns the upload guide, and StartHeadlessBuild returns the guide for a site that needs Wix business features. Use WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for Wix's editor, a template, Wix Studio or the Classic Editor.
|
|
507
508
|
`,
|
|
508
509
|
'import-claude-design-from-url': dedent `
|
|
509
510
|
Import a design created in Claude's design tool into Wix. Only for the signed \`claudeusercontent.com\` bundle URL Claude Design's "Send to Wix" produces (a self-contained HTML bundle with all images, fonts, and styles inlined). Creates a live Wix-hosted site and returns its URL.
|
|
@@ -945,16 +946,16 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
|
|
|
945
946
|
`,
|
|
946
947
|
ExecuteWixAPI: executeWixApiDescription,
|
|
947
948
|
// Named in SERVER_INSTRUCTIONS: when this tool's name or what it is for changes, update them to match.
|
|
948
|
-
|
|
949
|
-
A secondary site-creation tool, only for a user who asked for the Wix Harmony Editor or for Wix to design the site. Don't call it for any other site request, not even to check with the flag false. A new site is otherwise written in code and uploaded, with StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features.
|
|
949
|
+
WixHarmonyEditorBuild: dedent `
|
|
950
|
+
A secondary site-creation tool, only for a user who asked for the Wix Harmony Editor or for Wix to design the site in Wix's editor. A request for a site on Wix, or for Wix to build or make one, is neither. Don't call it for any other site request, not even to check with the flag false. A new site is otherwise written in code and uploaded, with StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features.
|
|
950
951
|
Builds a site with the Wix Harmony Editor: Wix designs a first version from the user's description, and the user keeps designing it in Wix's editor. Shows the build's progress and a preview.
|
|
951
|
-
Call it when the user asked for the Wix Harmony Editor, or for Wix to design the site, in their own words or as their answer to your question
|
|
952
|
+
Call it when the user asked for the Wix Harmony Editor, or for Wix to design the site in Wix's editor, in their own words or as their answer to your question, and quote those words in \`editorRequest\`. ${EDITOR_TAIL}
|
|
952
953
|
`,
|
|
953
954
|
// Named in SERVER_INSTRUCTIONS: when this tool's name or what it is for changes, update them to match.
|
|
954
955
|
SearchSiteTemplates: dedent `
|
|
955
956
|
A secondary site-creation tool, only for a user who asked for a template, Wix Studio or the Classic Editor. Don't call it for any other site request, not even to check with the flag false. A new site is otherwise written in code and uploaded, with StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features.
|
|
956
957
|
Shows a gallery of Wix templates, from Harmony, Wix Studio or the Classic Editor, for a site the user will design in Wix's editor. Wix templates come with Wix's business features (a store, online ordering, bookings, forms), so a request for a template comes here even when the site needs them.
|
|
957
|
-
Call it when the user asked for a template, Wix Studio or the Classic Editor, in their own words or as their answer to your question
|
|
958
|
+
Call it when the user asked for a template, Wix Studio or the Classic Editor, in their own words or as their answer to your question, and quote those words in \`templateRequest\`. ${EDITOR_TAIL} ${SITE_CREATION_COPY.templatePick.nonWidget}
|
|
958
959
|
`,
|
|
959
960
|
CreateSiteFromTemplate: dedent `
|
|
960
961
|
Creates a Wix site from a specific template (by \`metaSiteId\` or \`templateId\`), publishes it when possible, and shows a live preview with links to the editor and the published site.
|
|
@@ -991,20 +992,20 @@ export function buildToolDescriptions(includeReadme, includeImageUploadGuidance
|
|
|
991
992
|
UploadHeadlessWebsiteFiles: dedent `
|
|
992
993
|
The upload step of the StartDeployWebsite and StartHeadlessBuild guides, and nothing else: puts a finished website's files — a static site (index.html plus its CSS/JS/images, a static build, or a zip of the site) or a Wix Astro build — onto an existing Wix Headless site by its metaSiteId. Call it ONLY after one of them has returned its guide in this conversation and the site exists: for a new site, first run the recipe's provision call and pass the metaSiteId it returns; for a site deployed earlier, pass its metaSiteId. It does not create sites. Every upload replaces the whole file set and the URL stays. Returns the live URL and the dashboard link, and points back to the recipe for what comes next.
|
|
993
994
|
Pass the files themselves: in ${FILE_PARAM_CLIENTS} as \`attachments\` (any type, a zip is unpacked), elsewhere as the \`files\` text bundle (\`=== FILE: <path> ===\` sections, \`base64\` tag for small binaries). A static site must contain index.html at its root. A Wix Astro build with no file handle, from a shell that reaches the internet, goes in two calls: zip the build, call with \`prepare: true\` and the zip's \`size\` in bytes, PUT the zips it names with the \`curl\` commands it returns (the build, and the project source when the site's repository accepts it), then call again with the \`uploadKey\` it returned; that releases the build. The two calls, literally: {siteId, prepare: true, size} then {siteId, uploadKey, sourceUploadId?, expectedHeadRevisionId?, releaseNotes?}. A sandbox whose network is limited to a few hosts cannot upload to those URLs. A static site does not use the two calls. A Wix Astro build (the project's .wix/ and dist/ after \`astro build\` with the Wix hosting adapter, zipped from the project root) needs no index.html: it is released to the site's Wix hosting instead, server-rendered pages, the same site and URL. The project's source is stored with the release when the upload holds the project and the site's repository accepts it.
|
|
994
|
-
NOT a site-creation tool: a request to create, build, design or generate a site — with or without a description — never comes here first. Unless the user asked for Wix's editor or a template (
|
|
995
|
+
NOT a site-creation tool: a request to create, build, design or generate a site — with or without a description — never comes here first. Unless the user asked for Wix's editor or a template (WixHarmonyEditorBuild, SearchSiteTemplates), call StartDeployWebsite right away, without asking the user anything: it also takes files the user brought, uploaded first even when the site needs business features. StartHeadlessBuild instead for a new site with no files that needs Wix business features. Also NOT for media uploads to an existing site (UploadImageToWixSite) or any other API call (ExecuteWixAPI).
|
|
995
996
|
`,
|
|
996
997
|
// Named in SERVER_INSTRUCTIONS: when this tool's name or what it is for changes, update them to match.
|
|
997
998
|
StartDeployWebsite: dedent `
|
|
998
999
|
Creates a website on Wix and puts it live, or replaces the files of one deployed earlier. You write the site's code, or take the files the user brought (HTML/CSS/JS, a static build, a zip, another builder's export), and this returns the guide to create the site and upload them. Updates keep the same site and URL. Works with or without a Wix login (anonymous deploy with a save link), through the Wix MCP alone or from a shell. Call it right away, without asking the user anything first.
|
|
999
1000
|
When a new site needs Wix business features (${WIX_BUSINESS_FEATURES}), call StartHeadlessBuild instead. When the user brought files and the site needs those features, upload the files here first; the upload's result then points to StartHeadlessBuild to connect them.
|
|
1000
1001
|
Returns the guide; follow it and do the work yourself. Upload with UploadHeadlessWebsiteFiles once the site exists; the drop page is only the fallback.
|
|
1001
|
-
NOT for: a user who asked for Wix's editor, the Wix Harmony Editor, a template, Wix Studio or the Classic Editor (
|
|
1002
|
+
NOT for: a user who asked for Wix's editor, the Wix Harmony Editor, a template, Wix Studio or the Classic Editor (WixHarmonyEditorBuild, SearchSiteTemplates); a Claude Design bundle URL (import-claude-design-from-url); migrating a live site by URL or CSV exports; adding HTML or code into an existing Wix editor site; uploading images or documents to a site's media (UploadImageToWixSite).
|
|
1002
1003
|
`,
|
|
1003
1004
|
// Named in SERVER_INSTRUCTIONS: when this tool's name or what it is for changes, update them to match.
|
|
1004
1005
|
StartHeadlessBuild: dedent `
|
|
1005
1006
|
Returns Wix's headless guide, for a site that needs Wix business features (${WIX_BUSINESS_FEATURES}), run by Wix as a Wix Headless site. You write the site; the guide creates it, connects the features, and uploads it. Also to add those features to an existing Wix Headless site (one deployed from files is one), from a project download link, or to move a Wix site to code.
|
|
1006
1007
|
Call it right away: it only returns the guide, and the site's details are not needed first.
|
|
1007
|
-
NOT for: a site that needs no Wix business feature, or files the user brought that are not live yet (StartDeployWebsite: upload them first, then come back here for the features); a user who asked for Wix's editor, the Wix Harmony Editor, a template, Wix Studio or the Classic Editor, even when the site needs business features (
|
|
1008
|
+
NOT for: a site that needs no Wix business feature, or files the user brought that are not live yet (StartDeployWebsite: upload them first, then come back here for the features); a user who asked for Wix's editor, the Wix Harmony Editor, a template, Wix Studio or the Classic Editor, even when the site needs business features (WixHarmonyEditorBuild, SearchSiteTemplates); a Claude Design URL (import-claude-design-from-url).
|
|
1008
1009
|
`
|
|
1009
1010
|
};
|
|
1010
1011
|
// The tool's former name, kept for importers that read it by that key.
|
|
@@ -1275,7 +1276,7 @@ export function withUsageGuideOnEveryTool(config) {
|
|
|
1275
1276
|
*/
|
|
1276
1277
|
export const widgetSiteCreationConfig = {
|
|
1277
1278
|
toolDescriptions: Object.fromEntries([
|
|
1278
|
-
'
|
|
1279
|
+
'WixHarmonyEditorBuild',
|
|
1279
1280
|
'WixSiteCreation',
|
|
1280
1281
|
'SearchSiteTemplates',
|
|
1281
1282
|
'CreateSiteFromTemplate'
|
package/build/dts/docs/docs.js
CHANGED
|
@@ -5,6 +5,7 @@ import { captureException } from '@sentry/node';
|
|
|
5
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
|
+
import { closestMenuLinks, closestSkillFile, parentMenuUrls, skillManifestUrl, subMenusToRead } from './guessed-url.js';
|
|
8
9
|
import { isQueryOrSearchEndpoint, QUERY_CAPABILITY_MARKER } from './searchFormatting.js';
|
|
9
10
|
import { addGetToKnowTools, addGetSiteContextTool } from './get-to-know.js';
|
|
10
11
|
import { addStartHeadlessBuildTool } from './start-headless-build.js';
|
|
@@ -55,7 +56,17 @@ function shouldTryMenuFallbackForDocsRead(error, articleUrl) {
|
|
|
55
56
|
if (!message.includes('404') || !isMenuFallbackUrl) {
|
|
56
57
|
return false;
|
|
57
58
|
}
|
|
58
|
-
return !
|
|
59
|
+
return !isKnownArticleError(error);
|
|
60
|
+
}
|
|
61
|
+
// A 404 that says why (a deprecated page, a method with no schema) is the answer itself.
|
|
62
|
+
function isKnownArticleError(error) {
|
|
63
|
+
const message = getErrorMessage(error);
|
|
64
|
+
return [
|
|
65
|
+
'This resource is deprecated',
|
|
66
|
+
'This method is deprecated',
|
|
67
|
+
'This article is deprecated',
|
|
68
|
+
'No schema found'
|
|
69
|
+
].some((knownArticleError) => message.includes(knownArticleError));
|
|
59
70
|
}
|
|
60
71
|
function formatDocsReadError(toolAction, error) {
|
|
61
72
|
return `Could not fetch ${toolAction}: "${getErrorMessage(error)}".`;
|
|
@@ -139,6 +150,51 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
139
150
|
? summarizeLargeMenu(menuContent, url)
|
|
140
151
|
: normalizeMenuContent(menuContent);
|
|
141
152
|
};
|
|
153
|
+
// A docs or skills page that 404'd, most often a URL rewritten or guessed from a real one:
|
|
154
|
+
// the closest file in the skill or its folder's files, or the nearest menu above a docs page
|
|
155
|
+
// with its closest entries (one level into its closest sub-menus when none of its own is
|
|
156
|
+
// close). Null when nothing near exists, so the 404 stands.
|
|
157
|
+
const nearestToMissingPage = async (httpClient, url, isSkillsPage) => {
|
|
158
|
+
try {
|
|
159
|
+
if (isSkillsPage) {
|
|
160
|
+
const manifestUrl = skillManifestUrl(url);
|
|
161
|
+
if (!manifestUrl)
|
|
162
|
+
return null;
|
|
163
|
+
const manifest = JSON.parse(await fetchArticleContent(httpClient, manifestUrl, 'article'));
|
|
164
|
+
const guess = closestSkillFile(url, manifest, manifestUrl);
|
|
165
|
+
if (!guess)
|
|
166
|
+
return null;
|
|
167
|
+
if (guess.kind === 'file') {
|
|
168
|
+
const text = await fetchArticleContent(httpClient, guess.url, 'article');
|
|
169
|
+
return `Note: "${url}" does not exist. Found a similar file in the skill, ${guess.url}, and read it:\n\n${text}`;
|
|
170
|
+
}
|
|
171
|
+
return `Note: "${url}" does not exist, and no file in ${guess.folder ? `its folder (${guess.folder}/)` : 'the skill'} has a name close to it. ${guess.folder ? 'The files in that folder' : "The skill's top-level folders and files"}, to read the one you need (every file: ${guess.manifestUrl}):\n\n${guess.files.map((f) => `- ${f}`).join('\n')}`;
|
|
172
|
+
}
|
|
173
|
+
for (const menuUrl of parentMenuUrls(url)) {
|
|
174
|
+
const text = await fetchMenuTextForUrl(httpClient, menuUrl);
|
|
175
|
+
if (!text)
|
|
176
|
+
continue;
|
|
177
|
+
const subMenus = (await Promise.all(subMenusToRead(text, menuUrl, url).map(async (sub) => ({
|
|
178
|
+
sub,
|
|
179
|
+
text: await fetchMenuTextForUrl(httpClient, sub).catch(() => null)
|
|
180
|
+
})))).filter((m) => !!m.text);
|
|
181
|
+
const closest = closestMenuLinks([text, ...subMenus.map((m) => m.text)].join('\n'), menuUrl, url);
|
|
182
|
+
return [
|
|
183
|
+
`Note: "${url}" does not exist. Showing the nearest documentation menu above it, ${menuUrl}; read the page you need from its links.`,
|
|
184
|
+
...(closest.length
|
|
185
|
+
? [
|
|
186
|
+
`Closest to what you asked for:\n${closest.map((l) => `- ${l}`).join('\n')}`
|
|
187
|
+
]
|
|
188
|
+
: []),
|
|
189
|
+
text
|
|
190
|
+
].join('\n\n');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
logger.error(`[docs] no nearest page for ${url}: ${error}`);
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
};
|
|
142
198
|
// The two site-creation guides register first, so they head the tool list: an agent that
|
|
143
199
|
// loads every definition at once and gets a cut-down copy keeps the start and the end.
|
|
144
200
|
// On by default: they are routing slots, not docs sources.
|
|
@@ -865,6 +921,13 @@ export const addDocsTools = (server, allowedTools = [
|
|
|
865
921
|
// menu fallback failed too — fall through to error below
|
|
866
922
|
}
|
|
867
923
|
}
|
|
924
|
+
if (getErrorMessage(error).includes('404') &&
|
|
925
|
+
!isKnownArticleError(error)) {
|
|
926
|
+
const nearest = await nearestToMissingPage(httpClient, articleUrl, isSkillsPage);
|
|
927
|
+
if (nearest) {
|
|
928
|
+
return { content: [{ type: 'text', text: nearest }] };
|
|
929
|
+
}
|
|
930
|
+
}
|
|
868
931
|
return {
|
|
869
932
|
isError: true,
|
|
870
933
|
content: [
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const slugWords: (slug: string) => Set<string>;
|
|
2
|
+
/** Shared words over all words (Jaccard): 1 for the same words, 0 for none in common. */
|
|
3
|
+
export declare function slugSimilarity(a: string, b: string): number;
|
|
4
|
+
/** A file at least this close to the asked name, and the only one that close, is read in its place. */
|
|
5
|
+
export declare const SKILL_FILE_MATCH = 0.5;
|
|
6
|
+
export type SkillFileGuess = {
|
|
7
|
+
kind: 'file';
|
|
8
|
+
url: string;
|
|
9
|
+
path: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'folder';
|
|
12
|
+
folder: string;
|
|
13
|
+
files: string[];
|
|
14
|
+
manifestUrl: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The closest file to a skills registry URL that 404'd, from the skill's manifest
|
|
18
|
+
* (`https://www.wix.com/skills/<skill>.manifest.json`, `{ base, files: [{ path }] }`).
|
|
19
|
+
* A file of the same name in another folder counts when it is the only one; a near name
|
|
20
|
+
* counts in the same folder only. Null when the URL is not a skill file or the manifest
|
|
21
|
+
* can't be read.
|
|
22
|
+
*/
|
|
23
|
+
export declare function closestSkillFile(url: string, manifest: {
|
|
24
|
+
base?: string;
|
|
25
|
+
files?: {
|
|
26
|
+
path: string;
|
|
27
|
+
}[];
|
|
28
|
+
}, manifestUrl: string): SkillFileGuess | null;
|
|
29
|
+
/** The manifest of the skill a registry URL is in, or null for a URL that names no skill. */
|
|
30
|
+
export declare function skillManifestUrl(url: string): string | null;
|
|
31
|
+
/** How far above a docs page the nearest menu is looked for. */
|
|
32
|
+
export declare const MENU_WALK_UP_LEVELS = 3;
|
|
33
|
+
/** The menus above a dev.wix.com docs URL, nearest first. */
|
|
34
|
+
export declare function parentMenuUrls(url: string): string[];
|
|
35
|
+
/** The menu's own entries (links under it) whose last segment is closest to the asked page, best first. */
|
|
36
|
+
export declare function closestMenuLinks(menuText: string, menuUrl: string, askedUrl: string, limit?: number): string[];
|
|
37
|
+
/** Below this, a menu's best entry is no answer, and its closest sub-menus are read too. */
|
|
38
|
+
export declare const MENU_ENTRY_MATCH = 0.75;
|
|
39
|
+
/** The menu's sub-menus worth reading for the asked page: its entries sharing a word with it, closest first. */
|
|
40
|
+
export declare function subMenusToRead(menuText: string, menuUrl: string, askedUrl: string, limit?: number): string[];
|
|
41
|
+
//# sourceMappingURL=guessed-url.d.ts.map
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What ReadFullDocsArticle offers for a docs or skills URL that 404s. Most of these are
|
|
3
|
+
* guessed: a method slug invented under a real resource, a recipe link "tidied" into a
|
|
4
|
+
* path that never existed, a skill file renamed since an agent's notes were written.
|
|
5
|
+
* Instead of a bare not-found, the agent gets the nearest thing that exists:
|
|
6
|
+
*
|
|
7
|
+
* - a skills registry file: the skill's manifest names every file, so a file whose name
|
|
8
|
+
* is close to the asked one, in the same folder, is read in its place; otherwise the
|
|
9
|
+
* folder's files are listed;
|
|
10
|
+
* - a dev.wix.com docs page: the nearest menu above it, with the links whose names are
|
|
11
|
+
* closest to the asked page listed first.
|
|
12
|
+
*/
|
|
13
|
+
import { normalizeSkillsUrl } from './fetch-article.js';
|
|
14
|
+
const SKILLS_BASE = 'https://www.wix.com/skills/';
|
|
15
|
+
// Every host and path ReadFullDocsArticle accepts for the skills registry, as the
|
|
16
|
+
// www.wix.com/skills/ URL whose manifest is next to it.
|
|
17
|
+
const registryUrl = (url) => normalizeSkillsUrl(url).replace(/^https:\/\/(?:dev\.wix\.com(?:\/docs)?|www\.wix\.com\/velo\/reference)\/skills\//, SKILLS_BASE);
|
|
18
|
+
const DOCS_BASE = 'https://dev.wix.com/docs/';
|
|
19
|
+
// Words that say nothing about which file or page is meant.
|
|
20
|
+
const FILLER = new Set([
|
|
21
|
+
'',
|
|
22
|
+
'md',
|
|
23
|
+
'a',
|
|
24
|
+
'an',
|
|
25
|
+
'the',
|
|
26
|
+
'and',
|
|
27
|
+
'or',
|
|
28
|
+
'of',
|
|
29
|
+
'to',
|
|
30
|
+
'wix',
|
|
31
|
+
's'
|
|
32
|
+
]);
|
|
33
|
+
export const slugWords = (slug) => new Set(slug
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.replace(/\.md$/, '')
|
|
36
|
+
.split(/[^a-z0-9]+/)
|
|
37
|
+
.filter((w) => !FILLER.has(w))
|
|
38
|
+
// A plural names the same thing: posts, post.
|
|
39
|
+
.map((w) => (w.length > 3 && w.endsWith('s') ? w.slice(0, -1) : w)));
|
|
40
|
+
/** Shared words over all words (Jaccard): 1 for the same words, 0 for none in common. */
|
|
41
|
+
export function slugSimilarity(a, b) {
|
|
42
|
+
const x = slugWords(a);
|
|
43
|
+
const y = slugWords(b);
|
|
44
|
+
if (x.size === 0 || y.size === 0)
|
|
45
|
+
return 0;
|
|
46
|
+
let shared = 0;
|
|
47
|
+
for (const w of x)
|
|
48
|
+
if (y.has(w))
|
|
49
|
+
shared++;
|
|
50
|
+
return shared / (x.size + y.size - shared);
|
|
51
|
+
}
|
|
52
|
+
const lastSegment = (path) => path.slice(path.lastIndexOf('/') + 1);
|
|
53
|
+
const folderOf = (path) => path.includes('/') ? path.slice(0, path.lastIndexOf('/')) : '';
|
|
54
|
+
/** A file at least this close to the asked name, and the only one that close, is read in its place. */
|
|
55
|
+
export const SKILL_FILE_MATCH = 0.5;
|
|
56
|
+
/**
|
|
57
|
+
* The closest file to a skills registry URL that 404'd, from the skill's manifest
|
|
58
|
+
* (`https://www.wix.com/skills/<skill>.manifest.json`, `{ base, files: [{ path }] }`).
|
|
59
|
+
* A file of the same name in another folder counts when it is the only one; a near name
|
|
60
|
+
* counts in the same folder only. Null when the URL is not a skill file or the manifest
|
|
61
|
+
* can't be read.
|
|
62
|
+
*/
|
|
63
|
+
export function closestSkillFile(url, manifest, manifestUrl) {
|
|
64
|
+
const normalized = registryUrl(url).replace(/[?#].*$/, '');
|
|
65
|
+
if (!normalized.startsWith(SKILLS_BASE))
|
|
66
|
+
return null;
|
|
67
|
+
const [, ...rest] = normalized.slice(SKILLS_BASE.length).split('/');
|
|
68
|
+
const asked = rest.join('/');
|
|
69
|
+
const paths = (manifest.files ?? []).map((f) => f.path);
|
|
70
|
+
if (!asked || paths.length === 0)
|
|
71
|
+
return null;
|
|
72
|
+
const base = manifest.base ?? manifestUrl.replace(/\.manifest\.json$/, '/');
|
|
73
|
+
const name = lastSegment(asked);
|
|
74
|
+
const folder = folderOf(asked);
|
|
75
|
+
const sameName = paths.filter((p) => lastSegment(p) === name);
|
|
76
|
+
if (sameName.length === 1) {
|
|
77
|
+
return { kind: 'file', path: sameName[0], url: base + sameName[0] };
|
|
78
|
+
}
|
|
79
|
+
const ranked = paths
|
|
80
|
+
.filter((p) => folderOf(p) === folder)
|
|
81
|
+
.map((p) => ({ p, score: slugSimilarity(lastSegment(p), name) }))
|
|
82
|
+
.sort((a, b) => b.score - a.score);
|
|
83
|
+
const [best, next] = ranked;
|
|
84
|
+
if (best &&
|
|
85
|
+
best.score >= SKILL_FILE_MATCH &&
|
|
86
|
+
best.score > (next?.score ?? 0)) {
|
|
87
|
+
return { kind: 'file', path: best.p, url: base + best.p };
|
|
88
|
+
}
|
|
89
|
+
if (ranked.length > 0) {
|
|
90
|
+
return {
|
|
91
|
+
kind: 'folder',
|
|
92
|
+
folder,
|
|
93
|
+
files: ranked.map((r) => base + r.p),
|
|
94
|
+
manifestUrl
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// The folder doesn't exist either: the skill's top-level folders and files.
|
|
98
|
+
const top = [...new Set(paths.map((p) => p.split('/')[0]))].sort();
|
|
99
|
+
return {
|
|
100
|
+
kind: 'folder',
|
|
101
|
+
folder: '',
|
|
102
|
+
files: top.map((t) => base + t),
|
|
103
|
+
manifestUrl
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** The manifest of the skill a registry URL is in, or null for a URL that names no skill. */
|
|
107
|
+
export function skillManifestUrl(url) {
|
|
108
|
+
const normalized = registryUrl(url);
|
|
109
|
+
if (!normalized.startsWith(SKILLS_BASE))
|
|
110
|
+
return null;
|
|
111
|
+
const skill = normalized.slice(SKILLS_BASE.length).split(/[/?#]/)[0];
|
|
112
|
+
return skill ? `${SKILLS_BASE}${skill}.manifest.json` : null;
|
|
113
|
+
}
|
|
114
|
+
/** How far above a docs page the nearest menu is looked for. */
|
|
115
|
+
export const MENU_WALK_UP_LEVELS = 3;
|
|
116
|
+
// A menu this close to the root (`/docs/velo`, `/docs/api-reference/crm`) lists whole
|
|
117
|
+
// products, which says nothing about the page that was asked for.
|
|
118
|
+
const MIN_MENU_SEGMENTS = 3;
|
|
119
|
+
/** The menus above a dev.wix.com docs URL, nearest first. */
|
|
120
|
+
export function parentMenuUrls(url) {
|
|
121
|
+
const clean = url.replace(/[?#].*$/, '').replace(/\/+$/, '');
|
|
122
|
+
if (!clean.startsWith(DOCS_BASE))
|
|
123
|
+
return [];
|
|
124
|
+
const segments = clean.slice(DOCS_BASE.length).split('/');
|
|
125
|
+
const out = [];
|
|
126
|
+
for (let up = 1; up <= MENU_WALK_UP_LEVELS; up++) {
|
|
127
|
+
const kept = segments.length - up;
|
|
128
|
+
if (kept < MIN_MENU_SEGMENTS)
|
|
129
|
+
break;
|
|
130
|
+
out.push(DOCS_BASE + segments.slice(0, kept).join('/'));
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
/** The menu's own entries (links under it) whose last segment is closest to the asked page, best first. */
|
|
135
|
+
export function closestMenuLinks(menuText, menuUrl, askedUrl, limit = 3) {
|
|
136
|
+
const asked = lastSegment(askedUrl.replace(/[?#].*$/, '').replace(/\/+$/, ''));
|
|
137
|
+
const under = `${menuUrl.replace(/\/+$/, '')}/`;
|
|
138
|
+
const links = [
|
|
139
|
+
...new Set(menuText.match(/https:\/\/dev\.wix\.com\/docs\/[^\s)\]>"'`]+/g) ?? [])
|
|
140
|
+
].filter((l) => l.startsWith(under));
|
|
141
|
+
return links
|
|
142
|
+
.map((l) => ({
|
|
143
|
+
l,
|
|
144
|
+
score: slugSimilarity(lastSegment(l.replace(/\.md$/, '')), asked)
|
|
145
|
+
}))
|
|
146
|
+
.filter((r) => r.score > 0)
|
|
147
|
+
.sort((a, b) => b.score - a.score)
|
|
148
|
+
.slice(0, limit)
|
|
149
|
+
.map((r) => r.l);
|
|
150
|
+
}
|
|
151
|
+
const SMALL_MENU = 3;
|
|
152
|
+
/** Below this, a menu's best entry is no answer, and its closest sub-menus are read too. */
|
|
153
|
+
export const MENU_ENTRY_MATCH = 0.75;
|
|
154
|
+
/** The menu's sub-menus worth reading for the asked page: its entries sharing a word with it, closest first. */
|
|
155
|
+
export function subMenusToRead(menuText, menuUrl, askedUrl, limit = 2) {
|
|
156
|
+
const asked = lastSegment(askedUrl.replace(/[?#].*$/, '').replace(/\/+$/, ''));
|
|
157
|
+
const under = `${menuUrl.replace(/\/+$/, '')}/`;
|
|
158
|
+
// A method entry (`- [Create Order](…) _(POST)_`) is a page, not a menu.
|
|
159
|
+
const methods = new Set([
|
|
160
|
+
...menuText.matchAll(/\]\((https:\/\/dev\.wix\.com\/docs\/[^)\s]+)\)\s*_\((?:GET|POST|PUT|PATCH|DELETE)\)_/g)
|
|
161
|
+
].map((m) => m[1]));
|
|
162
|
+
// Direct children only: the legacy menu text also lists pages nested further down.
|
|
163
|
+
const entries = [
|
|
164
|
+
...new Set(menuText.match(/https:\/\/dev\.wix\.com\/docs\/[^\s)\]>"'`]+/g) ?? [])
|
|
165
|
+
].filter((l) => l.startsWith(under) &&
|
|
166
|
+
!l.slice(under.length).replace(/\.md$/, '').includes('/') &&
|
|
167
|
+
!methods.has(l));
|
|
168
|
+
const scored = entries
|
|
169
|
+
.map((l) => ({
|
|
170
|
+
l,
|
|
171
|
+
score: slugSimilarity(lastSegment(l.replace(/\.md$/, '')), asked)
|
|
172
|
+
}))
|
|
173
|
+
.sort((a, b) => b.score - a.score);
|
|
174
|
+
if (scored.some((s) => s.score >= MENU_ENTRY_MATCH))
|
|
175
|
+
return [];
|
|
176
|
+
// A menu of a few entries is read whole: none may share a word (catalog-v1 holds
|
|
177
|
+
// catalog and inventory; products sit under catalog).
|
|
178
|
+
if (entries.length <= SMALL_MENU)
|
|
179
|
+
return entries;
|
|
180
|
+
return scored
|
|
181
|
+
.filter((s) => s.score > 0)
|
|
182
|
+
.slice(0, limit)
|
|
183
|
+
.map((s) => s.l);
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=guessed-url.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const FREE_TEXT_INFO_PARAMS: readonly ["userRequest", "siteDescription", "siteForm", "siteFunctionality", "agentIdentity", "wixAccess", "reason", "whyNotExecuteWixAPI"];
|
|
1
|
+
export declare const FREE_TEXT_INFO_PARAMS: readonly ["userRequest", "siteDescription", "siteForm", "siteFunctionality", "agentIdentity", "wixAccess", "reason", "whyNotExecuteWixAPI", "editorRequest", "templateRequest"];
|
|
2
2
|
export declare function redactPersonalData(text: string): string;
|
|
3
3
|
export declare function serializeToolParamsForBi(args: unknown): string;
|
|
4
4
|
//# sourceMappingURL=redact-personal-data.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseFileBundle } from '../api-call/site-files.js';
|
|
1
2
|
// Free-text arguments that agents fill in for BI. Their descriptions ask for no
|
|
2
3
|
// personal data; this is the backstop for what comes through anyway, applied to
|
|
3
4
|
// these fields only before tool arguments are recorded. Other arguments (API
|
|
@@ -10,7 +11,9 @@ export const FREE_TEXT_INFO_PARAMS = [
|
|
|
10
11
|
'agentIdentity',
|
|
11
12
|
'wixAccess',
|
|
12
13
|
'reason',
|
|
13
|
-
'whyNotExecuteWixAPI'
|
|
14
|
+
'whyNotExecuteWixAPI',
|
|
15
|
+
'editorRequest',
|
|
16
|
+
'templateRequest'
|
|
14
17
|
];
|
|
15
18
|
const EMAIL = /[A-Z0-9._%+-]+@[A-Z0-9-]+(?:\.[A-Z0-9-]+)*\.[A-Z]{2,}/gi;
|
|
16
19
|
// A secret's value after its name: "password: x", "token=x", "the password is x",
|
|
@@ -70,10 +73,76 @@ function redactInfoParams(value) {
|
|
|
70
73
|
}
|
|
71
74
|
return redacted;
|
|
72
75
|
}
|
|
76
|
+
// A `files` argument carries a site's text whole: the upload tool's text bundle
|
|
77
|
+
// (`=== FILE: <path> ===` sections, `base64` for binaries) or a list of
|
|
78
|
+
// `{ path, content }` entries. The BI event goes out as a GET with the
|
|
79
|
+
// arguments in the query string, and a bundle past about 12 KB fails that
|
|
80
|
+
// request and loses the row (2026-10-28: every upload above that size was
|
|
81
|
+
// missing from BI). Recorded instead: the paths and their sizes, as the upload
|
|
82
|
+
// parses them (a base64 file's decoded size), with the path list cut at
|
|
83
|
+
// MAX_LISTED_PATHS_CHARS so a 2,000-file upload stays far below that limit too.
|
|
84
|
+
const MAX_LISTED_PATHS_CHARS = 2_000;
|
|
85
|
+
function summarizeFileBundle(bundle) {
|
|
86
|
+
let sections;
|
|
87
|
+
try {
|
|
88
|
+
sections = parseFileBundle(bundle).map((file) => ({
|
|
89
|
+
path: file.path,
|
|
90
|
+
bytes: file.bytes.length
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
sections = [];
|
|
95
|
+
}
|
|
96
|
+
if (sections.length === 0) {
|
|
97
|
+
return `${new TextEncoder().encode(bundle).length} bytes, no file sections`;
|
|
98
|
+
}
|
|
99
|
+
return formatFileSummary(sections);
|
|
100
|
+
}
|
|
101
|
+
function formatFileSummary(files) {
|
|
102
|
+
const total = files.reduce((sum, file) => sum + file.bytes, 0);
|
|
103
|
+
let listed = '';
|
|
104
|
+
let shown = 0;
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
const entry = `${shown ? ', ' : ''}${file.path} (${file.bytes})`;
|
|
107
|
+
if (listed.length + entry.length > MAX_LISTED_PATHS_CHARS)
|
|
108
|
+
break;
|
|
109
|
+
listed += entry;
|
|
110
|
+
shown++;
|
|
111
|
+
}
|
|
112
|
+
const more = files.length - shown;
|
|
113
|
+
return `${files.length} file(s), ${total} bytes: ${listed}${more ? `${shown ? ', ' : ''}and ${more} more` : ''}`;
|
|
114
|
+
}
|
|
115
|
+
function compactFileParams(value) {
|
|
116
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
const record = value;
|
|
120
|
+
const files = record.files;
|
|
121
|
+
if (typeof files === 'string') {
|
|
122
|
+
return { ...record, files: summarizeFileBundle(files) };
|
|
123
|
+
}
|
|
124
|
+
if (Array.isArray(files) &&
|
|
125
|
+
files.length > 0 &&
|
|
126
|
+
files.every((entry) => entry &&
|
|
127
|
+
typeof entry === 'object' &&
|
|
128
|
+
typeof entry.content === 'string')) {
|
|
129
|
+
return {
|
|
130
|
+
...record,
|
|
131
|
+
files: formatFileSummary(files.map((entry) => ({
|
|
132
|
+
path: entry.path ?? '?',
|
|
133
|
+
bytes: new TextEncoder().encode(entry.content).length
|
|
134
|
+
})))
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
function prepareForBi(value) {
|
|
140
|
+
return compactFileParams(redactInfoParams(value));
|
|
141
|
+
}
|
|
73
142
|
// Tool arguments as recorded in BI and error reports: the arguments object, or
|
|
74
143
|
// the MCP SDK's positional argument list, with the free-text info fields
|
|
75
|
-
// redacted.
|
|
144
|
+
// redacted and a `files` argument reduced to its paths and sizes.
|
|
76
145
|
export function serializeToolParamsForBi(args) {
|
|
77
|
-
return JSON.stringify(Array.isArray(args) ? args.map(
|
|
146
|
+
return JSON.stringify(Array.isArray(args) ? args.map(prepareForBi) : prepareForBi(args));
|
|
78
147
|
}
|
|
79
148
|
//# sourceMappingURL=redact-personal-data.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SITE_BUILDER_TOOL_NAME = "
|
|
1
|
+
export declare const SITE_BUILDER_TOOL_NAME = "WixHarmonyEditorBuild";
|
|
2
2
|
export declare const EDIT_SITE_TOOL_NAME = "EditSite";
|
|
3
3
|
export declare const PULL_SITE_JOB_TOOL_NAME = "pullSiteCreationJob";
|
|
4
4
|
export declare const CLAIM_SITE_TOOL_NAME = "ClaimAnonymousSite";
|
|
@@ -10,7 +10,7 @@ export declare const PICK_IMAGES_TOOL_NAME = "PickImagesForWixMedia";
|
|
|
10
10
|
export declare const MEDIA_UPLOAD_URL_TOOL_NAME = "CreateWixMediaUploadUrl";
|
|
11
11
|
/** The Wix business features that send a site to StartHeadlessBuild: what wix-headless-kit ships. */
|
|
12
12
|
export declare const WIX_BUSINESS_FEATURES = "a store, bookings or appointments, rentals, events and tickets, a restaurant menu with online orders or reservations, a blog, a portfolio, pricing plans and memberships, donations, Wix Forms, members and login, a CMS, payments";
|
|
13
|
-
/**
|
|
13
|
+
/** WixHarmonyEditorBuild's and SearchSiteTemplates' answer when the agent says the user did not ask for them. */
|
|
14
14
|
/**
|
|
15
15
|
* The widget payload of a refused editor call: the gallery and builder widgets render nothing
|
|
16
16
|
* for it, since the host mounts them for every call of their tool.
|
|
@@ -20,7 +20,7 @@ export declare const NOT_REQUESTED_WIDGET_PAYLOAD: {
|
|
|
20
20
|
};
|
|
21
21
|
export declare const EDITOR_NOT_REQUESTED_MESSAGE = "Nothing was created: the user did not ask for this. A new site is written in code and uploaded: call StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features. Don't offer Wix's editor or a template instead.";
|
|
22
22
|
/** WixSiteCreation's answer: it no longer opens a chooser, it sends the agent to the code path. */
|
|
23
|
-
export declare const SITE_CREATION_ROUTE_MESSAGE = "A new site is written in code and uploaded. Call StartDeployWebsite now for the upload guide, or StartHeadlessBuild when the site needs Wix business features. Use
|
|
23
|
+
export declare const SITE_CREATION_ROUTE_MESSAGE = "A new site is written in code and uploaded. Call StartDeployWebsite now for the upload guide, or StartHeadlessBuild when the site needs Wix business features. Use WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for the Wix Harmony Editor, a template, Wix Studio or the Classic Editor.";
|
|
24
24
|
/** Fallback actions when the industry is generic or unclear. */
|
|
25
25
|
export declare const SITE_CREATION_DEFAULT_ACTIONS = "add products, set up bookings, and adjust your content";
|
|
26
26
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Tool name constants - separated to avoid circular dependencies during widget builds
|
|
2
2
|
// These constants can be imported by both the widgets and the tool implementations
|
|
3
3
|
// Named in SERVER_INSTRUCTIONS (config/default-config.ts): when this tool's name or what it is for changes, update them to match.
|
|
4
|
-
export const SITE_BUILDER_TOOL_NAME = '
|
|
4
|
+
export const SITE_BUILDER_TOOL_NAME = 'WixHarmonyEditorBuild';
|
|
5
5
|
export const EDIT_SITE_TOOL_NAME = 'EditSite';
|
|
6
6
|
export const PULL_SITE_JOB_TOOL_NAME = 'pullSiteCreationJob';
|
|
7
7
|
export const CLAIM_SITE_TOOL_NAME = 'ClaimAnonymousSite';
|
|
@@ -15,7 +15,7 @@ export const PICK_IMAGES_TOOL_NAME = 'PickImagesForWixMedia';
|
|
|
15
15
|
export const MEDIA_UPLOAD_URL_TOOL_NAME = 'CreateWixMediaUploadUrl';
|
|
16
16
|
/** The Wix business features that send a site to StartHeadlessBuild: what wix-headless-kit ships. */
|
|
17
17
|
export const WIX_BUSINESS_FEATURES = 'a store, bookings or appointments, rentals, events and tickets, a restaurant menu with online orders or reservations, a blog, a portfolio, pricing plans and memberships, donations, Wix Forms, members and login, a CMS, payments';
|
|
18
|
-
/**
|
|
18
|
+
/** WixHarmonyEditorBuild's and SearchSiteTemplates' answer when the agent says the user did not ask for them. */
|
|
19
19
|
/**
|
|
20
20
|
* The widget payload of a refused editor call: the gallery and builder widgets render nothing
|
|
21
21
|
* for it, since the host mounts them for every call of their tool.
|
|
@@ -23,7 +23,7 @@ export const WIX_BUSINESS_FEATURES = 'a store, bookings or appointments, rentals
|
|
|
23
23
|
export const NOT_REQUESTED_WIDGET_PAYLOAD = { notRequested: true };
|
|
24
24
|
export const EDITOR_NOT_REQUESTED_MESSAGE = `Nothing was created: the user did not ask for this. A new site is written in code and uploaded: call StartDeployWebsite, or StartHeadlessBuild when it needs Wix business features. Don't offer Wix's editor or a template instead.`;
|
|
25
25
|
/** WixSiteCreation's answer: it no longer opens a chooser, it sends the agent to the code path. */
|
|
26
|
-
export const SITE_CREATION_ROUTE_MESSAGE = `A new site is written in code and uploaded. Call StartDeployWebsite now for the upload guide, or StartHeadlessBuild when the site needs Wix business features. Use
|
|
26
|
+
export const SITE_CREATION_ROUTE_MESSAGE = `A new site is written in code and uploaded. Call StartDeployWebsite now for the upload guide, or StartHeadlessBuild when the site needs Wix business features. Use WixHarmonyEditorBuild or SearchSiteTemplates only when the user asked for the Wix Harmony Editor, a template, Wix Studio or the Classic Editor.`;
|
|
27
27
|
/** Fallback actions when the industry is generic or unclear. */
|
|
28
28
|
export const SITE_CREATION_DEFAULT_ACTIONS = 'add products, set up bookings, and adjust your content';
|
|
29
29
|
/**
|
|
@@ -13,7 +13,7 @@ export function addPullSiteJobTool(server, authStrategy, options) {
|
|
|
13
13
|
title: 'Pull Site Job',
|
|
14
14
|
description: isWidgetClient
|
|
15
15
|
? 'Poll the status of a site creation or editing job. Do not call this tool unless the user explicitly asks for status polling.'
|
|
16
|
-
: 'Poll the status of a site creation or editing job. Call this tool with the jobId returned by
|
|
16
|
+
: 'Poll the status of a site creation or editing job. Call this tool with the jobId returned by WixHarmonyEditorBuild or EditSite to check if the site build is complete. When the job status is COMPLETED, the response includes the previewUrl and editorUrl.',
|
|
17
17
|
inputSchema: {
|
|
18
18
|
jobId: z.string().describe('The job ID to pull')
|
|
19
19
|
},
|