mirror of
https://github.com/microsoft/playwright-mcp.git
synced 2025-07-26 08:32:26 +08:00
188 lines
5.5 KiB
JavaScript
188 lines
5.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// @ts-check
|
|
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import url from 'node:url'
|
|
import zodToJsonSchema from 'zod-to-json-schema'
|
|
|
|
import commonTools from '../lib/tools/common.js';
|
|
import consoleTools from '../lib/tools/console.js';
|
|
import dialogsTools from '../lib/tools/dialogs.js';
|
|
import filesTools from '../lib/tools/files.js';
|
|
import installTools from '../lib/tools/install.js';
|
|
import keyboardTools from '../lib/tools/keyboard.js';
|
|
import navigateTools from '../lib/tools/navigate.js';
|
|
import pdfTools from '../lib/tools/pdf.js';
|
|
import snapshotTools from '../lib/tools/snapshot.js';
|
|
import tabsTools from '../lib/tools/tabs.js';
|
|
import screenTools from '../lib/tools/screen.js';
|
|
import testTools from '../lib/tools/testing.js';
|
|
|
|
// Category definitions for tools
|
|
const categories = {
|
|
'Snapshot-based Interactions': [
|
|
...snapshotTools,
|
|
],
|
|
'Vision-based Interactions': [
|
|
...screenTools
|
|
],
|
|
'Tab Management': [
|
|
...tabsTools(true),
|
|
],
|
|
'Navigation': [
|
|
...navigateTools(true),
|
|
],
|
|
'Keyboard': [
|
|
...keyboardTools(true)
|
|
],
|
|
'Console': [
|
|
...consoleTools
|
|
],
|
|
'Files and Media': [
|
|
...filesTools(true),
|
|
...pdfTools
|
|
],
|
|
'Utilities': [
|
|
...commonTools(true),
|
|
...installTools,
|
|
...dialogsTools(true),
|
|
],
|
|
'Testing': [
|
|
...testTools,
|
|
],
|
|
};
|
|
|
|
// NOTE: Can be removed when we drop Node.js 18 support and changed to import.meta.filename.
|
|
const __filename = url.fileURLToPath(import.meta.url);
|
|
|
|
const kStartMarker = `<!--- Generated by ${path.basename(__filename)} -->`;
|
|
const kEndMarker = `<!--- End of generated section -->`;
|
|
|
|
/**
|
|
* @param {ParsedToolSchema} tool
|
|
* @returns {string}
|
|
*/
|
|
function formatToolForReadme(tool) {
|
|
const lines = /** @type {string[]} */ ([]);
|
|
lines.push(`<!-- NOTE: This has been generated via ${path.basename(__filename)} -->\n\n`);
|
|
lines.push(`- **${tool.name}**\n`);
|
|
lines.push(` - Description: ${tool.description}\n`);
|
|
|
|
if (tool.parameters && tool.parameters.length > 0) {
|
|
lines.push(` - Parameters:\n`);
|
|
tool.parameters.forEach(param => {
|
|
const meta = /** @type {string[]} */ ([]);
|
|
if (param.type)
|
|
meta.push(param.type);
|
|
if (param.optional)
|
|
meta.push('optional');
|
|
lines.push(` - \`${param.name}\` ${meta.length ? `(${meta.join(', ')})` : ''}: ${param.description}\n`);
|
|
});
|
|
} else {
|
|
lines.push(` - Parameters: None\n`);
|
|
}
|
|
|
|
lines.push('\n');
|
|
return lines.join('');
|
|
}
|
|
|
|
/**
|
|
* @typedef {{
|
|
* name: any;
|
|
* description: any;
|
|
* parameters: {
|
|
* name: string;
|
|
* description: string;
|
|
* optional: boolean;
|
|
* type: string;
|
|
* }[];
|
|
*}} ParsedToolSchema
|
|
*/
|
|
|
|
/**
|
|
* @param {import('../src/tools/tool').ToolSchema<any>} schema
|
|
* @returns {ParsedToolSchema}
|
|
*/
|
|
function processToolSchema(schema) {
|
|
const inputSchema = /** @type {import('zod-to-json-schema').JsonSchema7ObjectType} */ (zodToJsonSchema(schema.inputSchema || {}));
|
|
if (inputSchema.type !== 'object')
|
|
throw new Error(`Tool ${schema.name} input schema is not an object`);
|
|
|
|
// In JSON Schema, properties are considered optional unless listed in the required array
|
|
const requiredParams = inputSchema?.required || [];
|
|
|
|
const parameters = Object.entries(inputSchema.properties).map(([name, prop]) => {
|
|
return {
|
|
name,
|
|
description: prop.description || '',
|
|
optional: !requiredParams.includes(name),
|
|
type: /** @type {any} */ (prop).type,
|
|
};
|
|
});
|
|
|
|
return {
|
|
name: schema.name,
|
|
description: schema.description,
|
|
parameters
|
|
};
|
|
}
|
|
|
|
async function updateReadme() {
|
|
console.log('Loading tool information from compiled modules...');
|
|
|
|
// Count the tools processed
|
|
const totalTools = Object.values(categories).flat().length;
|
|
console.log(`Found ${totalTools} tools`);
|
|
|
|
const generatedLines = /** @type {string[]} */ ([]);
|
|
|
|
for (const [category, categoryTools] of Object.entries(categories)) {
|
|
generatedLines.push(`### ${category}\n\n`);
|
|
for (const tool of categoryTools) {
|
|
const scheme = processToolSchema(tool.schema);
|
|
generatedLines.push(formatToolForReadme(scheme));
|
|
}
|
|
}
|
|
|
|
const readmePath = path.join(path.dirname(__filename), '..', 'README.md');
|
|
const readmeContent = await fs.promises.readFile(readmePath, 'utf-8');
|
|
const startMarker = readmeContent.indexOf(kStartMarker);
|
|
const endMarker = readmeContent.indexOf(kEndMarker);
|
|
if (startMarker === -1 || endMarker === -1)
|
|
throw new Error('Markers for generated section not found in README');
|
|
|
|
const newReadmeContent = [
|
|
readmeContent.slice(0, startMarker),
|
|
kStartMarker + '\n\n',
|
|
generatedLines.join(''),
|
|
kEndMarker,
|
|
readmeContent.slice(endMarker + kEndMarker.length),
|
|
].join('');
|
|
|
|
// Write updated README
|
|
await fs.promises.writeFile(readmePath, newReadmeContent, 'utf-8');
|
|
console.log('README updated successfully');
|
|
}
|
|
|
|
// Run the update
|
|
updateReadme().catch(err => {
|
|
console.error('Error updating README:', err);
|
|
process.exit(1);
|
|
});
|