diff --git a/.github/workflows/quality-gates.yml b/.github/workflows/quality-gates.yml index 629efe60..c719c2bf 100644 --- a/.github/workflows/quality-gates.yml +++ b/.github/workflows/quality-gates.yml @@ -6,6 +6,7 @@ on: - ".github/workflows/quality-gates.yml" - "lefthook.yml" - "package/ego-browser/**" + - "skills/ego-browser/SKILL.md" - "skills/ego-browser/learnings/**" push: branches: @@ -15,6 +16,7 @@ on: - ".github/workflows/quality-gates.yml" - "lefthook.yml" - "package/ego-browser/**" + - "skills/ego-browser/SKILL.md" - "skills/ego-browser/learnings/**" jobs: @@ -72,4 +74,3 @@ jobs: - name: Validate site skills working-directory: package/ego-browser run: npm run validate:site-skills - diff --git a/package/ego-browser/src/legacy-skill-guard.test.mjs b/package/ego-browser/src/legacy-skill-guard.test.mjs index da5bd71a..31f8cbce 100644 --- a/package/ego-browser/src/legacy-skill-guard.test.mjs +++ b/package/ego-browser/src/legacy-skill-guard.test.mjs @@ -1,13 +1,21 @@ import test from "node:test"; import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; import { + LEGACY_GLOBAL_HELPERS, LEGACY_TASK_SPACE_REPLACEMENTS, STALE_SKILL_PREFIX, installLegacySkillGuards, } from "../dist/src/legacy-skill-guard.js"; import { resetSink } from "../dist/src/output-sink.js"; +const SKILL_URL = new URL( + "../../../skills/ego-browser/SKILL.md", + import.meta.url, +); + const EXPECTED_TASK_SPACE_REPLACEMENTS = { listTaskSpaces: "taskSpaces.list()", switchTaskSpace: "taskSpaces.switch(nameOrId)", @@ -65,3 +73,36 @@ test("legacy skill guards cover only the removed task-space global surface", () } resetSink(); }); + +test("the current skill examples do not call removed global helpers", () => { + const skill = readFileSync(fileURLToPath(SKILL_URL), "utf8"); + const examples = executableCodeBlocks(skill); + + assert.notEqual(examples, "", "SKILL.md must contain executable examples"); + + for (const helper of LEGACY_GLOBAL_HELPERS) { + const unqualifiedCall = new RegExp( + `(? match[1]) + .join("\n"); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} diff --git a/package/ego-browser/src/legacy-skill-guard.ts b/package/ego-browser/src/legacy-skill-guard.ts index 57707f74..b07ecf77 100644 --- a/package/ego-browser/src/legacy-skill-guard.ts +++ b/package/ego-browser/src/legacy-skill-guard.ts @@ -6,7 +6,7 @@ type InstallTarget = Record; * Globals removed when the agent-facing API moved to Playwright-style facades. * Keep this list as the single cleanup source for both embedded and direct-CLI runs. */ -const LEGACY_GLOBAL_HELPERS = [ +export const LEGACY_GLOBAL_HELPERS = [ "click", "dblclick", "hover", diff --git a/skills/ego-browser/SKILL.md b/skills/ego-browser/SKILL.md index bf153804..0138144c 100644 --- a/skills/ego-browser/SKILL.md +++ b/skills/ego-browser/SKILL.md @@ -126,8 +126,8 @@ EOF ## Runtime map -- `page`: navigation and state (`goto`, `reload`, `url`, `title`, `info`), semantic locators, waits, `snapshot`, `screenshot`, `screencast`, `evaluate`, `keyboard`, `mouse`, downloads, and event draining. -- `page.locator(selector)`: chaining and filtering; `first` / `nth` / `last`; click, hover, `dragTo`, `scrollIntoViewIfNeeded`, form, keyboard, upload, state-read, collection, element-evaluate, screenshot, and wait methods. +- `page`: navigation and state (`goto`, `reload`, `url`, `title`, `info`), semantic locators, waits, `snapshot`, `screenshot`, `screencast`, `evaluate`, keyboard (`press`, `down`, `up`, `insertText`, `type`), mouse, downloads, and event draining. +- `page.locator(selector)`: chaining and filtering; `first` / `nth` / `last`; click, hover, `dragTo`, `scrollIntoViewIfNeeded`, form, keyboard (`press`, `pressSequentially`), upload, state-read, collection, element-evaluate, screenshot, and wait methods. - `browser`: `listTabs`, `currentTab`, `switchTab`, `openOrReuseTab`, `closeTab`, `ensureRealTab`, `iframeTarget`. - `taskSpaces`: `list`, `switch`, `new`, `useOrCreate`, `claim`, `complete`, `handOff`, `takeOver`, `waitForAgentControl`. - `fetch.server` performs Node-side requests; `fetch.browser` performs requests in the current page origin. Use `cdp` only as an escape hatch.