@olonjs/cli 3.0.103 → 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.
@@ -596,7 +596,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
596
596
  "@tiptap/extension-link": "^2.11.5",
597
597
  "@tiptap/react": "^2.11.5",
598
598
  "@tiptap/starter-kit": "^2.11.5",
599
- "@olonjs/core": "^1.0.90",
599
+ "@olonjs/core": "^1.0.91",
600
600
  "clsx": "^2.1.1",
601
601
  "lucide-react": "^0.474.0",
602
602
  "react": "^19.0.0",
@@ -1119,304 +1119,304 @@ console.log('[sync-pages-to-public] Synced pages to public/pages');
1119
1119
  END_OF_FILE_CONTENT
1120
1120
  echo "Creating scripts/webmcp-feature-check.mjs..."
1121
1121
  cat << 'END_OF_FILE_CONTENT' > "scripts/webmcp-feature-check.mjs"
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
- });
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
+ });
1420
1420
 
1421
1421
  END_OF_FILE_CONTENT
1422
1422
  mkdir -p "src"