From 8872891ab6efc617af9f378fa202fc1002af2f6f Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 22 Jun 2026 16:54:35 -0700 Subject: [PATCH] feat(cli): warn when installed skill is out of date --- .npmignore | 1 + playwright-cli.js | 25 +++++++-------- skillCheck.js | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 skillCheck.js diff --git a/.npmignore b/.npmignore index 574e93d..4caf4da 100644 --- a/.npmignore +++ b/.npmignore @@ -2,4 +2,5 @@ !README.md !LICENSE !playwright-cli.js +!skillCheck.js !skills/** diff --git a/playwright-cli.js b/playwright-cli.js index 2f6b814..01eb7a5 100755 --- a/playwright-cli.js +++ b/playwright-cli.js @@ -23,6 +23,7 @@ const path = require('path'); const { program } = require('playwright-core/lib/tools/cli-client/program'); const coreBundle = require('playwright-core/lib/coreBundle'); const { tools, registry } = coreBundle; +const { checkInstalledSkills, frame } = require('./skillCheck'); const packageJson = require('./package.json'); @@ -31,6 +32,9 @@ const ONE_DAY_MS = 24 * 60 * 60 * 1000; main(); async function main() { + const command = process.argv.slice(2).find(arg => !arg.startsWith('-')); + if (command !== 'install') + checkInstalledSkills(); await notifyAboutUpdate().catch(() => {}); program({ embedderVersion: packageJson.version }); } @@ -72,23 +76,16 @@ async function fetchLatestVersion() { } /** - * - * @param {string} current - * @param {string} latest + * + * @param {string} current + * @param {string} latest */ function printNotice(current, latest) { - const lines = [ + process.stderr.write('\n' + frame([ `Update available for ${packageJson.name}: ${current} → ${latest}`, `Run \`npm install -g ${packageJson.name}@latest\` (global) or`, - `\`npm install ${packageJson.name}@latest\` (local) to update.`, - ]; - const width = Math.max(...lines.map(line => line.length)); - const top = `╭${'─'.repeat(width + 2)}╮`; - const bottom = `╰${'─'.repeat(width + 2)}╯`; - process.stderr.write('\n' + top + '\n'); - for (const line of lines) - process.stderr.write(`│ ${line.padEnd(width)} │\n`); - process.stderr.write(bottom + '\n\n'); + `\`npm install --save-dev ${packageJson.name}@latest\` (local) to update.`, + ]) + '\n'); } function cacheFile() { @@ -106,7 +103,7 @@ function readCache() { } /** - * @param {*} data + * @param {*} data */ function writeCache(data) { try { diff --git a/skillCheck.js b/skillCheck.js new file mode 100644 index 0000000..7f2f441 --- /dev/null +++ b/skillCheck.js @@ -0,0 +1,78 @@ +/** + * 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 + +const fs = require('fs'); +const path = require('path'); + +function bundledSkillFile() { + const programPath = require.resolve('playwright-core/lib/tools/cli-client/program'); + return path.join(path.dirname(programPath), 'skill', 'SKILL.md'); +} + +function installedSkillTargets() { + const cwd = process.cwd(); + return [ + { dir: path.join(cwd, '.claude', 'skills', 'playwright-cli'), command: 'playwright-cli install --skills' }, + { dir: path.join(cwd, '.agents', 'skills', 'playwright-cli'), command: 'playwright-cli install --skills=agents' }, + ]; +} + +/** + * @param {string} file + * @returns + */ +function readSkill(file) { + return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null; +} + +/** + * @param {string[]} lines + * @returns {string} + */ +function frame(lines) { + const width = Math.max(...lines.map(line => line.length)); + const top = '╔' + '═'.repeat(width + 2) + '╗'; + const bottom = '╚' + '═'.repeat(width + 2) + '╝'; + const body = lines.map(line => `║ ${line.padEnd(width)} ║`); + return [top, ...body, bottom].join('\n') + '\n'; +} + +function checkInstalledSkills() { + try { + const bundled = readSkill(bundledSkillFile()); + if (!bundled) + return; + for (const target of installedSkillTargets()) { + const installed = readSkill(path.join(target.dir, 'SKILL.md')); + if (installed === null) + continue; + if (installed !== bundled) { + process.stderr.write(frame([ + `The playwright-cli skill at '${path.relative(process.cwd(), target.dir)}'`, + `does not match the tool version.`, + ``, + `Run \`${target.command}\``, + `to install the up-to-date skill.`, + ])); + } + } + } catch { + } +} + +module.exports = { checkInstalledSkills, frame };