#!/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 networkTools from '../lib/tools/network.js'; import pdfTools from '../lib/tools/pdf.js'; import snapshotTools from '../lib/tools/snapshot.js'; import tabsTools from '../lib/tools/tabs.js'; import screenshotTools from '../lib/tools/screenshot.js'; import testTools from '../lib/tools/testing.js'; import visionTools from '../lib/tools/vision.js'; import waitTools from '../lib/tools/wait.js'; // Category definitions for tools const categories = { 'Interactions': [ ...snapshotTools, ...keyboardTools(true), ...waitTools(true), ...filesTools(true), ...dialogsTools(true), ], 'Navigation': [ ...navigateTools(true), ], 'Resources': [ ...screenshotTools, ...pdfTools, ...networkTools, ...consoleTools, ], 'Utilities': [ ...installTools, ...commonTools(true), ], 'Tabs': [ ...tabsTools(true), ], 'Testing': [ ...testTools, ], 'Vision mode': [ ...visionTools, ...keyboardTools(), ...waitTools(false), ...filesTools(false), ...dialogsTools(false), ], }; // 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 = ``; const kEndMarker = ``; /** * @param {import('../src/tools/tool.js').ToolSchema} tool * @returns {string} */ function formatToolForReadme(tool) { const lines = /** @type {string[]} */ ([]); lines.push(`\n\n`); lines.push(`- **${tool.name}**\n`); lines.push(` - Title: ${tool.title}\n`); lines.push(` - Description: ${tool.description}\n`); const inputSchema = /** @type {any} */ (zodToJsonSchema(tool.inputSchema || {})); const requiredParams = inputSchema.required || []; if (inputSchema.properties && Object.keys(inputSchema.properties).length) { lines.push(` - Parameters:\n`); Object.entries(inputSchema.properties).forEach(([name, param]) => { const optional = !requiredParams.includes(name); const meta = /** @type {string[]} */ ([]); if (param.type) meta.push(param.type); if (optional) meta.push('optional'); lines.push(` - \`${name}\` ${meta.length ? `(${meta.join(', ')})` : ''}: ${param.description}\n`); }); } else { lines.push(` - Parameters: None\n`); } lines.push(` - Read-only: **${tool.type === 'readOnly'}**\n`); lines.push('\n'); return lines.join(''); } 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(`
\n${category}\n\n`); for (const tool of categoryTools) generatedLines.push(formatToolForReadme(tool.schema)); generatedLines.push(`
\n\n`); } 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); });