@wix/mcp 1.0.97 → 1.0.98

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.
@@ -100102,10 +100102,7 @@ function addSuggestedDomainTool(server2, authStrategy2) {
100102
100102
  openWorldHint: false
100103
100103
  },
100104
100104
  _meta: {
100105
- securitySchemes: [
100106
- { type: "noauth" },
100107
- { type: "oauth2", scopes: ["offline_access"] }
100108
- ],
100105
+ securitySchemes: [{ type: "oauth2", scopes: ["offline_access"] }],
100109
100106
  // Model-visible so hosts (e.g. Microsoft 365 Copilot) can call it directly and show it
100110
100107
  // in their debug info; 'app' keeps it callable from the site-builder widget.
100111
100108
  ui: { visibility: ["app", "model"] },
@@ -100331,10 +100328,7 @@ function addDomainAvailabilityTool(server2) {
100331
100328
  openWorldHint: false
100332
100329
  },
100333
100330
  _meta: {
100334
- securitySchemes: [
100335
- { type: "noauth" },
100336
- { type: "oauth2", scopes: ["offline_access"] }
100337
- ],
100331
+ securitySchemes: [{ type: "oauth2", scopes: ["offline_access"] }],
100338
100332
  ui: { visibility: ["app", "model"] },
100339
100333
  "openai/toolInvocation/invoking": "Checking domain availability",
100340
100334
  "openai/toolInvocation/invoked": "Domain availability checked"
@@ -20923,6 +20923,7 @@ __export(index_exports, {
20923
20923
  addEditSiteWidgetTool: () => addEditSiteWidgetTool,
20924
20924
  addExecuteCodeModeTool: () => addExecuteCodeModeTool,
20925
20925
  addGetProfileTool: () => addGetProfileTool,
20926
+ addGetWixelAssetFilesTool: () => addGetWixelAssetFilesTool,
20926
20927
  addGetWixelAssetTool: () => addGetWixelAssetTool,
20927
20928
  addGetWixelJobStatusTool: () => addGetWixelJobStatusTool,
20928
20929
  addGetWixelProjectAssetsTool: () => addGetWixelProjectAssetsTool,
@@ -49123,10 +49124,7 @@ function addSuggestedDomainTool(server, authStrategy) {
49123
49124
  openWorldHint: false
49124
49125
  },
49125
49126
  _meta: {
49126
- securitySchemes: [
49127
- { type: "noauth" },
49128
- { type: "oauth2", scopes: ["offline_access"] }
49129
- ],
49127
+ securitySchemes: [{ type: "oauth2", scopes: ["offline_access"] }],
49130
49128
  // Model-visible so hosts (e.g. Microsoft 365 Copilot) can call it directly and show it
49131
49129
  // in their debug info; 'app' keeps it callable from the site-builder widget.
49132
49130
  ui: { visibility: ["app", "model"] },
@@ -49352,10 +49350,7 @@ function addDomainAvailabilityTool(server) {
49352
49350
  openWorldHint: false
49353
49351
  },
49354
49352
  _meta: {
49355
- securitySchemes: [
49356
- { type: "noauth" },
49357
- { type: "oauth2", scopes: ["offline_access"] }
49358
- ],
49353
+ securitySchemes: [{ type: "oauth2", scopes: ["offline_access"] }],
49359
49354
  ui: { visibility: ["app", "model"] },
49360
49355
  "openai/toolInvocation/invoking": "Checking domain availability",
49361
49356
  "openai/toolInvocation/invoked": "Domain availability checked"
@@ -51915,6 +51910,59 @@ async function getStylePresetsByIds2({
51915
51910
  };
51916
51911
  });
51917
51912
  }
51913
+ function wixelHostClient({
51914
+ siteAuthHeaders,
51915
+ apiBaseURL = WWW_ASSET_V1_ASSET_API_BASE_URL,
51916
+ conductorOverride
51917
+ }) {
51918
+ return (0, import_http_client14.createHttpClient)({
51919
+ headers: {
51920
+ ...COMMON_HEADERS,
51921
+ ...siteAuthHeaders,
51922
+ ...conductorOverride ? { ...CONDUCTOR_OVERRIDE_HEADERS } : {}
51923
+ },
51924
+ baseURL: apiBaseURL
51925
+ });
51926
+ }
51927
+ var WIXEL_HOST_EXPORT_ASSET_PATH = "/_api/wixel/v1/export/asset";
51928
+ var WIXEL_HOST_EXPORT_STATE_PATH = "/_api/wixel/v1/export/state";
51929
+ async function startAssetExport({
51930
+ assetId,
51931
+ params,
51932
+ ...options
51933
+ }) {
51934
+ const { data } = await wixelHostClient(options).post(
51935
+ WIXEL_HOST_EXPORT_ASSET_PATH,
51936
+ {
51937
+ projectId: options.projectId,
51938
+ assetId,
51939
+ assetType: options.assetType,
51940
+ ...params ? { params } : {}
51941
+ }
51942
+ );
51943
+ if (!data?.jobId) {
51944
+ throw new Error("Wixel did not start an export job for this asset");
51945
+ }
51946
+ return data.jobId;
51947
+ }
51948
+ async function getAssetExportState({
51949
+ jobId,
51950
+ ...options
51951
+ }) {
51952
+ const { data } = await wixelHostClient(options).post(WIXEL_HOST_EXPORT_STATE_PATH, {
51953
+ jobId,
51954
+ projectId: options.projectId,
51955
+ assetType: options.assetType
51956
+ });
51957
+ const state = data?.state ?? {};
51958
+ return {
51959
+ complete: state.complete === true,
51960
+ progress: state.progress ?? null,
51961
+ url: state.url ?? null,
51962
+ errorDescription: state.errorDescription ?? null,
51963
+ title: state.title ?? null
51964
+ };
51965
+ }
51918
51966
 
51919
51967
  // src/wixel/get-wixel-job-status-tool.ts
51920
51968
  var TOOL_NAME = "getWixelJobStatus";
@@ -52571,6 +52619,29 @@ async function getWixelSessionProjectId({
52571
52619
  const session = data?.sessions?.find((entry) => entry.id === sessionId);
52572
52620
  return session?.projectId ?? null;
52573
52621
  }
52622
+ var PREVIEW_TOOLS = /* @__PURE__ */ new Set([
52623
+ "generate_image",
52624
+ "edit_image",
52625
+ "remove_image_background"
52626
+ ]);
52627
+ var MAX_PREVIEW_URLS = 4;
52628
+ function collectPreviewUrls(messages, askIndex, turnId) {
52629
+ const urls = [];
52630
+ for (let i = 0; i <= askIndex; i++) {
52631
+ const message = messages[i];
52632
+ if (turnId && message.turnId !== turnId) continue;
52633
+ for (const part of message.parts ?? []) {
52634
+ const response = part.functionResponse;
52635
+ if (!response?.name || !PREVIEW_TOOLS.has(response.name)) continue;
52636
+ for (const url of extractMediaUrls(
52637
+ JSON.stringify(response.response ?? "")
52638
+ )) {
52639
+ if (!urls.includes(url)) urls.push(url);
52640
+ }
52641
+ }
52642
+ }
52643
+ return urls.slice(-MAX_PREVIEW_URLS);
52644
+ }
52574
52645
  async function getWixelSessionActivity({
52575
52646
  sessionId,
52576
52647
  ...base
@@ -52662,10 +52733,12 @@ async function getWixelPendingQuestion({
52662
52733
  const questions = call.args?.questions ?? [];
52663
52734
  if (!questions.length) continue;
52664
52735
  if (ownTurn && message.turnId !== ownTurn) return null;
52736
+ const previewUrls = collectPreviewUrls(messages, i, message.turnId);
52665
52737
  return {
52666
52738
  toolCallId: call.id,
52667
52739
  turnId: message.turnId,
52668
- questions
52740
+ questions,
52741
+ ...previewUrls.length ? { previewUrls } : {}
52669
52742
  };
52670
52743
  }
52671
52744
  if (part.text || part.functionCall || part.functionResponse) {
@@ -53026,14 +53099,20 @@ Call this when get_wixel_task flags a question, or its reply asks the user somet
53026
53099
  const summary = pending.questions.map(
53027
53100
  (question, index) => `${index + 1}. [${question.kind}] ${question.title ?? ""}${question.customCanvas?.componentName ? ` (${question.customCanvas.componentName})` : ""}`
53028
53101
  ).join("\n");
53102
+ const previewUrls = pending.previewUrls ?? [];
53103
+ const previewText = previewUrls.length ? `
53104
+
53105
+ Sample made so far (what the user is approving):
53106
+ ${previewUrls.map((url) => `- ${url}`).join("\n")}` : "";
53107
+ const previewInstruction = previewUrls.length ? "Show the user the sample first: give the link(s) above and, when you can write files, save them under assets/_preview/ (for example assets/_preview/sample-1.png) and name the path, so the user sees the look before answering. " : "";
53029
53108
  const responseText = widgetShown ? `An interactive question widget is displayed to the user (questionId: ${pending.toolCallId}):
53030
53109
  ${summary}
53031
53110
  <agent_instruction>Do NOT repeat the question content as text \u2014 the user answers inside the widget, which sends the answer to Wixel itself. This is NOT a turn-taking situation: the result of the user's widget answer reaches YOU only through get_wixel_task \u2014 nothing wakes you if you stop, and ending your turn BREAKS the flow (the result would never be delivered).
53032
53111
  Therefore: briefly tell the user to answer in the widget, then keep calling get_wixel_task (taskId: "${args.taskId}", metaSiteId: "${args.metaSiteId}", waitSeconds: 25) in a continuous loop, and do NOT end your turn until it reports the turn done, however long it takes (the user may think for a while, then generation takes minutes). If it names a newer taskId (the widget's answer opened a new turn), follow that one.
53033
53112
  - Polls that flag questionId ${pending.toolCallId} mean the user has not answered THIS question yet \u2014 do NOT call get_wixel_pending_question again for it, just keep polling.
53034
53113
  - When the turn is done: if the response flags a NEW interactive question, call get_wixel_pending_question again (it renders the next widget). Otherwise present the reply to the user as a normal chat message, always including the "Edit in Wixel" link when provided.</agent_instruction>` : `The Wixel agent asked:
53035
- ${summary}
53036
- <agent_instruction>Present the question(s) with their options/content to the user, then send their answer as plain text via send_wixel_message (contextId: "${args.contextId}", metaSiteId: "${args.metaSiteId}") and poll get_wixel_task for the taskId it returns.</agent_instruction>`;
53114
+ ${summary}${previewText}
53115
+ <agent_instruction>${previewInstruction}Present the question(s) with their options/content to the user, then send their answer as plain text via send_wixel_message (contextId: "${args.contextId}", metaSiteId: "${args.metaSiteId}") and poll get_wixel_task for the taskId it returns.</agent_instruction>`;
53037
53116
  return {
53038
53117
  isError: false,
53039
53118
  content: [{ type: "text", text: responseText }],
@@ -53996,6 +54075,358 @@ function addWixelSessionTools(server, authStrategy, options = {}) {
53996
54075
  addGetWixelTurnResultTool(server, authStrategy, shared);
53997
54076
  }
53998
54077
 
54078
+ // src/wixel/app-icon-files.ts
54079
+ var WIX_MEDIA_FILE = /^(https:\/\/static\.wixstatic\.com\/media\/[^/?#]+)/;
54080
+ var ANDROID_MIPMAPS = [
54081
+ ["mdpi", 48],
54082
+ ["hdpi", 72],
54083
+ ["xhdpi", 96],
54084
+ ["xxhdpi", 144],
54085
+ ["xxxhdpi", 192]
54086
+ ];
54087
+ function wixMediaFileUrl(url) {
54088
+ return WIX_MEDIA_FILE.exec(url)?.[1] ?? null;
54089
+ }
54090
+ function wixMediaSquarePng(fileUrl, size) {
54091
+ return `${fileUrl}/v1/fill/w_${size},h_${size},al_c,q_95/icon-${size}.png`;
54092
+ }
54093
+ function buildAppIconFiles(exportedPngUrl, appName) {
54094
+ const file = wixMediaFileUrl(exportedPngUrl);
54095
+ if (!file) {
54096
+ return null;
54097
+ }
54098
+ const png = (path, size) => ({
54099
+ path,
54100
+ url: wixMediaSquarePng(file, size)
54101
+ });
54102
+ return [
54103
+ png("ios/AppIcon.appiconset/icon-1024.png", 1024),
54104
+ {
54105
+ path: "ios/AppIcon.appiconset/Contents.json",
54106
+ content: JSON.stringify(
54107
+ {
54108
+ images: [
54109
+ {
54110
+ filename: "icon-1024.png",
54111
+ idiom: "universal",
54112
+ platform: "ios",
54113
+ size: "1024x1024"
54114
+ }
54115
+ ],
54116
+ info: { author: "wixel", version: 1 }
54117
+ },
54118
+ null,
54119
+ 2
54120
+ )
54121
+ },
54122
+ ...ANDROID_MIPMAPS.map(
54123
+ ([density, size]) => png(`android/res/mipmap-${density}/ic_launcher.png`, size)
54124
+ ),
54125
+ png("android/play-store-512.png", 512),
54126
+ png("web/favicon-16.png", 16),
54127
+ png("web/favicon-32.png", 32),
54128
+ png("web/favicon-48.png", 48),
54129
+ png("web/apple-touch-icon.png", 180),
54130
+ png("web/icon-192.png", 192),
54131
+ png("web/icon-512.png", 512),
54132
+ {
54133
+ path: "web/site.webmanifest",
54134
+ content: JSON.stringify(
54135
+ {
54136
+ name: appName,
54137
+ short_name: appName.slice(0, 12),
54138
+ icons: [
54139
+ { src: "icon-192.png", sizes: "192x192", type: "image/png" },
54140
+ { src: "icon-512.png", sizes: "512x512", type: "image/png" }
54141
+ ],
54142
+ display: "standalone"
54143
+ },
54144
+ null,
54145
+ 2
54146
+ )
54147
+ }
54148
+ ];
54149
+ }
54150
+
54151
+ // src/wixel/wixel-asset-files-tool.ts
54152
+ var ASSET_FILE_LAYOUTS = ["files", "spriteSheet", "appIcons"];
54153
+ var ICONS_FILE_TYPES = [
54154
+ "png",
54155
+ "pngTransparentBackground",
54156
+ "svg",
54157
+ "svgTransparentBackground"
54158
+ ];
54159
+ var ICONS_SIZES = [
54160
+ "16px",
54161
+ "24px",
54162
+ "32px",
54163
+ "64px",
54164
+ "128px",
54165
+ "256px",
54166
+ "512px"
54167
+ ];
54168
+ var POLL_INTERVAL_MS = 2e3;
54169
+ var MAX_WAIT_SECONDS = 25;
54170
+ function buildExportParams(assetType, args) {
54171
+ const layout = args.layout ?? "files";
54172
+ if (assetType === "IMAGE" && layout === "appIcons") {
54173
+ return { format: "png", quality: 100, scale: 1 };
54174
+ }
54175
+ if (assetType !== "ICONS") {
54176
+ if (layout !== "files") {
54177
+ throw new Error(
54178
+ layout === "appIcons" ? `layout "appIcons" needs an ICONS or IMAGE asset (the app icon); this asset is ${assetType}` : `layout "${layout}" needs an ICONS asset (an icon / sprite set); this asset is ${assetType}`
54179
+ );
54180
+ }
54181
+ return void 0;
54182
+ }
54183
+ if (layout === "files") {
54184
+ return {
54185
+ // Engines and app projects want plain transparent PNGs, not the
54186
+ // editor's default SVG-wrapped PNG.
54187
+ fileType: args.fileType ?? "pngTransparentBackground",
54188
+ ...args.size ? { size: args.size } : { size: "512px" }
54189
+ };
54190
+ }
54191
+ return {
54192
+ layout,
54193
+ ...layout === "spriteSheet" && args.size ? { size: args.size } : {}
54194
+ };
54195
+ }
54196
+ async function waitForExport(read, waitSeconds) {
54197
+ const deadline = Date.now() + waitSeconds * 1e3;
54198
+ let state = await read();
54199
+ while (!state.complete && !state.errorDescription && Date.now() < deadline) {
54200
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
54201
+ state = await read();
54202
+ }
54203
+ return state;
54204
+ }
54205
+ function describeContents(layout, assetType) {
54206
+ if (assetType !== "ICONS") {
54207
+ return "The file is the asset as the editor downloads it.";
54208
+ }
54209
+ switch (layout) {
54210
+ case "spriteSheet":
54211
+ return 'The zip holds <set>-sheet.png (frames on one grid, feet on one baseline), <set>-sheet.json (Aseprite array frame map: frames "0","1"\u2026, one frameTags entry per pose \u2014 load with Phaser this.load.aseprite + this.anims.createFromAseprite) and frames/<n>-<pose>.png.';
54212
+ case "appIcons":
54213
+ return "The zip holds ios/AppIcon.appiconset (1024 px + Contents.json, drop into Assets.xcassets), android/res/mipmap-*/ic_launcher.png + android/play-store-512.png, and web/ favicons, apple-touch-icon.png, icon-192/512.png and site.webmanifest.";
54214
+ default:
54215
+ return "The zip holds one transparent PNG per tile, named after the tile.";
54216
+ }
54217
+ }
54218
+ function addGetWixelAssetFilesTool(server, authStrategy, options = {}) {
54219
+ const { getSiteAuthHeaders } = authStrategy;
54220
+ server.registerTool(
54221
+ "get_wixel_asset_files",
54222
+ {
54223
+ title: "Get Wixel asset files",
54224
+ description: `Download the files of an asset made in a Wixel conversation, to use them in code (a game, an app, a site). Pass the metaSiteId and sessionId that send_wixel_message returned.
54225
+ - Without assetId: lists the project's assets (id, name, type) \u2014 pick one.
54226
+ - With assetId: exports it and returns a zip URL. For an ICONS asset choose layout:
54227
+ "files" (default) one transparent PNG per tile;
54228
+ "spriteSheet" for a character's poses / animation frames: one aligned sheet + Aseprite JSON frame map (Phaser createFromAseprite) + aligned frames;
54229
+ "appIcons" for an app or game icon: iOS app icon set, Android mipmaps + Play Store 512, web favicons + manifest.
54230
+ An IMAGE asset (an app icon tile) also takes layout "appIcons": you get one URL per file instead of a zip.
54231
+ - If the export is still running, call again with the returned jobId, assetType, layout and assetId.
54232
+ Download the URL and unzip it into the project; never re-draw or re-generate assets the user already approved.`,
54233
+ inputSchema: {
54234
+ metaSiteId: external_exports.string().describe("metaSiteId returned by send_wixel_message"),
54235
+ sessionId: external_exports.string().describe("sessionId returned by send_wixel_message"),
54236
+ assetId: external_exports.string().optional().describe("Asset to export; omit to list the project assets"),
54237
+ layout: external_exports.enum(ASSET_FILE_LAYOUTS).optional().describe(
54238
+ "ICONS assets only: files (default), spriteSheet, appIcons"
54239
+ ),
54240
+ fileType: external_exports.enum(ICONS_FILE_TYPES).optional().describe(
54241
+ 'ICONS layout "files" only; default pngTransparentBackground'
54242
+ ),
54243
+ size: external_exports.enum(ICONS_SIZES).optional().describe(
54244
+ 'ICONS: tile size for "files" (default 512px), frame cell size for "spriteSheet" (default 256px)'
54245
+ ),
54246
+ jobId: external_exports.string().optional().describe("Continue waiting on an export this tool started"),
54247
+ assetType: external_exports.string().optional().describe("With jobId: the assetType this tool returned"),
54248
+ waitSeconds: external_exports.number().min(0).max(MAX_WAIT_SECONDS).optional().describe("How long to wait for the export (default 25)")
54249
+ },
54250
+ annotations: {
54251
+ readOnlyHint: true,
54252
+ destructiveHint: false,
54253
+ openWorldHint: false
54254
+ }
54255
+ },
54256
+ async (args, extra) => {
54257
+ setWixelToolBi(extra, { siteId: args.metaSiteId });
54258
+ const siteAuthHeaders = await getSiteAuthHeaders(args.metaSiteId);
54259
+ try {
54260
+ const projectId = await getWixelSessionProjectId({
54261
+ authHeaders: siteAuthHeaders,
54262
+ conductorOverride: options.conductorOverride,
54263
+ sessionId: args.sessionId
54264
+ });
54265
+ if (!projectId) {
54266
+ throw new Error(
54267
+ "This Wixel conversation has no project yet \u2014 make something first"
54268
+ );
54269
+ }
54270
+ const base = {
54271
+ siteAuthHeaders,
54272
+ projectId,
54273
+ conductorOverride: options.conductorOverride
54274
+ };
54275
+ const waitSeconds = args.waitSeconds ?? MAX_WAIT_SECONDS;
54276
+ if (args.jobId) {
54277
+ if (!args.assetType) {
54278
+ throw new Error("Pass the assetType returned with the jobId");
54279
+ }
54280
+ const assetType2 = args.assetType;
54281
+ const state2 = await waitForExport(
54282
+ () => getAssetExportState({ ...base, assetType: assetType2, jobId: args.jobId }),
54283
+ waitSeconds
54284
+ );
54285
+ const assetName = state2.complete && args.assetId && assetType2 === "IMAGE" && args.layout === "appIcons" ? await getAsset({ ...base, assetId: args.assetId }).then((asset2) => asset2?.name).catch(() => void 0) : void 0;
54286
+ return exportResult(state2, args, assetType2, args.jobId, assetName);
54287
+ }
54288
+ if (!args.assetId) {
54289
+ const { assets } = await queryAssets(base);
54290
+ const list = (assets ?? []).filter((asset2) => !asset2.archived).map((asset2) => ({
54291
+ id: asset2.id,
54292
+ name: asset2.name ?? null,
54293
+ type: asset2.type ?? null
54294
+ }));
54295
+ return {
54296
+ isError: false,
54297
+ content: [
54298
+ {
54299
+ type: "text",
54300
+ text: `${list.length} assets in this Wixel project:
54301
+ ${list.map(
54302
+ (a2) => `- ${a2.name ?? "(unnamed)"} [${a2.type}] id=${a2.id}`
54303
+ ).join(
54304
+ "\n"
54305
+ )}
54306
+ Call get_wixel_asset_files again with the assetId to download one.`
54307
+ }
54308
+ ],
54309
+ structuredContent: { success: true, projectId, assets: list }
54310
+ };
54311
+ }
54312
+ const asset = await getAsset({ ...base, assetId: args.assetId });
54313
+ const assetType = asset?.type;
54314
+ if (!assetType) {
54315
+ throw new Error(
54316
+ `Asset ${args.assetId} was not found in this project`
54317
+ );
54318
+ }
54319
+ const params = buildExportParams(assetType, args);
54320
+ const jobId = await startAssetExport({
54321
+ ...base,
54322
+ assetType,
54323
+ assetId: args.assetId,
54324
+ params
54325
+ });
54326
+ const state = await waitForExport(
54327
+ () => getAssetExportState({ ...base, assetType, jobId }),
54328
+ waitSeconds
54329
+ );
54330
+ return exportResult(state, args, assetType, jobId, asset?.name);
54331
+ } catch (error2) {
54332
+ rethrowIfUnauthorized(error2);
54333
+ console.error("\u274C Error getting Wixel asset files:", {
54334
+ message: error2.message,
54335
+ requestId: error2.requestId
54336
+ });
54337
+ const errorMessage = error2.message;
54338
+ return {
54339
+ isError: true,
54340
+ content: [{ type: "text", text: errorMessage }],
54341
+ structuredContent: { success: false, error: errorMessage }
54342
+ };
54343
+ }
54344
+ }
54345
+ );
54346
+ }
54347
+ function exportResult(state, args, assetType, jobId, assetName) {
54348
+ if (state.errorDescription) {
54349
+ return {
54350
+ isError: true,
54351
+ content: [
54352
+ {
54353
+ type: "text",
54354
+ text: `Export failed: ${state.errorDescription}`
54355
+ }
54356
+ ],
54357
+ structuredContent: {
54358
+ success: false,
54359
+ error: state.errorDescription,
54360
+ jobId,
54361
+ assetType
54362
+ }
54363
+ };
54364
+ }
54365
+ const layout = args.layout ?? "files";
54366
+ if (!state.complete || !state.url) {
54367
+ return {
54368
+ isError: false,
54369
+ content: [
54370
+ {
54371
+ type: "text",
54372
+ text: `Export still running${state.progress != null ? ` (${state.progress}%)` : ""}. Call get_wixel_asset_files again with jobId "${jobId}", assetType "${assetType}", layout "${layout}"${args.assetId ? ` and assetId "${args.assetId}"` : ""}.`
54373
+ }
54374
+ ],
54375
+ structuredContent: {
54376
+ success: true,
54377
+ status: "running",
54378
+ progress: state.progress,
54379
+ jobId,
54380
+ assetType,
54381
+ layout,
54382
+ ...args.assetId ? { assetId: args.assetId } : {}
54383
+ }
54384
+ };
54385
+ }
54386
+ if (assetType === "IMAGE" && layout === "appIcons") {
54387
+ const files = buildAppIconFiles(state.url, assetName || "App");
54388
+ if (files) {
54389
+ return {
54390
+ isError: false,
54391
+ content: [
54392
+ {
54393
+ type: "text",
54394
+ text: `App icon files ready \u2014 download each URL to its path, write the JSON files as given:
54395
+ ${files.map((f2) => `- ${f2.path}: ${f2.url ?? f2.content}`).join("\n")}`
54396
+ }
54397
+ ],
54398
+ structuredContent: {
54399
+ success: true,
54400
+ status: "ready",
54401
+ url: state.url,
54402
+ files,
54403
+ jobId,
54404
+ assetType,
54405
+ layout
54406
+ }
54407
+ };
54408
+ }
54409
+ }
54410
+ return {
54411
+ isError: false,
54412
+ content: [
54413
+ {
54414
+ type: "text",
54415
+ text: `Files ready: ${state.url}
54416
+ ${describeContents(args.layout, assetType)}`
54417
+ }
54418
+ ],
54419
+ structuredContent: {
54420
+ success: true,
54421
+ status: "ready",
54422
+ url: state.url,
54423
+ jobId,
54424
+ assetType,
54425
+ layout: args.layout ?? "files"
54426
+ }
54427
+ };
54428
+ }
54429
+
53999
54430
  // src/wixel/index.ts
54000
54431
  function addWixelTools(server, authStrategy, options = {}) {
54001
54432
  addGetWixelJobStatusTool(server, authStrategy, options);
@@ -54003,6 +54434,7 @@ function addWixelTools(server, authStrategy, options = {}) {
54003
54434
  addGetWixelAssetTool(server, authStrategy, options);
54004
54435
  addGetWixelProjectAssetsTool(server, authStrategy, options);
54005
54436
  addWixelSessionTools(server, authStrategy, options);
54437
+ addGetWixelAssetFilesTool(server, authStrategy, options);
54006
54438
  }
54007
54439
 
54008
54440
  // src/import-claude-design-tool/constants.ts
@@ -56989,6 +57421,7 @@ function createWixToolkit(options) {
56989
57421
  addEditSiteWidgetTool,
56990
57422
  addExecuteCodeModeTool,
56991
57423
  addGetProfileTool,
57424
+ addGetWixelAssetFilesTool,
56992
57425
  addGetWixelAssetTool,
56993
57426
  addGetWixelJobStatusTool,
56994
57427
  addGetWixelProjectAssetsTool,
@@ -45,10 +45,7 @@ export function addDomainAvailabilityTool(server) {
45
45
  openWorldHint: false
46
46
  },
47
47
  _meta: {
48
- securitySchemes: [
49
- { type: 'noauth' },
50
- { type: 'oauth2', scopes: ['offline_access'] }
51
- ],
48
+ securitySchemes: [{ type: 'oauth2', scopes: ['offline_access'] }],
52
49
  ui: { visibility: ['app', 'model'] },
53
50
  'openai/toolInvocation/invoking': 'Checking domain availability',
54
51
  'openai/toolInvocation/invoked': 'Domain availability checked'
@@ -68,10 +68,7 @@ export function addSuggestedDomainTool(server, authStrategy) {
68
68
  openWorldHint: false
69
69
  },
70
70
  _meta: {
71
- securitySchemes: [
72
- { type: 'noauth' },
73
- { type: 'oauth2', scopes: ['offline_access'] }
74
- ],
71
+ securitySchemes: [{ type: 'oauth2', scopes: ['offline_access'] }],
75
72
  // Model-visible so hosts (e.g. Microsoft 365 Copilot) can call it directly and show it
76
73
  // in their debug info; 'app' keeps it callable from the site-builder widget.
77
74
  ui: { visibility: ['app', 'model'] },
@@ -2,14 +2,25 @@ export declare const UNAUTHORIZED_ERROR_NAME = "UnauthorizedError";
2
2
  export type McpHeaders = Record<string, string>;
3
3
  /**
4
4
  * Material the execute runtime needs to obtain a site-scoped token for any site
5
- * on demand (multi-site ExecuteWixAPI). `oauth` is exchanged for a per-site
6
- * token via the oauth2/token refresh-grant; `apiKey` works for any site as-is.
7
- * The oauth refresh token is sensitive: never log it, never expose to sandbox JS.
5
+ * on demand (multi-site ExecuteWixAPI).
6
+ *
7
+ * - `oauth`: exchanged per site via the oauth2/token refresh grant.
8
+ * - `accountToken`: an account-level user access token, exchanged per site via
9
+ * the oauth2/token RFC 8693 token-exchange grant (account token + site_id →
10
+ * site-scoped token, no client secret, no refresh token issued). For callers
11
+ * that mint short-lived account tokens and hold no refresh token, such as
12
+ * the AI Assistant platform.
13
+ * - `apiKey`: works for any site as-is; the runtime only adds `wix-site-id`.
14
+ *
15
+ * Every variant is a credential: never log it, never expose it to sandbox JS.
8
16
  */
9
17
  export type SiteAuthContext = {
10
18
  type: 'oauth';
11
19
  clientId: string;
12
20
  refreshToken: string;
21
+ } | {
22
+ type: 'accountToken';
23
+ accessToken: string;
13
24
  } | {
14
25
  type: 'apiKey';
15
26
  accessToken: string;
@@ -39,14 +39,25 @@ export declare const UNAUTHORIZED_ERROR_NAME = "UnauthorizedError";
39
39
  export type McpHeaders = Record<string, string>;
40
40
  /**
41
41
  * Material the execute runtime needs to obtain a site-scoped token for any site
42
- * on demand (multi-site ExecuteWixAPI). `oauth` is exchanged for a per-site
43
- * token via the oauth2/token refresh-grant; `apiKey` works for any site as-is.
44
- * The oauth refresh token is sensitive: never log it, never expose to sandbox JS.
42
+ * on demand (multi-site ExecuteWixAPI).
43
+ *
44
+ * - `oauth`: exchanged per site via the oauth2/token refresh grant.
45
+ * - `accountToken`: an account-level user access token, exchanged per site via
46
+ * the oauth2/token RFC 8693 token-exchange grant (account token + site_id →
47
+ * site-scoped token, no client secret, no refresh token issued). For callers
48
+ * that mint short-lived account tokens and hold no refresh token, such as
49
+ * the AI Assistant platform.
50
+ * - `apiKey`: works for any site as-is; the runtime only adds `wix-site-id`.
51
+ *
52
+ * Every variant is a credential: never log it, never expose it to sandbox JS.
45
53
  */
46
54
  export type SiteAuthContext = {
47
55
  type: "oauth";
48
56
  clientId: string;
49
57
  refreshToken: string;
58
+ } | {
59
+ type: "accountToken";
60
+ accessToken: string;
50
61
  } | {
51
62
  type: "apiKey";
52
63
  accessToken: string;
@@ -39,14 +39,25 @@ export declare const UNAUTHORIZED_ERROR_NAME = "UnauthorizedError";
39
39
  export type McpHeaders = Record<string, string>;
40
40
  /**
41
41
  * Material the execute runtime needs to obtain a site-scoped token for any site
42
- * on demand (multi-site ExecuteWixAPI). `oauth` is exchanged for a per-site
43
- * token via the oauth2/token refresh-grant; `apiKey` works for any site as-is.
44
- * The oauth refresh token is sensitive: never log it, never expose to sandbox JS.
42
+ * on demand (multi-site ExecuteWixAPI).
43
+ *
44
+ * - `oauth`: exchanged per site via the oauth2/token refresh grant.
45
+ * - `accountToken`: an account-level user access token, exchanged per site via
46
+ * the oauth2/token RFC 8693 token-exchange grant (account token + site_id →
47
+ * site-scoped token, no client secret, no refresh token issued). For callers
48
+ * that mint short-lived account tokens and hold no refresh token, such as
49
+ * the AI Assistant platform.
50
+ * - `apiKey`: works for any site as-is; the runtime only adds `wix-site-id`.
51
+ *
52
+ * Every variant is a credential: never log it, never expose it to sandbox JS.
45
53
  */
46
54
  export type SiteAuthContext = {
47
55
  type: "oauth";
48
56
  clientId: string;
49
57
  refreshToken: string;
58
+ } | {
59
+ type: "accountToken";
60
+ accessToken: string;
50
61
  } | {
51
62
  type: "apiKey";
52
63
  accessToken: string;