// Embed the DeepSeek Harness-specific browser skill at build time. The model-facing // skill deliberately documents only injected browser_* tools; the repository's CLI // skill is a separate interface and must never be concatenated here. // Output: src/skill-content.generated.ts (gitignored, built before tsdown and // before vitest), so registration is a pure in-memory read. import { readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const here = dirname(fileURLToPath(import.meta.url)); const pkg = join(here, ".."); const source = readFileSync(join(pkg, "skill", "SKILL.md"), "utf8"); function stripFrontmatter(markdown) { if (!markdown.startsWith("---\n")) return markdown; const end = markdown.indexOf("\n---\n", 4); return end === -1 ? markdown : markdown.slice(end + 5).replace(/^\s*\n/, ""); } const SUPPORTED_BROWSER_TOOLS = [ "browser_session_start", "browser_session_stop", "browser_session_list", "browser_navigate", "browser_navigate_back", "browser_navigate_forward", "browser_reload", "browser_wait_for_navigation", "browser_snapshot", "browser_observe", "browser_get_html", "browser_screenshot", "browser_console", "browser_network", "browser_click", "browser_hover", "browser_fill", "browser_select", "browser_press", "browser_tab_list", "browser_tab_create", "browser_tab_select", "browser_tab_close", "browser_tab_borrow", "browser_tab_return", "browser_request_help", "browser_emulate", "browser_window_resize", ]; function validateModelFacingSkill(markdown) { if (/\bbsk\b/i.test(markdown)) { throw new Error("DSH skill must not expose the internal CLI name"); } if (/```(?:bash|sh|shell)\b/i.test(markdown)) { throw new Error("DSH skill must not contain command-line code blocks"); } const mentioned = new Set(markdown.match(/\bbrowser_[a-z][a-z_]*\b/g) ?? []); const supported = new Set(SUPPORTED_BROWSER_TOOLS); const unknown = [...mentioned].filter((name) => !supported.has(name)); const missing = SUPPORTED_BROWSER_TOOLS.filter((name) => !mentioned.has(name)); if (unknown.length > 0) { throw new Error(`DSH skill mentions unsupported browser tools: ${unknown.join(", ")}`); } if (missing.length > 0) { throw new Error(`DSH skill omits supported browser tools: ${missing.join(", ")}`); } } const NAME = "browser-skill"; const DESCRIPTION = "Browser automation against the user's logged-in Chromium through this plugin's injected " + "browser_* tools. Use to visit and read pages, fill forms, click through flows, inspect tabs, " + "debug page activity, or smoke-test UI changes in a managed Agent Window."; const content = `${stripFrontmatter(source).trim()}\n`; validateModelFacingSkill(content); const banner = "// GENERATED by scripts/build-skill-content.mjs — do not edit.\n" + "// Source: skill/SKILL.md (DeepSeek Harness browser_* tool instructions).\n"; writeFileSync( join(pkg, "src", "skill-content.generated.ts"), `${banner}export const BSK_SKILL_NAME = ${JSON.stringify(NAME)};\n` + `export const BSK_SKILL_DESCRIPTION = ${JSON.stringify(DESCRIPTION)};\n` + `export const BSK_SKILL_MARKDOWN = ${JSON.stringify(content)};\n`, ); console.log(`skill-content.generated.ts written (${content.length} chars)`);