@olonjs/cli 3.0.100 → 3.0.104

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.
@@ -551,7 +551,6 @@ Senza questo, in Studio l'overlay non si vede nell'iframe.
551
551
  Usando questo percorso hai **governance** piena: tipi, schema, editor, Add Section e overlay allineati alle spec v1.2. Per le versioni con tutti i "Perché servono" usa il file **JSONPAGES_Specs_v1.2_completo.md**.
552
552
 
553
553
  END_OF_FILE_CONTENT
554
- mkdir -p "docs/ver"
555
554
  echo "Creating index.html..."
556
555
  cat << 'END_OF_FILE_CONTENT' > "index.html"
557
556
  <!DOCTYPE html>
@@ -597,7 +596,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
597
596
  "@tiptap/extension-link": "^2.11.5",
598
597
  "@tiptap/react": "^2.11.5",
599
598
  "@tiptap/starter-kit": "^2.11.5",
600
- "@olonjs/core": "^1.0.88",
599
+ "@olonjs/core": "^1.0.91",
601
600
  "clsx": "^2.1.1",
602
601
  "lucide-react": "^0.474.0",
603
602
  "react": "^19.0.0",
@@ -1120,304 +1119,304 @@ console.log('[sync-pages-to-public] Synced pages to public/pages');
1120
1119
  END_OF_FILE_CONTENT
1121
1120
  echo "Creating scripts/webmcp-feature-check.mjs..."
1122
1121
  cat << 'END_OF_FILE_CONTENT' > "scripts/webmcp-feature-check.mjs"
1123
- import fs from 'fs/promises';
1124
- import path from 'path';
1125
- import { fileURLToPath } from 'url';
1126
- import { createRequire } from 'module';
1127
-
1128
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
1129
- const rootDir = path.resolve(__dirname, '..');
1130
- const baseUrl = process.env.WEBMCP_BASE_URL ?? 'http://127.0.0.1:4173';
1131
-
1132
- function pageFilePathFromSlug(slug) {
1133
- return path.resolve(rootDir, 'src', 'data', 'pages', `${slug}.json`);
1134
- }
1135
-
1136
- function adminUrlFromSlug(slug) {
1137
- return `${baseUrl}/admin${slug === 'home' ? '' : `/${slug}`}`;
1138
- }
1139
-
1140
- function isStringSchema(schema) {
1141
- if (!schema || typeof schema !== 'object') return false;
1142
- if (schema.type === 'string') return true;
1143
- if (Array.isArray(schema.anyOf)) {
1144
- return schema.anyOf.some((entry) => entry && typeof entry === 'object' && entry.type === 'string');
1145
- }
1146
- return false;
1147
- }
1148
-
1149
- function findTopLevelStringField(sectionSchema) {
1150
- const properties = sectionSchema?.properties;
1151
- if (!properties || typeof properties !== 'object') return null;
1152
- const preferred = ['title', 'sectionTitle', 'label', 'headline', 'name'];
1153
- for (const key of preferred) {
1154
- if (isStringSchema(properties[key])) return key;
1155
- }
1156
- for (const [key, value] of Object.entries(properties)) {
1157
- if (isStringSchema(value)) return key;
1158
- }
1159
- return null;
1160
- }
1161
-
1162
- async function loadPlaywright() {
1163
- const require = createRequire(import.meta.url);
1164
- try {
1165
- return require('playwright');
1166
- } catch (error) {
1167
- const message = error instanceof Error ? error.message : String(error);
1168
- throw new Error(
1169
- `Playwright is required for WebMCP verification. Install it before running this script. Original error: ${message}`
1170
- );
1171
- }
1172
- }
1173
-
1174
- async function readPageJson(slug) {
1175
- const pageFilePath = pageFilePathFromSlug(slug);
1176
- const raw = await fs.readFile(pageFilePath, 'utf8');
1177
- return { raw, json: JSON.parse(raw), pageFilePath };
1178
- }
1179
-
1180
- async function waitFor(predicate, timeoutMs, label) {
1181
- const startedAt = Date.now();
1182
- for (;;) {
1183
- const result = await predicate();
1184
- if (result) return result;
1185
- if (Date.now() - startedAt > timeoutMs) {
1186
- throw new Error(`Timed out while waiting for ${label}.`);
1187
- }
1188
- await new Promise((resolve) => setTimeout(resolve, 150));
1189
- }
1190
- }
1191
-
1192
- async function waitForFileFieldValue(slug, sectionId, fieldKey, expectedValue) {
1193
- await waitFor(async () => {
1194
- const { json } = await readPageJson(slug);
1195
- const section = Array.isArray(json.sections)
1196
- ? json.sections.find((item) => item?.id === sectionId)
1197
- : null;
1198
- return section?.data?.[fieldKey] === expectedValue;
1199
- }, 8_000, `file field "${fieldKey}" = "${expectedValue}"`);
1200
- }
1201
-
1202
- async function ensureResponseOk(response, label) {
1203
- if (!response.ok) {
1204
- const text = await response.text();
1205
- throw new Error(`${label} failed with ${response.status}: ${text}`);
1206
- }
1207
- return response;
1208
- }
1209
-
1210
- async function fetchJson(relativePath, label) {
1211
- const response = await ensureResponseOk(await fetch(`${baseUrl}${relativePath}`), label);
1212
- return response.json();
1213
- }
1214
-
1215
- async function selectTarget() {
1216
- const siteIndex = await fetchJson('/mcp-manifest.json', 'Manifest index request');
1217
- const requestedSlug = typeof process.env.WEBMCP_TARGET_SLUG === 'string' && process.env.WEBMCP_TARGET_SLUG.trim()
1218
- ? process.env.WEBMCP_TARGET_SLUG.trim()
1219
- : null;
1220
-
1221
- const candidatePages = requestedSlug
1222
- ? (siteIndex.pages ?? []).filter((page) => page?.slug === requestedSlug)
1223
- : (siteIndex.pages ?? []);
1224
-
1225
- for (const pageEntry of candidatePages) {
1226
- if (!pageEntry?.slug || !pageEntry?.manifestHref || !pageEntry?.contractHref) continue;
1227
- const pageManifest = await fetchJson(pageEntry.manifestHref, `Page manifest request for ${pageEntry.slug}`);
1228
- const pageContract = await fetchJson(pageEntry.contractHref, `Page contract request for ${pageEntry.slug}`);
1229
- const localInstances = Array.isArray(pageContract.sectionInstances)
1230
- ? pageContract.sectionInstances.filter((section) => section?.scope === 'local')
1231
- : [];
1232
- const tools = Array.isArray(pageManifest.tools) ? pageManifest.tools : [];
1233
-
1234
- for (const tool of tools) {
1235
- const sectionType = tool?.sectionType;
1236
- if (typeof tool?.name !== 'string' || typeof sectionType !== 'string') continue;
1237
- const targetInstance = localInstances.find((section) => section?.type === sectionType);
1238
- if (!targetInstance?.id) continue;
1239
- const targetFieldKey = findTopLevelStringField(pageContract.sectionSchemas?.[sectionType]);
1240
- if (!targetFieldKey) continue;
1241
- const pageState = await readPageJson(pageEntry.slug);
1242
- const section = Array.isArray(pageState.json.sections)
1243
- ? pageState.json.sections.find((item) => item?.id === targetInstance.id)
1244
- : null;
1245
- const originalValue = section?.data?.[targetFieldKey];
1246
- if (typeof originalValue !== 'string') continue;
1247
-
1248
- return {
1249
- slug: pageEntry.slug,
1250
- manifestHref: pageEntry.manifestHref,
1251
- contractHref: pageEntry.contractHref,
1252
- toolName: tool.name,
1253
- sectionId: targetInstance.id,
1254
- fieldKey: targetFieldKey,
1255
- originalValue,
1256
- originalState: pageState,
1257
- };
1258
- }
1259
- }
1260
-
1261
- throw new Error(
1262
- requestedSlug
1263
- ? `No valid WebMCP verification target found for page "${requestedSlug}".`
1264
- : 'No valid WebMCP verification target found in manifest index.'
1265
- );
1266
- }
1267
-
1268
- async function main() {
1269
- const { chromium } = await loadPlaywright();
1270
- const target = await selectTarget();
1271
- const nextValue = `${target.originalValue} WebMCP ${Date.now()}`;
1272
- const browser = await chromium.launch({ headless: true });
1273
- const page = await browser.newPage();
1274
- const consoleEvents = [];
1275
- let mutationApplied = false;
1276
-
1277
- page.on('console', (message) => {
1278
- if (message.type() === 'error' || message.type() === 'warning') {
1279
- consoleEvents.push(`[console:${message.type()}] ${message.text()}`);
1280
- }
1281
- });
1282
- page.on('pageerror', (error) => {
1283
- consoleEvents.push(`[pageerror] ${error.message}`);
1284
- });
1285
-
1286
- const restoreOriginal = async () => {
1287
- try {
1288
- await page.evaluate(
1289
- async ({ toolName, slug, sectionId, fieldKey, value }) => {
1290
- const runtime = navigator.modelContextTesting;
1291
- if (!runtime?.executeTool) return;
1292
- await runtime.executeTool(
1293
- toolName,
1294
- JSON.stringify({
1295
- slug,
1296
- sectionId,
1297
- fieldKey,
1298
- value,
1299
- })
1300
- );
1301
- },
1302
- {
1303
- toolName: target.toolName,
1304
- slug: target.slug,
1305
- sectionId: target.sectionId,
1306
- fieldKey: target.fieldKey,
1307
- value: target.originalValue,
1308
- }
1309
- );
1310
- await waitForFileFieldValue(target.slug, target.sectionId, target.fieldKey, target.originalValue);
1311
- } catch {
1312
- await fs.writeFile(target.originalState.pageFilePath, target.originalState.raw, 'utf8');
1313
- }
1314
- };
1315
-
1316
- try {
1317
- const pageManifest = await fetchJson(target.manifestHref, `Manifest request for ${target.slug}`);
1318
- if (!Array.isArray(pageManifest.tools) || !pageManifest.tools.some((tool) => tool?.name === target.toolName)) {
1319
- throw new Error(`Manifest does not expose ${target.toolName}.`);
1320
- }
1321
-
1322
- const pageContract = await fetchJson(target.contractHref, `Contract request for ${target.slug}`);
1323
- if (!Array.isArray(pageContract.tools) || !pageContract.tools.some((tool) => tool?.name === target.toolName)) {
1324
- throw new Error(`Page contract does not expose ${target.toolName}.`);
1325
- }
1326
-
1327
- await page.goto(adminUrlFromSlug(target.slug), { waitUntil: 'networkidle' });
1328
-
1329
- try {
1330
- await page.waitForFunction(
1331
- ({ manifestHref, contractHref }) => {
1332
- const manifestLink = document.head.querySelector('link[rel="mcp-manifest"]');
1333
- const contractLink = document.head.querySelector('link[rel="olon-contract"]');
1334
- return manifestLink?.getAttribute('href') === manifestHref
1335
- && contractLink?.getAttribute('href') === contractHref;
1336
- },
1337
- { manifestHref: target.manifestHref, contractHref: target.contractHref },
1338
- { timeout: 10_000 }
1339
- );
1340
- } catch (error) {
1341
- const diagnostics = await page.evaluate(() => ({
1342
- head: document.head.innerHTML,
1343
- bodyText: document.body.innerText,
1344
- }));
1345
- throw new Error(
1346
- [
1347
- error instanceof Error ? error.message : String(error),
1348
- `head=${diagnostics.head}`,
1349
- `body=${diagnostics.bodyText}`,
1350
- ...consoleEvents,
1351
- ].join('\n')
1352
- );
1353
- }
1354
-
1355
- const toolNames = await page.evaluate(() => {
1356
- const runtime = navigator.modelContextTesting;
1357
- return runtime?.listTools?.().map((tool) => tool.name) ?? [];
1358
- });
1359
- if (!toolNames.includes(target.toolName)) {
1360
- throw new Error(`Runtime did not register ${target.toolName}. Found: ${toolNames.join(', ')}`);
1361
- }
1362
-
1363
- const rawResult = await page.evaluate(
1364
- async ({ toolName, slug, sectionId, fieldKey, value }) => {
1365
- const runtime = navigator.modelContextTesting;
1366
- if (!runtime?.executeTool) {
1367
- throw new Error('navigator.modelContextTesting.executeTool is unavailable.');
1368
- }
1369
- return runtime.executeTool(
1370
- toolName,
1371
- JSON.stringify({
1372
- slug,
1373
- sectionId,
1374
- fieldKey,
1375
- value,
1376
- })
1377
- );
1378
- },
1379
- {
1380
- toolName: target.toolName,
1381
- slug: target.slug,
1382
- sectionId: target.sectionId,
1383
- fieldKey: target.fieldKey,
1384
- value: nextValue,
1385
- }
1386
- );
1387
-
1388
- const parsedResult = JSON.parse(rawResult);
1389
- if (parsedResult?.isError) {
1390
- throw new Error(`WebMCP tool returned an error: ${rawResult}`);
1391
- }
1392
-
1393
- mutationApplied = true;
1394
- await waitForFileFieldValue(target.slug, target.sectionId, target.fieldKey, nextValue);
1395
- await page.frameLocator('iframe').getByText(nextValue, { exact: true }).waitFor({ state: 'attached' });
1396
-
1397
- console.log(
1398
- JSON.stringify({
1399
- ok: true,
1400
- slug: target.slug,
1401
- manifestHref: target.manifestHref,
1402
- contractHref: target.contractHref,
1403
- toolName: target.toolName,
1404
- sectionId: target.sectionId,
1405
- fieldKey: target.fieldKey,
1406
- toolNames,
1407
- })
1408
- );
1409
- } finally {
1410
- if (mutationApplied) {
1411
- await restoreOriginal();
1412
- }
1413
- await browser.close();
1414
- }
1415
- }
1416
-
1417
- main().catch((error) => {
1418
- console.error(error instanceof Error ? error.stack ?? error.message : String(error));
1419
- process.exit(1);
1420
- });
1122
+ import fs from 'fs/promises';
1123
+ import path from 'path';
1124
+ import { fileURLToPath } from 'url';
1125
+ import { createRequire } from 'module';
1126
+
1127
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
1128
+ const rootDir = path.resolve(__dirname, '..');
1129
+ const baseUrl = process.env.WEBMCP_BASE_URL ?? 'http://127.0.0.1:4173';
1130
+
1131
+ function pageFilePathFromSlug(slug) {
1132
+ return path.resolve(rootDir, 'src', 'data', 'pages', `${slug}.json`);
1133
+ }
1134
+
1135
+ function adminUrlFromSlug(slug) {
1136
+ return `${baseUrl}/admin${slug === 'home' ? '' : `/${slug}`}`;
1137
+ }
1138
+
1139
+ function isStringSchema(schema) {
1140
+ if (!schema || typeof schema !== 'object') return false;
1141
+ if (schema.type === 'string') return true;
1142
+ if (Array.isArray(schema.anyOf)) {
1143
+ return schema.anyOf.some((entry) => entry && typeof entry === 'object' && entry.type === 'string');
1144
+ }
1145
+ return false;
1146
+ }
1147
+
1148
+ function findTopLevelStringField(sectionSchema) {
1149
+ const properties = sectionSchema?.properties;
1150
+ if (!properties || typeof properties !== 'object') return null;
1151
+ const preferred = ['title', 'sectionTitle', 'label', 'headline', 'name'];
1152
+ for (const key of preferred) {
1153
+ if (isStringSchema(properties[key])) return key;
1154
+ }
1155
+ for (const [key, value] of Object.entries(properties)) {
1156
+ if (isStringSchema(value)) return key;
1157
+ }
1158
+ return null;
1159
+ }
1160
+
1161
+ async function loadPlaywright() {
1162
+ const require = createRequire(import.meta.url);
1163
+ try {
1164
+ return require('playwright');
1165
+ } catch (error) {
1166
+ const message = error instanceof Error ? error.message : String(error);
1167
+ throw new Error(
1168
+ `Playwright is required for WebMCP verification. Install it before running this script. Original error: ${message}`
1169
+ );
1170
+ }
1171
+ }
1172
+
1173
+ async function readPageJson(slug) {
1174
+ const pageFilePath = pageFilePathFromSlug(slug);
1175
+ const raw = await fs.readFile(pageFilePath, 'utf8');
1176
+ return { raw, json: JSON.parse(raw), pageFilePath };
1177
+ }
1178
+
1179
+ async function waitFor(predicate, timeoutMs, label) {
1180
+ const startedAt = Date.now();
1181
+ for (;;) {
1182
+ const result = await predicate();
1183
+ if (result) return result;
1184
+ if (Date.now() - startedAt > timeoutMs) {
1185
+ throw new Error(`Timed out while waiting for ${label}.`);
1186
+ }
1187
+ await new Promise((resolve) => setTimeout(resolve, 150));
1188
+ }
1189
+ }
1190
+
1191
+ async function waitForFileFieldValue(slug, sectionId, fieldKey, expectedValue) {
1192
+ await waitFor(async () => {
1193
+ const { json } = await readPageJson(slug);
1194
+ const section = Array.isArray(json.sections)
1195
+ ? json.sections.find((item) => item?.id === sectionId)
1196
+ : null;
1197
+ return section?.data?.[fieldKey] === expectedValue;
1198
+ }, 8_000, `file field "${fieldKey}" = "${expectedValue}"`);
1199
+ }
1200
+
1201
+ async function ensureResponseOk(response, label) {
1202
+ if (!response.ok) {
1203
+ const text = await response.text();
1204
+ throw new Error(`${label} failed with ${response.status}: ${text}`);
1205
+ }
1206
+ return response;
1207
+ }
1208
+
1209
+ async function fetchJson(relativePath, label) {
1210
+ const response = await ensureResponseOk(await fetch(`${baseUrl}${relativePath}`), label);
1211
+ return response.json();
1212
+ }
1213
+
1214
+ async function selectTarget() {
1215
+ const siteIndex = await fetchJson('/mcp-manifest.json', 'Manifest index request');
1216
+ const requestedSlug = typeof process.env.WEBMCP_TARGET_SLUG === 'string' && process.env.WEBMCP_TARGET_SLUG.trim()
1217
+ ? process.env.WEBMCP_TARGET_SLUG.trim()
1218
+ : null;
1219
+
1220
+ const candidatePages = requestedSlug
1221
+ ? (siteIndex.pages ?? []).filter((page) => page?.slug === requestedSlug)
1222
+ : (siteIndex.pages ?? []);
1223
+
1224
+ for (const pageEntry of candidatePages) {
1225
+ if (!pageEntry?.slug || !pageEntry?.manifestHref || !pageEntry?.contractHref) continue;
1226
+ const pageManifest = await fetchJson(pageEntry.manifestHref, `Page manifest request for ${pageEntry.slug}`);
1227
+ const pageContract = await fetchJson(pageEntry.contractHref, `Page contract request for ${pageEntry.slug}`);
1228
+ const localInstances = Array.isArray(pageContract.sectionInstances)
1229
+ ? pageContract.sectionInstances.filter((section) => section?.scope === 'local')
1230
+ : [];
1231
+ const tools = Array.isArray(pageManifest.tools) ? pageManifest.tools : [];
1232
+
1233
+ for (const tool of tools) {
1234
+ const sectionType = tool?.sectionType;
1235
+ if (typeof tool?.name !== 'string' || typeof sectionType !== 'string') continue;
1236
+ const targetInstance = localInstances.find((section) => section?.type === sectionType);
1237
+ if (!targetInstance?.id) continue;
1238
+ const targetFieldKey = findTopLevelStringField(pageContract.sectionSchemas?.[sectionType]);
1239
+ if (!targetFieldKey) continue;
1240
+ const pageState = await readPageJson(pageEntry.slug);
1241
+ const section = Array.isArray(pageState.json.sections)
1242
+ ? pageState.json.sections.find((item) => item?.id === targetInstance.id)
1243
+ : null;
1244
+ const originalValue = section?.data?.[targetFieldKey];
1245
+ if (typeof originalValue !== 'string') continue;
1246
+
1247
+ return {
1248
+ slug: pageEntry.slug,
1249
+ manifestHref: pageEntry.manifestHref,
1250
+ contractHref: pageEntry.contractHref,
1251
+ toolName: tool.name,
1252
+ sectionId: targetInstance.id,
1253
+ fieldKey: targetFieldKey,
1254
+ originalValue,
1255
+ originalState: pageState,
1256
+ };
1257
+ }
1258
+ }
1259
+
1260
+ throw new Error(
1261
+ requestedSlug
1262
+ ? `No valid WebMCP verification target found for page "${requestedSlug}".`
1263
+ : 'No valid WebMCP verification target found in manifest index.'
1264
+ );
1265
+ }
1266
+
1267
+ async function main() {
1268
+ const { chromium } = await loadPlaywright();
1269
+ const target = await selectTarget();
1270
+ const nextValue = `${target.originalValue} WebMCP ${Date.now()}`;
1271
+ const browser = await chromium.launch({ headless: true });
1272
+ const page = await browser.newPage();
1273
+ const consoleEvents = [];
1274
+ let mutationApplied = false;
1275
+
1276
+ page.on('console', (message) => {
1277
+ if (message.type() === 'error' || message.type() === 'warning') {
1278
+ consoleEvents.push(`[console:${message.type()}] ${message.text()}`);
1279
+ }
1280
+ });
1281
+ page.on('pageerror', (error) => {
1282
+ consoleEvents.push(`[pageerror] ${error.message}`);
1283
+ });
1284
+
1285
+ const restoreOriginal = async () => {
1286
+ try {
1287
+ await page.evaluate(
1288
+ async ({ toolName, slug, sectionId, fieldKey, value }) => {
1289
+ const runtime = navigator.modelContextTesting;
1290
+ if (!runtime?.executeTool) return;
1291
+ await runtime.executeTool(
1292
+ toolName,
1293
+ JSON.stringify({
1294
+ slug,
1295
+ sectionId,
1296
+ fieldKey,
1297
+ value,
1298
+ })
1299
+ );
1300
+ },
1301
+ {
1302
+ toolName: target.toolName,
1303
+ slug: target.slug,
1304
+ sectionId: target.sectionId,
1305
+ fieldKey: target.fieldKey,
1306
+ value: target.originalValue,
1307
+ }
1308
+ );
1309
+ await waitForFileFieldValue(target.slug, target.sectionId, target.fieldKey, target.originalValue);
1310
+ } catch {
1311
+ await fs.writeFile(target.originalState.pageFilePath, target.originalState.raw, 'utf8');
1312
+ }
1313
+ };
1314
+
1315
+ try {
1316
+ const pageManifest = await fetchJson(target.manifestHref, `Manifest request for ${target.slug}`);
1317
+ if (!Array.isArray(pageManifest.tools) || !pageManifest.tools.some((tool) => tool?.name === target.toolName)) {
1318
+ throw new Error(`Manifest does not expose ${target.toolName}.`);
1319
+ }
1320
+
1321
+ const pageContract = await fetchJson(target.contractHref, `Contract request for ${target.slug}`);
1322
+ if (!Array.isArray(pageContract.tools) || !pageContract.tools.some((tool) => tool?.name === target.toolName)) {
1323
+ throw new Error(`Page contract does not expose ${target.toolName}.`);
1324
+ }
1325
+
1326
+ await page.goto(adminUrlFromSlug(target.slug), { waitUntil: 'networkidle' });
1327
+
1328
+ try {
1329
+ await page.waitForFunction(
1330
+ ({ manifestHref, contractHref }) => {
1331
+ const manifestLink = document.head.querySelector('link[rel="mcp-manifest"]');
1332
+ const contractLink = document.head.querySelector('link[rel="olon-contract"]');
1333
+ return manifestLink?.getAttribute('href') === manifestHref
1334
+ && contractLink?.getAttribute('href') === contractHref;
1335
+ },
1336
+ { manifestHref: target.manifestHref, contractHref: target.contractHref },
1337
+ { timeout: 10_000 }
1338
+ );
1339
+ } catch (error) {
1340
+ const diagnostics = await page.evaluate(() => ({
1341
+ head: document.head.innerHTML,
1342
+ bodyText: document.body.innerText,
1343
+ }));
1344
+ throw new Error(
1345
+ [
1346
+ error instanceof Error ? error.message : String(error),
1347
+ `head=${diagnostics.head}`,
1348
+ `body=${diagnostics.bodyText}`,
1349
+ ...consoleEvents,
1350
+ ].join('\n')
1351
+ );
1352
+ }
1353
+
1354
+ const toolNames = await page.evaluate(() => {
1355
+ const runtime = navigator.modelContextTesting;
1356
+ return runtime?.listTools?.().map((tool) => tool.name) ?? [];
1357
+ });
1358
+ if (!toolNames.includes(target.toolName)) {
1359
+ throw new Error(`Runtime did not register ${target.toolName}. Found: ${toolNames.join(', ')}`);
1360
+ }
1361
+
1362
+ const rawResult = await page.evaluate(
1363
+ async ({ toolName, slug, sectionId, fieldKey, value }) => {
1364
+ const runtime = navigator.modelContextTesting;
1365
+ if (!runtime?.executeTool) {
1366
+ throw new Error('navigator.modelContextTesting.executeTool is unavailable.');
1367
+ }
1368
+ return runtime.executeTool(
1369
+ toolName,
1370
+ JSON.stringify({
1371
+ slug,
1372
+ sectionId,
1373
+ fieldKey,
1374
+ value,
1375
+ })
1376
+ );
1377
+ },
1378
+ {
1379
+ toolName: target.toolName,
1380
+ slug: target.slug,
1381
+ sectionId: target.sectionId,
1382
+ fieldKey: target.fieldKey,
1383
+ value: nextValue,
1384
+ }
1385
+ );
1386
+
1387
+ const parsedResult = JSON.parse(rawResult);
1388
+ if (parsedResult?.isError) {
1389
+ throw new Error(`WebMCP tool returned an error: ${rawResult}`);
1390
+ }
1391
+
1392
+ mutationApplied = true;
1393
+ await waitForFileFieldValue(target.slug, target.sectionId, target.fieldKey, nextValue);
1394
+ await page.frameLocator('iframe').getByText(nextValue, { exact: true }).waitFor({ state: 'attached' });
1395
+
1396
+ console.log(
1397
+ JSON.stringify({
1398
+ ok: true,
1399
+ slug: target.slug,
1400
+ manifestHref: target.manifestHref,
1401
+ contractHref: target.contractHref,
1402
+ toolName: target.toolName,
1403
+ sectionId: target.sectionId,
1404
+ fieldKey: target.fieldKey,
1405
+ toolNames,
1406
+ })
1407
+ );
1408
+ } finally {
1409
+ if (mutationApplied) {
1410
+ await restoreOriginal();
1411
+ }
1412
+ await browser.close();
1413
+ }
1414
+ }
1415
+
1416
+ main().catch((error) => {
1417
+ console.error(error instanceof Error ? error.stack ?? error.message : String(error));
1418
+ process.exit(1);
1419
+ });
1421
1420
 
1422
1421
  END_OF_FILE_CONTENT
1423
1422
  mkdir -p "src"
@@ -4750,7 +4749,6 @@ export type ImageBreakData = z.infer<typeof ImageBreakSchema>;
4750
4749
  export type ImageBreakSettings = Record<string, unknown>;
4751
4750
 
4752
4751
  END_OF_FILE_CONTENT
4753
- mkdir -p "src/components/image-test"
4754
4752
  mkdir -p "src/components/kitchen-showcase"
4755
4753
  echo "Creating src/components/kitchen-showcase/View.tsx..."
4756
4754
  cat << 'END_OF_FILE_CONTENT' > "src/components/kitchen-showcase/View.tsx"
@@ -11446,7 +11444,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
11446
11444
 
11447
11445
  END_OF_FILE_CONTENT
11448
11446
  # SKIP: src/registry-types.ts is binary and cannot be embedded as text.
11449
- mkdir -p "src/server"
11450
11447
  mkdir -p "src/types"
11451
11448
  echo "Creating src/types.ts..."
11452
11449
  cat << 'END_OF_FILE_CONTENT' > "src/types.ts"