diff --git a/packages/baoyu-chrome-cdp/package.json b/packages/baoyu-chrome-cdp/package.json index 0014ad3..3fea2ee 100644 --- a/packages/baoyu-chrome-cdp/package.json +++ b/packages/baoyu-chrome-cdp/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" } diff --git a/packages/baoyu-md/package.json b/packages/baoyu-md/package.json index a6f7086..2adc131 100644 --- a/packages/baoyu-md/package.json +++ b/packages/baoyu-md/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" }, diff --git a/scripts/lib/shared-skill-packages.mjs b/scripts/lib/shared-skill-packages.mjs index f283cb8..d7c19a5 100644 --- a/scripts/lib/shared-skill-packages.mjs +++ b/scripts/lib/shared-skill-packages.mjs @@ -10,8 +10,12 @@ const PACKAGE_DEPENDENCY_SECTIONS = [ "devDependencies", ]; -const SKIPPED_DIRS = new Set([".git", ".clawhub", ".clawdhub", "node_modules"]); +const SKIPPED_DIRS = new Set([".git", ".changeset", ".clawhub", ".clawdhub", "node_modules"]); const SKIPPED_FILES = new Set([".DS_Store"]); +const TEST_DIR_NAMES = new Set(["__tests__", "test", "tests"]); +const TEST_FILE_PATTERN = /\.(test|spec)\.[^.]+$/; +const CHANGELOG_FILE_PATTERN = /^CHANGELOG(?:\..+)?\.md$/i; +const UNSUPPORTED_FILES_GLOB_PATTERN = /[*?[\]{}!]/; export async function syncSharedSkillPackages(repoRoot, options = {}) { const root = path.resolve(repoRoot); @@ -131,23 +135,7 @@ async function syncPackageTree({ sourceDir, targetDir, workspacePackages }) { const sourcePackageJsonPath = path.join(sourceDir, "package.json"); const packageJson = JSON.parse(await fs.readFile(sourcePackageJsonPath, "utf8")); const localDeps = collectLocalDependencies(packageJson, workspacePackages); - - const entries = await fs.readdir(sourceDir, { withFileTypes: true }); - for (const entry of entries) { - if (SKIPPED_DIRS.has(entry.name) || SKIPPED_FILES.has(entry.name)) continue; - - const sourcePath = path.join(sourceDir, entry.name); - const targetPath = path.join(targetDir, entry.name); - - if (entry.isDirectory()) { - await copyDirectory(sourcePath, targetPath); - continue; - } - - if (!entry.isFile() || entry.name === "package.json") continue; - await fs.mkdir(path.dirname(targetPath), { recursive: true }); - await fs.copyFile(sourcePath, targetPath); - } + await copyPackageContents({ sourceDir, targetDir, packageJson }); for (const name of localDeps) { const nestedSourceDir = workspacePackages.get(name); @@ -167,7 +155,7 @@ async function copyDirectory(sourceDir, targetDir) { await fs.mkdir(targetDir, { recursive: true }); const entries = await fs.readdir(sourceDir, { withFileTypes: true }); for (const entry of entries) { - if (SKIPPED_DIRS.has(entry.name) || SKIPPED_FILES.has(entry.name)) continue; + if (shouldSkipEntry(entry)) continue; const sourcePath = path.join(sourceDir, entry.name); const targetPath = path.join(targetDir, entry.name); @@ -183,6 +171,102 @@ async function copyDirectory(sourceDir, targetDir) { } } +async function copyPackageContents({ sourceDir, targetDir, packageJson }) { + const includedPaths = resolveIncludedPackagePaths(packageJson); + if (!includedPaths) { + const entries = await fs.readdir(sourceDir, { withFileTypes: true }); + for (const entry of entries) { + if (shouldSkipEntry(entry)) continue; + + const sourcePath = path.join(sourceDir, entry.name); + const targetPath = path.join(targetDir, entry.name); + + if (entry.isDirectory()) { + await copyDirectory(sourcePath, targetPath); + continue; + } + + if (!entry.isFile() || entry.name === "package.json") continue; + await fs.mkdir(path.dirname(targetPath), { recursive: true }); + await fs.copyFile(sourcePath, targetPath); + } + return; + } + + for (const relativePath of includedPaths) { + const sourcePath = path.join(sourceDir, relativePath); + const targetPath = path.join(targetDir, relativePath); + await copyPath(sourcePath, targetPath); + } +} + +async function copyPath(sourcePath, targetPath) { + let stat; + try { + stat = await fs.lstat(sourcePath); + } catch (error) { + if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return; + throw error; + } + + const name = path.basename(sourcePath); + if (stat.isDirectory()) { + if (shouldSkipName(name, { isDirectory: true })) return; + await copyDirectory(sourcePath, targetPath); + return; + } + + if (!stat.isFile()) return; + if (name === "package.json" || shouldSkipName(name, { isFile: true })) return; + await fs.mkdir(path.dirname(targetPath), { recursive: true }); + await fs.copyFile(sourcePath, targetPath); +} + +function resolveIncludedPackagePaths(packageJson) { + if (!Array.isArray(packageJson.files)) return null; + + const includedPaths = []; + for (const entry of packageJson.files) { + if (typeof entry !== "string") continue; + + const normalized = normalizeIncludedPath(entry); + if (!normalized || normalized === "package.json") continue; + includedPaths.push(normalized); + } + + return [...new Set(includedPaths)]; +} + +function normalizeIncludedPath(entry) { + const trimmed = entry.trim(); + if (!trimmed) return null; + if (UNSUPPORTED_FILES_GLOB_PATTERN.test(trimmed)) { + throw new Error(`Unsupported package.json files entry: ${entry}`); + } + + const normalized = path.posix.normalize(trimmed.replace(/\\/g, "/")).replace(/^(\.\/)+/, ""); + if (!normalized || normalized === ".") return null; + if (path.posix.isAbsolute(normalized) || normalized.startsWith("../")) { + throw new Error(`Package file entry must stay within the package root: ${entry}`); + } + + return normalized; +} + +function shouldSkipEntry(entry) { + return shouldSkipName(entry.name, { + isDirectory: entry.isDirectory(), + isFile: entry.isFile(), + }); +} + +function shouldSkipName(name, { isDirectory = false, isFile = false } = {}) { + if (SKIPPED_DIRS.has(name) || SKIPPED_FILES.has(name)) return true; + if (isDirectory && TEST_DIR_NAMES.has(name)) return true; + if (isFile && (TEST_FILE_PATTERN.test(name) || CHANGELOG_FILE_PATTERN.test(name))) return true; + return false; +} + async function discoverWorkspacePackages(repoRoot) { const packagesRoot = path.join(repoRoot, "packages"); const map = new Map(); diff --git a/scripts/lib/shared-skill-packages.test.ts b/scripts/lib/shared-skill-packages.test.ts index eb939a4..74ebfc7 100644 --- a/scripts/lib/shared-skill-packages.test.ts +++ b/scripts/lib/shared-skill-packages.test.ts @@ -31,6 +31,26 @@ test("syncSharedSkillPackages vendors workspace packages into skill scripts", as path.join(root, "packages", "baoyu-md", "src", "index.ts"), "export const markdown = true;\n", ); + await writeFile( + path.join(root, "packages", "baoyu-md", "src", "index.test.ts"), + "test('ignored', () => {});\n", + ); + await writeFile( + path.join(root, "packages", "baoyu-md", "src", "__tests__", "helper.ts"), + "export const helper = true;\n", + ); + await writeFile( + path.join(root, "packages", "baoyu-md", "tests", "setup.ts"), + "export const setup = true;\n", + ); + await writeFile( + path.join(root, "packages", "baoyu-md", ".changeset", "demo.md"), + "---\n", + ); + await writeFile( + path.join(root, "packages", "baoyu-md", "CHANGELOG.md"), + "# changelog\n", + ); const consumerDir = path.join(root, "skills", "demo-skill", "scripts"); await writeJson(path.join(consumerDir, "package.json"), { @@ -67,4 +87,97 @@ test("syncSharedSkillPackages vendors workspace packages into skill scripts", as "utf8", ); assert.match(vendoredFile, /markdown = true/); + + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "baoyu-md", "src", "index.test.ts"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "baoyu-md", "src", "__tests__", "helper.ts"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "baoyu-md", "tests", "setup.ts"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "baoyu-md", ".changeset", "demo.md"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "baoyu-md", "CHANGELOG.md"), "utf8"), + { code: "ENOENT" }, + ); +}); + +test("syncSharedSkillPackages respects package.json files allowlists", async (t) => { + const root = await makeTempDir("baoyu-sync-files-"); + t.after(() => fs.rm(root, { recursive: true, force: true })); + + await writeJson(path.join(root, "packages", "demo-pkg", "package.json"), { + name: "demo-pkg", + version: "1.0.0", + files: ["README.md", "src", "CHANGELOG.md", ".changeset"], + }); + await writeFile( + path.join(root, "packages", "demo-pkg", "README.md"), + "# Demo\n", + ); + await writeFile( + path.join(root, "packages", "demo-pkg", "src", "index.ts"), + "export const demo = true;\n", + ); + await writeFile( + path.join(root, "packages", "demo-pkg", "src", "index.test.ts"), + "test('ignored', () => {});\n", + ); + await writeFile( + path.join(root, "packages", "demo-pkg", "docs", "private.md"), + "private\n", + ); + await writeFile( + path.join(root, "packages", "demo-pkg", "CHANGELOG.md"), + "# changelog\n", + ); + await writeFile( + path.join(root, "packages", "demo-pkg", ".changeset", "demo.md"), + "---\n", + ); + + const consumerDir = path.join(root, "skills", "demo-skill", "scripts"); + await writeJson(path.join(consumerDir, "package.json"), { + name: "demo-skill-scripts", + version: "1.0.0", + dependencies: { + "demo-pkg": "^1.0.0", + }, + }); + + await syncSharedSkillPackages(root, { install: false }); + + const readme = await fs.readFile(path.join(consumerDir, "vendor", "demo-pkg", "README.md"), "utf8"); + assert.match(readme, /Demo/); + + const vendoredSource = await fs.readFile( + path.join(consumerDir, "vendor", "demo-pkg", "src", "index.ts"), + "utf8", + ); + assert.match(vendoredSource, /demo = true/); + + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "demo-pkg", "docs", "private.md"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "demo-pkg", "CHANGELOG.md"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "demo-pkg", ".changeset", "demo.md"), "utf8"), + { code: "ENOENT" }, + ); + await assert.rejects( + fs.readFile(path.join(consumerDir, "vendor", "demo-pkg", "src", "index.test.ts"), "utf8"), + { code: "ENOENT" }, + ); }); diff --git a/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/package.json b/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/package.json index 0014ad3..3fea2ee 100644 --- a/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/package.json +++ b/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" } diff --git a/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts b/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts deleted file mode 100644 index f745da5..0000000 --- a/skills/baoyu-danger-gemini-web/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -import assert from "node:assert/strict"; -import { spawn, type ChildProcess } from "node:child_process"; -import fs from "node:fs/promises"; -import http from "node:http"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { - discoverRunningChromeDebugPort, - findChromeExecutable, - findExistingChromeDebugPort, - getFreePort, - openPageSession, - resolveSharedChromeProfileDir, - waitForChromeDebugPort, -} from "./index.ts"; - -function useEnv( - t: TestContext, - values: Record, -): void { - const previous = new Map(); - for (const [key, value] of Object.entries(values)) { - previous.set(key, process.env[key]); - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - - t.after(() => { - for (const [key, value] of previous.entries()) { - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - }); -} - -async function makeTempDir(prefix: string): Promise { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -async function startDebugServer(port: number): Promise { - const server = http.createServer((req, res) => { - if (req.url === "/json/version") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - webSocketDebuggerUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - })); - return; - } - - res.writeHead(404); - res.end(); - }); - - await new Promise((resolve, reject) => { - server.once("error", reject); - server.listen(port, "127.0.0.1", () => resolve()); - }); - - return server; -} - -async function closeServer(server: http.Server): Promise { - await new Promise((resolve, reject) => { - server.close((error) => { - if (error) reject(error); - else resolve(); - }); - }); -} - -function shellPathForPlatform(): string | null { - if (process.platform === "win32") return null; - return "/bin/bash"; -} - -async function startFakeChromiumProcess(port: number): Promise { - const shell = shellPathForPlatform(); - if (!shell) return null; - - const child = spawn( - shell, - [ - "-lc", - `exec -a chromium-mock ${JSON.stringify(process.execPath)} -e 'setInterval(() => {}, 1000)' -- --remote-debugging-port=${port}`, - ], - { stdio: "ignore" }, - ); - - await new Promise((resolve) => setTimeout(resolve, 250)); - return child; -} - -async function stopProcess(child: ChildProcess | null): Promise { - if (!child) return; - if (child.exitCode !== null || child.signalCode !== null) return; - - child.kill("SIGTERM"); - await new Promise((resolve) => setTimeout(resolve, 100)); - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - if (child.exitCode !== null || child.signalCode !== null) return; - await new Promise((resolve) => child.once("exit", resolve)); -} - -test("getFreePort honors a fixed environment override and otherwise allocates a TCP port", async (t) => { - useEnv(t, { TEST_FIXED_PORT: "45678" }); - assert.equal(await getFreePort("TEST_FIXED_PORT"), 45678); - - const dynamicPort = await getFreePort(); - assert.ok(Number.isInteger(dynamicPort)); - assert.ok(dynamicPort > 0); -}); - -test("findChromeExecutable prefers env overrides and falls back to candidate paths", async (t) => { - const root = await makeTempDir("baoyu-chrome-bin-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const envChrome = path.join(root, "env-chrome"); - const fallbackChrome = path.join(root, "fallback-chrome"); - await fs.writeFile(envChrome, ""); - await fs.writeFile(fallbackChrome, ""); - - useEnv(t, { BAOYU_CHROME_PATH: envChrome }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - envChrome, - ); - - useEnv(t, { BAOYU_CHROME_PATH: null }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - fallbackChrome, - ); -}); - -test("resolveSharedChromeProfileDir supports env overrides, WSL paths, and default suffixes", (t) => { - useEnv(t, { BAOYU_SHARED_PROFILE: "/tmp/custom-profile" }); - assert.equal( - resolveSharedChromeProfileDir({ - envNames: ["BAOYU_SHARED_PROFILE"], - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.resolve("/tmp/custom-profile"), - ); - - useEnv(t, { BAOYU_SHARED_PROFILE: null }); - assert.equal( - resolveSharedChromeProfileDir({ - wslWindowsHome: "/mnt/c/Users/demo", - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.join("/mnt/c/Users/demo", ".local", "share", "demo-app", "demo-profile"), - ); - - const fallback = resolveSharedChromeProfileDir({ - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }); - assert.match(fallback, /demo-app[\\/]demo-profile$/); -}); - -test("findExistingChromeDebugPort reads DevToolsActivePort and validates it against a live endpoint", async (t) => { - const root = await makeTempDir("baoyu-cdp-profile-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await findExistingChromeDebugPort({ profileDir: root, timeoutMs: 1000 }); - assert.equal(found, port); -}); - -test("discoverRunningChromeDebugPort reads DevToolsActivePort from the provided user-data dir", async (t) => { - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.deepEqual(found, { - port, - wsUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - }); -}); - -test("discoverRunningChromeDebugPort ignores unrelated debugging processes", async (t) => { - if (process.platform === "win32") { - t.skip("Process discovery fallback is not used on Windows."); - return; - } - - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - const fakeChromium = await startFakeChromiumProcess(port); - t.after(async () => { await stopProcess(fakeChromium); }); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.equal(found, null); -}); - -test("openPageSession reports whether it created a new target", async () => { - const calls: string[] = []; - const cdpExisting = { - send: async (method: string): Promise => { - calls.push(method); - if (method === "Target.getTargets") { - return { - targetInfos: [{ targetId: "existing-target", type: "page", url: "https://gemini.google.com/app" }], - } as T; - } - if (method === "Target.attachToTarget") return { sessionId: "session-existing" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const existing = await openPageSession({ - cdp: cdpExisting as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(existing, { - sessionId: "session-existing", - targetId: "existing-target", - createdTarget: false, - }); - assert.deepEqual(calls, ["Target.getTargets", "Target.attachToTarget"]); - - const createCalls: string[] = []; - const cdpCreated = { - send: async (method: string): Promise => { - createCalls.push(method); - if (method === "Target.getTargets") return { targetInfos: [] } as T; - if (method === "Target.createTarget") return { targetId: "created-target" } as T; - if (method === "Target.attachToTarget") return { sessionId: "session-created" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const created = await openPageSession({ - cdp: cdpCreated as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(created, { - sessionId: "session-created", - targetId: "created-target", - createdTarget: true, - }); - assert.deepEqual(createCalls, ["Target.getTargets", "Target.createTarget", "Target.attachToTarget"]); -}); - -test("waitForChromeDebugPort retries until the debug endpoint becomes available", async (t) => { - const port = await getFreePort(); - - const serverPromise = (async () => { - await new Promise((resolve) => setTimeout(resolve, 200)); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - })(); - - const websocketUrl = await waitForChromeDebugPort(port, 4000, { - includeLastError: true, - }); - await serverPromise; - - assert.equal(websocketUrl, `ws://127.0.0.1:${port}/devtools/browser/demo`); -}); diff --git a/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/package.json b/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/package.json index 0014ad3..3fea2ee 100644 --- a/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/package.json +++ b/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" } diff --git a/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts b/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts deleted file mode 100644 index f745da5..0000000 --- a/skills/baoyu-danger-x-to-markdown/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -import assert from "node:assert/strict"; -import { spawn, type ChildProcess } from "node:child_process"; -import fs from "node:fs/promises"; -import http from "node:http"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { - discoverRunningChromeDebugPort, - findChromeExecutable, - findExistingChromeDebugPort, - getFreePort, - openPageSession, - resolveSharedChromeProfileDir, - waitForChromeDebugPort, -} from "./index.ts"; - -function useEnv( - t: TestContext, - values: Record, -): void { - const previous = new Map(); - for (const [key, value] of Object.entries(values)) { - previous.set(key, process.env[key]); - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - - t.after(() => { - for (const [key, value] of previous.entries()) { - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - }); -} - -async function makeTempDir(prefix: string): Promise { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -async function startDebugServer(port: number): Promise { - const server = http.createServer((req, res) => { - if (req.url === "/json/version") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - webSocketDebuggerUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - })); - return; - } - - res.writeHead(404); - res.end(); - }); - - await new Promise((resolve, reject) => { - server.once("error", reject); - server.listen(port, "127.0.0.1", () => resolve()); - }); - - return server; -} - -async function closeServer(server: http.Server): Promise { - await new Promise((resolve, reject) => { - server.close((error) => { - if (error) reject(error); - else resolve(); - }); - }); -} - -function shellPathForPlatform(): string | null { - if (process.platform === "win32") return null; - return "/bin/bash"; -} - -async function startFakeChromiumProcess(port: number): Promise { - const shell = shellPathForPlatform(); - if (!shell) return null; - - const child = spawn( - shell, - [ - "-lc", - `exec -a chromium-mock ${JSON.stringify(process.execPath)} -e 'setInterval(() => {}, 1000)' -- --remote-debugging-port=${port}`, - ], - { stdio: "ignore" }, - ); - - await new Promise((resolve) => setTimeout(resolve, 250)); - return child; -} - -async function stopProcess(child: ChildProcess | null): Promise { - if (!child) return; - if (child.exitCode !== null || child.signalCode !== null) return; - - child.kill("SIGTERM"); - await new Promise((resolve) => setTimeout(resolve, 100)); - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - if (child.exitCode !== null || child.signalCode !== null) return; - await new Promise((resolve) => child.once("exit", resolve)); -} - -test("getFreePort honors a fixed environment override and otherwise allocates a TCP port", async (t) => { - useEnv(t, { TEST_FIXED_PORT: "45678" }); - assert.equal(await getFreePort("TEST_FIXED_PORT"), 45678); - - const dynamicPort = await getFreePort(); - assert.ok(Number.isInteger(dynamicPort)); - assert.ok(dynamicPort > 0); -}); - -test("findChromeExecutable prefers env overrides and falls back to candidate paths", async (t) => { - const root = await makeTempDir("baoyu-chrome-bin-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const envChrome = path.join(root, "env-chrome"); - const fallbackChrome = path.join(root, "fallback-chrome"); - await fs.writeFile(envChrome, ""); - await fs.writeFile(fallbackChrome, ""); - - useEnv(t, { BAOYU_CHROME_PATH: envChrome }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - envChrome, - ); - - useEnv(t, { BAOYU_CHROME_PATH: null }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - fallbackChrome, - ); -}); - -test("resolveSharedChromeProfileDir supports env overrides, WSL paths, and default suffixes", (t) => { - useEnv(t, { BAOYU_SHARED_PROFILE: "/tmp/custom-profile" }); - assert.equal( - resolveSharedChromeProfileDir({ - envNames: ["BAOYU_SHARED_PROFILE"], - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.resolve("/tmp/custom-profile"), - ); - - useEnv(t, { BAOYU_SHARED_PROFILE: null }); - assert.equal( - resolveSharedChromeProfileDir({ - wslWindowsHome: "/mnt/c/Users/demo", - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.join("/mnt/c/Users/demo", ".local", "share", "demo-app", "demo-profile"), - ); - - const fallback = resolveSharedChromeProfileDir({ - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }); - assert.match(fallback, /demo-app[\\/]demo-profile$/); -}); - -test("findExistingChromeDebugPort reads DevToolsActivePort and validates it against a live endpoint", async (t) => { - const root = await makeTempDir("baoyu-cdp-profile-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await findExistingChromeDebugPort({ profileDir: root, timeoutMs: 1000 }); - assert.equal(found, port); -}); - -test("discoverRunningChromeDebugPort reads DevToolsActivePort from the provided user-data dir", async (t) => { - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.deepEqual(found, { - port, - wsUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - }); -}); - -test("discoverRunningChromeDebugPort ignores unrelated debugging processes", async (t) => { - if (process.platform === "win32") { - t.skip("Process discovery fallback is not used on Windows."); - return; - } - - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - const fakeChromium = await startFakeChromiumProcess(port); - t.after(async () => { await stopProcess(fakeChromium); }); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.equal(found, null); -}); - -test("openPageSession reports whether it created a new target", async () => { - const calls: string[] = []; - const cdpExisting = { - send: async (method: string): Promise => { - calls.push(method); - if (method === "Target.getTargets") { - return { - targetInfos: [{ targetId: "existing-target", type: "page", url: "https://gemini.google.com/app" }], - } as T; - } - if (method === "Target.attachToTarget") return { sessionId: "session-existing" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const existing = await openPageSession({ - cdp: cdpExisting as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(existing, { - sessionId: "session-existing", - targetId: "existing-target", - createdTarget: false, - }); - assert.deepEqual(calls, ["Target.getTargets", "Target.attachToTarget"]); - - const createCalls: string[] = []; - const cdpCreated = { - send: async (method: string): Promise => { - createCalls.push(method); - if (method === "Target.getTargets") return { targetInfos: [] } as T; - if (method === "Target.createTarget") return { targetId: "created-target" } as T; - if (method === "Target.attachToTarget") return { sessionId: "session-created" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const created = await openPageSession({ - cdp: cdpCreated as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(created, { - sessionId: "session-created", - targetId: "created-target", - createdTarget: true, - }); - assert.deepEqual(createCalls, ["Target.getTargets", "Target.createTarget", "Target.attachToTarget"]); -}); - -test("waitForChromeDebugPort retries until the debug endpoint becomes available", async (t) => { - const port = await getFreePort(); - - const serverPromise = (async () => { - await new Promise((resolve) => setTimeout(resolve, 200)); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - })(); - - const websocketUrl = await waitForChromeDebugPort(port, 4000, { - includeLastError: true, - }); - await serverPromise; - - assert.equal(websocketUrl, `ws://127.0.0.1:${port}/devtools/browser/demo`); -}); diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/package.json b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/package.json index a6f7086..2adc131 100644 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/package.json +++ b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" }, diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/content.test.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/content.test.ts deleted file mode 100644 index 91dbd72..0000000 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/content.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - extractSummaryFromBody, - extractTitleFromMarkdown, - parseFrontmatter, - pickFirstString, - serializeFrontmatter, - stripWrappingQuotes, - toFrontmatterString, -} from "./content.ts"; - -test("parseFrontmatter extracts YAML fields and strips wrapping quotes", () => { - const input = `--- -title: "Hello World" -author: ‘Baoyu’ -summary: plain text ---- -# Heading - -Body`; - - const result = parseFrontmatter(input); - - assert.deepEqual(result.frontmatter, { - title: "Hello World", - author: "Baoyu", - summary: "plain text", - }); - assert.match(result.body, /^# Heading/); -}); - -test("parseFrontmatter returns original content when no frontmatter exists", () => { - const input = "# No frontmatter"; - assert.deepEqual(parseFrontmatter(input), { - frontmatter: {}, - body: input, - }); -}); - -test("serializeFrontmatter renders YAML only when fields exist", () => { - assert.equal(serializeFrontmatter({}), ""); - assert.equal( - serializeFrontmatter({ title: "Hello", author: "Baoyu" }), - "---\ntitle: Hello\nauthor: Baoyu\n---\n", - ); -}); - -test("quote and frontmatter string helpers normalize mixed scalar values", () => { - assert.equal(stripWrappingQuotes(`" quoted "`), "quoted"); - assert.equal(stripWrappingQuotes("“ 中文标题 ”"), "中文标题"); - assert.equal(stripWrappingQuotes("plain"), "plain"); - - assert.equal(toFrontmatterString("'hello'"), "hello"); - assert.equal(toFrontmatterString(42), "42"); - assert.equal(toFrontmatterString(false), "false"); - assert.equal(toFrontmatterString({}), undefined); - - assert.equal( - pickFirstString({ summary: 123, title: "" }, ["title", "summary"]), - "123", - ); -}); - -test("markdown title and summary extraction skip non-body content and clean formatting", () => { - const markdown = ` -![cover](cover.png) -## “My Title” - -Body paragraph -`; - assert.equal(extractTitleFromMarkdown(markdown), "My Title"); - - const summary = extractSummaryFromBody( - ` -# Heading -> quote -- list -1. ordered -\`\`\` -code -\`\`\` -This is **the first paragraph** with [a link](https://example.com) and \`inline code\` that should be summarized cleanly. -`, - 70, - ); - - assert.equal( - summary, - "This is the first paragraph with a link and inline code that should...", - ); -}); diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/document.test.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/document.test.ts deleted file mode 100644 index bfa6533..0000000 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/document.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import assert from "node:assert/strict"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { COLOR_PRESETS, FONT_FAMILY_MAP } from "./constants.ts"; -import { - buildMarkdownDocumentMeta, - formatTimestamp, - renderMarkdownDocument, - resolveColorToken, - resolveFontFamilyToken, - resolveMarkdownStyle, - resolveRenderOptions, -} from "./document.ts"; - -function escapeRegExp(value: string): string { - return value.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`); -} - -function findInlineStyle(html: string, tagName: string, text: string): string { - const pattern = new RegExp( - `<${tagName}[^>]*style="([^"]*)"[^>]*>${escapeRegExp(text)}`, - ); - const match = html.match(pattern); - assert.ok(match, `Expected inline style for <${tagName}>${text}`); - return match![1]!; -} - -function useCwd(t: TestContext, cwd: string): void { - const previous = process.cwd(); - process.chdir(cwd); - t.after(() => { - process.chdir(previous); - }); -} - -async function makeTempDir(prefix: string): Promise { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -test("document token resolvers map known presets and allow passthrough values", () => { - assert.equal(resolveColorToken("green"), COLOR_PRESETS.green); - assert.equal(resolveColorToken("#123456"), "#123456"); - assert.equal(resolveColorToken(), undefined); - - assert.equal(resolveFontFamilyToken("mono"), FONT_FAMILY_MAP.mono); - assert.equal(resolveFontFamilyToken("Custom Font"), "Custom Font"); - assert.equal(resolveFontFamilyToken(), undefined); -}); - -test("formatTimestamp uses compact sortable datetime output", () => { - const date = new Date("2026-03-13T21:04:05.000Z"); - const pad = (value: number) => String(value).padStart(2, "0"); - const expected = `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad( - date.getDate(), - )}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`; - - assert.equal(formatTimestamp(date), expected); -}); - -test("buildMarkdownDocumentMeta prefers frontmatter and falls back to markdown title and summary", () => { - const metaFromYaml = buildMarkdownDocumentMeta( - "# Markdown Title\n\nBody summary paragraph that should be ignored.", - { - title: `" YAML Title "`, - author: "'Baoyu'", - summary: `" YAML Summary "`, - }, - "fallback", - ); - - assert.deepEqual(metaFromYaml, { - title: "YAML Title", - author: "Baoyu", - description: "YAML Summary", - }); - - const metaFromMarkdown = buildMarkdownDocumentMeta( - `## “Markdown Title”\n\nThis is the first body paragraph that should become the summary because it is long enough.`, - {}, - "fallback", - ); - - assert.equal(metaFromMarkdown.title, "Markdown Title"); - assert.match(metaFromMarkdown.description ?? "", /^This is the first body paragraph/); -}); - -test("resolveMarkdownStyle merges theme defaults with explicit overrides", () => { - const style = resolveMarkdownStyle({ - theme: "modern", - primaryColor: "#112233", - fontFamily: "Custom Sans", - }); - - assert.equal(style.primaryColor, "#112233"); - assert.equal(style.fontFamily, "Custom Sans"); - assert.equal(style.fontSize, "15px"); - assert.equal(style.containerBg, "rgba(250, 249, 245, 1)"); -}); - -test("resolveRenderOptions loads workspace EXTEND settings and lets explicit options win", async (t) => { - const root = await makeTempDir("baoyu-md-render-options-"); - useCwd(t, root); - - const extendPath = path.join( - root, - ".baoyu-skills", - "baoyu-markdown-to-html", - "EXTEND.md", - ); - await fs.mkdir(path.dirname(extendPath), { recursive: true }); - await fs.writeFile( - extendPath, - `--- -default_theme: modern -default_color: green -default_font_family: mono -default_font_size: 17 -default_code_theme: nord -mac_code_block: false -show_line_number: true -cite: true -count: true -legend: title-alt -keep_title: true ---- -`, - ); - - const fromExtend = resolveRenderOptions(); - assert.equal(fromExtend.theme, "modern"); - assert.equal(fromExtend.primaryColor, COLOR_PRESETS.green); - assert.equal(fromExtend.fontFamily, FONT_FAMILY_MAP.mono); - assert.equal(fromExtend.fontSize, "17px"); - assert.equal(fromExtend.codeTheme, "nord"); - assert.equal(fromExtend.isMacCodeBlock, false); - assert.equal(fromExtend.isShowLineNumber, true); - assert.equal(fromExtend.citeStatus, true); - assert.equal(fromExtend.countStatus, true); - assert.equal(fromExtend.legend, "title-alt"); - assert.equal(fromExtend.keepTitle, true); - - const explicit = resolveRenderOptions({ - theme: "simple", - fontSize: "18px", - keepTitle: false, - }); - assert.equal(explicit.theme, "simple"); - assert.equal(explicit.fontSize, "18px"); - assert.equal(explicit.keepTitle, false); -}); - -test("renderMarkdownDocument layers default rules into grace theme before CSS inlining", async () => { - const { html } = await renderMarkdownDocument( - `## Section\n\nParagraph with **bold** text.`, - { keepTitle: true, theme: "grace" }, - ); - - const h2Style = findInlineStyle(html, "h2", "Section"); - assert.match(h2Style, /background: #92617E/); - assert.match(h2Style, /box-shadow: 0 4px 6px rgba\(0, 0, 0, 0\.1\)/); - - const pMatch = html.match(/]*style="([^"]*)"[^>]*>/); - assert.ok(pMatch, "Expected inline style on

tag"); - assert.match(pMatch![1]!, /color:/); - - const strongPattern = /]*style="([^"]*)"[^>]*>bold<\/strong>/; - const strongMatch = html.match(strongPattern); - assert.ok(strongMatch, "Expected inline style for bold"); - assert.match(strongMatch![1]!, /font-weight:/); -}); diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/html-builder.test.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/html-builder.test.ts deleted file mode 100644 index b68de0d..0000000 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/html-builder.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { DEFAULT_STYLE } from "./constants.ts"; -import { - buildCss, - buildHtmlDocument, - modifyHtmlStructure, - normalizeCssText, - normalizeInlineCss, - removeFirstHeading, -} from "./html-builder.ts"; - -test("buildCss injects style variables and concatenates base and theme CSS", () => { - const css = buildCss("body { color: red; }", ".theme { color: blue; }"); - - assert.match(css, /--md-primary-color: #0F4C81;/); - assert.match(css, /body \{ color: red; \}/); - assert.match(css, /\.theme \{ color: blue; \}/); -}); - -test("buildHtmlDocument includes optional meta tags and code theme CSS", () => { - const html = buildHtmlDocument( - { - title: "Doc", - author: "Baoyu", - description: "Summary", - }, - "body { color: red; }", - "

Hello
", - ".hljs { color: blue; }", - ); - - assert.match(html, /Doc<\/title>/); - assert.match(html, /meta name="author" content="Baoyu"/); - assert.match(html, /meta name="description" content="Summary"/); - assert.match(html, /<style>body \{ color: red; \}<\/style>/); - assert.match(html, /<style>\.hljs \{ color: blue; \}<\/style>/); - assert.match(html, /<article>Hello<\/article>/); -}); - -test("normalizeCssText and normalizeInlineCss replace variables and strip declarations", () => { - const rawCss = ` -:root { --md-primary-color: #000; --md-font-size: 12px; --foreground: 0 0% 5%; } -.box { color: var(--md-primary-color); font-size: var(--md-font-size); background: hsl(var(--foreground)); } -`; - - const normalizedCss = normalizeCssText(rawCss, DEFAULT_STYLE); - assert.match(normalizedCss, /color: #0F4C81/); - assert.match(normalizedCss, /font-size: 16px/); - assert.match(normalizedCss, /background: #3f3f3f/); - assert.doesNotMatch(normalizedCss, /--md-primary-color/); - - const normalizedHtml = normalizeInlineCss( - `<style>${rawCss}</style><div style="color: var(--md-primary-color)"></div>`, - DEFAULT_STYLE, - ); - assert.match(normalizedHtml, /color: #0F4C81/); - assert.doesNotMatch(normalizedHtml, /var\(--md-primary-color\)/); -}); - -test("normalizeInlineCss removes quoted custom property values without leaving fragments behind", () => { - const normalizedHtml = normalizeInlineCss( - `<html style="--md-font-family: Menlo, Monaco, 'Courier New', monospace; color: var(--md-primary-color)"></html>`, - DEFAULT_STYLE, - ); - - assert.match(normalizedHtml, /style=" color: #0F4C81"/); - assert.doesNotMatch(normalizedHtml, /Courier New/); - assert.doesNotMatch(normalizedHtml, /--md-font-family/); -}); - -test("HTML structure helpers hoist nested lists and remove the first heading", () => { - const nestedList = `<ul><li>Parent<ul><li>Child</li></ul></li></ul>`; - assert.equal( - modifyHtmlStructure(nestedList), - `<ul><li>Parent</li><ul><li>Child</li></ul></ul>`, - ); - - const html = `<h1>Title</h1><p>Intro</p><h2>Sub</h2>`; - assert.equal(removeFirstHeading(html), `<p>Intro</p><h2>Sub</h2>`); -}); diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/images.test.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/images.test.ts deleted file mode 100644 index cc187c2..0000000 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/images.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import assert from "node:assert/strict"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - getImageExtension, - replaceMarkdownImagesWithPlaceholders, - resolveContentImages, - resolveImagePath, -} from "./images.ts"; - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -test("replaceMarkdownImagesWithPlaceholders rewrites markdown and tracks image metadata", () => { - const result = replaceMarkdownImagesWithPlaceholders( - `![cover](images/cover.png)\n\nText\n\n![diagram](images/diagram.webp)`, - "IMG_", - ); - - assert.equal(result.markdown, `IMG_1\n\nText\n\nIMG_2`); - assert.deepEqual(result.images, [ - { alt: "cover", originalPath: "images/cover.png", placeholder: "IMG_1" }, - { alt: "diagram", originalPath: "images/diagram.webp", placeholder: "IMG_2" }, - ]); -}); - -test("image extension and local fallback resolution handle common path variants", async (t) => { - assert.equal(getImageExtension("https://example.com/a.jpeg?x=1"), "jpeg"); - assert.equal(getImageExtension("/tmp/figure"), "png"); - - const root = await makeTempDir("baoyu-md-images-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const baseDir = path.join(root, "article"); - const tempDir = path.join(root, "tmp"); - await fs.mkdir(baseDir, { recursive: true }); - await fs.mkdir(tempDir, { recursive: true }); - await fs.writeFile(path.join(baseDir, "figure.webp"), "webp"); - - const resolved = await resolveImagePath("figure.png", baseDir, tempDir, "test"); - assert.equal(resolved, path.join(baseDir, "figure.webp")); -}); - -test("resolveContentImages resolves image placeholders against the content directory", async (t) => { - const root = await makeTempDir("baoyu-md-content-images-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const baseDir = path.join(root, "article"); - const tempDir = path.join(root, "tmp"); - await fs.mkdir(baseDir, { recursive: true }); - await fs.mkdir(tempDir, { recursive: true }); - await fs.writeFile(path.join(baseDir, "cover.png"), "png"); - - const resolved = await resolveContentImages( - [ - { - alt: "cover", - originalPath: "cover.png", - placeholder: "IMG_1", - }, - ], - baseDir, - tempDir, - "test", - ); - - assert.deepEqual(resolved, [ - { - alt: "cover", - originalPath: "cover.png", - placeholder: "IMG_1", - localPath: path.join(baseDir, "cover.png"), - }, - ]); -}); diff --git a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts b/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts deleted file mode 100644 index 702804c..0000000 --- a/skills/baoyu-markdown-to-html/scripts/vendor/baoyu-md/src/renderer.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { initRenderer, renderMarkdown } from "./renderer.ts"; - -const render = (md: string) => { - const r = initRenderer(); - return renderMarkdown(md, r).html; -}; - -test("bold with inline code (no underscore)", () => { - const html = render("**算出 `logits`,算出 `loss`。**"); - assert.match(html, /<code[^>]*>logits<\/code>/); - assert.match(html, /<code[^>]*>loss<\/code>/); -}); - -test("bold with inline code (contains underscore)", () => { - const html = render("**变成 `input_ids`。**"); - assert.match(html, /<code[^>]*>input_ids<\/code>/); -}); - -test("emphasis with inline code", () => { - const html = render("*查看 `hidden_states`*"); - assert.match(html, /<code[^>]*>hidden_states<\/code>/); -}); - -test("plain inline code (regression)", () => { - const html = render("`lm_head`"); - assert.match(html, /<code[^>]*>lm_head<\/code>/); -}); - -test("bold without code (regression)", () => { - const html = render("**纯粗体文本**"); - assert.match(html, /<strong[^>]*>纯粗体文本<\/strong>/); - assert.doesNotMatch(html, /<code/); -}); - -test("bold with inline code containing backticks", () => { - const html = render("**``a`b``**"); - assert.match(html, /<code[^>]*>a`b<\/code>/); -}); - -test("emphasis with inline code containing backticks", () => { - const html = render("*``a`b``*"); - assert.match(html, /<em[^>]*><code[^>]*>a`b<\/code><\/em>/); -}); - -test("bold with inline code containing consecutive backticks", () => { - const html = render("**```a``b```**"); - assert.match(html, /<code[^>]*>a``b<\/code>/); -}); - -test("bold with inline code containing only backticks", () => { - const html = render("**```` `` ````**"); - assert.match(html, /<code[^>]*>``<\/code>/); -}); - -test("bold with inline code containing only spaces", () => { - const oneSpace = render("**`` ``**"); - assert.match(oneSpace, /<code[^>]*> <\/code>/); - - const twoSpaces = render("**`` ``**"); - assert.match(twoSpaces, /<code[^>]*> <\/code>/); -}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/package.json b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/package.json index 0014ad3..3fea2ee 100644 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/package.json +++ b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" } diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts deleted file mode 100644 index f745da5..0000000 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -import assert from "node:assert/strict"; -import { spawn, type ChildProcess } from "node:child_process"; -import fs from "node:fs/promises"; -import http from "node:http"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { - discoverRunningChromeDebugPort, - findChromeExecutable, - findExistingChromeDebugPort, - getFreePort, - openPageSession, - resolveSharedChromeProfileDir, - waitForChromeDebugPort, -} from "./index.ts"; - -function useEnv( - t: TestContext, - values: Record<string, string | null>, -): void { - const previous = new Map<string, string | undefined>(); - for (const [key, value] of Object.entries(values)) { - previous.set(key, process.env[key]); - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - - t.after(() => { - for (const [key, value] of previous.entries()) { - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - }); -} - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -async function startDebugServer(port: number): Promise<http.Server> { - const server = http.createServer((req, res) => { - if (req.url === "/json/version") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - webSocketDebuggerUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - })); - return; - } - - res.writeHead(404); - res.end(); - }); - - await new Promise<void>((resolve, reject) => { - server.once("error", reject); - server.listen(port, "127.0.0.1", () => resolve()); - }); - - return server; -} - -async function closeServer(server: http.Server): Promise<void> { - await new Promise<void>((resolve, reject) => { - server.close((error) => { - if (error) reject(error); - else resolve(); - }); - }); -} - -function shellPathForPlatform(): string | null { - if (process.platform === "win32") return null; - return "/bin/bash"; -} - -async function startFakeChromiumProcess(port: number): Promise<ChildProcess | null> { - const shell = shellPathForPlatform(); - if (!shell) return null; - - const child = spawn( - shell, - [ - "-lc", - `exec -a chromium-mock ${JSON.stringify(process.execPath)} -e 'setInterval(() => {}, 1000)' -- --remote-debugging-port=${port}`, - ], - { stdio: "ignore" }, - ); - - await new Promise((resolve) => setTimeout(resolve, 250)); - return child; -} - -async function stopProcess(child: ChildProcess | null): Promise<void> { - if (!child) return; - if (child.exitCode !== null || child.signalCode !== null) return; - - child.kill("SIGTERM"); - await new Promise((resolve) => setTimeout(resolve, 100)); - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - if (child.exitCode !== null || child.signalCode !== null) return; - await new Promise((resolve) => child.once("exit", resolve)); -} - -test("getFreePort honors a fixed environment override and otherwise allocates a TCP port", async (t) => { - useEnv(t, { TEST_FIXED_PORT: "45678" }); - assert.equal(await getFreePort("TEST_FIXED_PORT"), 45678); - - const dynamicPort = await getFreePort(); - assert.ok(Number.isInteger(dynamicPort)); - assert.ok(dynamicPort > 0); -}); - -test("findChromeExecutable prefers env overrides and falls back to candidate paths", async (t) => { - const root = await makeTempDir("baoyu-chrome-bin-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const envChrome = path.join(root, "env-chrome"); - const fallbackChrome = path.join(root, "fallback-chrome"); - await fs.writeFile(envChrome, ""); - await fs.writeFile(fallbackChrome, ""); - - useEnv(t, { BAOYU_CHROME_PATH: envChrome }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - envChrome, - ); - - useEnv(t, { BAOYU_CHROME_PATH: null }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - fallbackChrome, - ); -}); - -test("resolveSharedChromeProfileDir supports env overrides, WSL paths, and default suffixes", (t) => { - useEnv(t, { BAOYU_SHARED_PROFILE: "/tmp/custom-profile" }); - assert.equal( - resolveSharedChromeProfileDir({ - envNames: ["BAOYU_SHARED_PROFILE"], - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.resolve("/tmp/custom-profile"), - ); - - useEnv(t, { BAOYU_SHARED_PROFILE: null }); - assert.equal( - resolveSharedChromeProfileDir({ - wslWindowsHome: "/mnt/c/Users/demo", - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.join("/mnt/c/Users/demo", ".local", "share", "demo-app", "demo-profile"), - ); - - const fallback = resolveSharedChromeProfileDir({ - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }); - assert.match(fallback, /demo-app[\\/]demo-profile$/); -}); - -test("findExistingChromeDebugPort reads DevToolsActivePort and validates it against a live endpoint", async (t) => { - const root = await makeTempDir("baoyu-cdp-profile-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await findExistingChromeDebugPort({ profileDir: root, timeoutMs: 1000 }); - assert.equal(found, port); -}); - -test("discoverRunningChromeDebugPort reads DevToolsActivePort from the provided user-data dir", async (t) => { - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.deepEqual(found, { - port, - wsUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - }); -}); - -test("discoverRunningChromeDebugPort ignores unrelated debugging processes", async (t) => { - if (process.platform === "win32") { - t.skip("Process discovery fallback is not used on Windows."); - return; - } - - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - const fakeChromium = await startFakeChromiumProcess(port); - t.after(async () => { await stopProcess(fakeChromium); }); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.equal(found, null); -}); - -test("openPageSession reports whether it created a new target", async () => { - const calls: string[] = []; - const cdpExisting = { - send: async <T>(method: string): Promise<T> => { - calls.push(method); - if (method === "Target.getTargets") { - return { - targetInfos: [{ targetId: "existing-target", type: "page", url: "https://gemini.google.com/app" }], - } as T; - } - if (method === "Target.attachToTarget") return { sessionId: "session-existing" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const existing = await openPageSession({ - cdp: cdpExisting as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(existing, { - sessionId: "session-existing", - targetId: "existing-target", - createdTarget: false, - }); - assert.deepEqual(calls, ["Target.getTargets", "Target.attachToTarget"]); - - const createCalls: string[] = []; - const cdpCreated = { - send: async <T>(method: string): Promise<T> => { - createCalls.push(method); - if (method === "Target.getTargets") return { targetInfos: [] } as T; - if (method === "Target.createTarget") return { targetId: "created-target" } as T; - if (method === "Target.attachToTarget") return { sessionId: "session-created" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const created = await openPageSession({ - cdp: cdpCreated as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(created, { - sessionId: "session-created", - targetId: "created-target", - createdTarget: true, - }); - assert.deepEqual(createCalls, ["Target.getTargets", "Target.createTarget", "Target.attachToTarget"]); -}); - -test("waitForChromeDebugPort retries until the debug endpoint becomes available", async (t) => { - const port = await getFreePort(); - - const serverPromise = (async () => { - await new Promise((resolve) => setTimeout(resolve, 200)); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - })(); - - const websocketUrl = await waitForChromeDebugPort(port, 4000, { - includeLastError: true, - }); - await serverPromise; - - assert.equal(websocketUrl, `ws://127.0.0.1:${port}/devtools/browser/demo`); -}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/package.json b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/package.json index a6f7086..2adc131 100644 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/package.json +++ b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" }, diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/content.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/content.test.ts deleted file mode 100644 index 91dbd72..0000000 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/content.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - extractSummaryFromBody, - extractTitleFromMarkdown, - parseFrontmatter, - pickFirstString, - serializeFrontmatter, - stripWrappingQuotes, - toFrontmatterString, -} from "./content.ts"; - -test("parseFrontmatter extracts YAML fields and strips wrapping quotes", () => { - const input = `--- -title: "Hello World" -author: ‘Baoyu’ -summary: plain text ---- -# Heading - -Body`; - - const result = parseFrontmatter(input); - - assert.deepEqual(result.frontmatter, { - title: "Hello World", - author: "Baoyu", - summary: "plain text", - }); - assert.match(result.body, /^# Heading/); -}); - -test("parseFrontmatter returns original content when no frontmatter exists", () => { - const input = "# No frontmatter"; - assert.deepEqual(parseFrontmatter(input), { - frontmatter: {}, - body: input, - }); -}); - -test("serializeFrontmatter renders YAML only when fields exist", () => { - assert.equal(serializeFrontmatter({}), ""); - assert.equal( - serializeFrontmatter({ title: "Hello", author: "Baoyu" }), - "---\ntitle: Hello\nauthor: Baoyu\n---\n", - ); -}); - -test("quote and frontmatter string helpers normalize mixed scalar values", () => { - assert.equal(stripWrappingQuotes(`" quoted "`), "quoted"); - assert.equal(stripWrappingQuotes("“ 中文标题 ”"), "中文标题"); - assert.equal(stripWrappingQuotes("plain"), "plain"); - - assert.equal(toFrontmatterString("'hello'"), "hello"); - assert.equal(toFrontmatterString(42), "42"); - assert.equal(toFrontmatterString(false), "false"); - assert.equal(toFrontmatterString({}), undefined); - - assert.equal( - pickFirstString({ summary: 123, title: "" }, ["title", "summary"]), - "123", - ); -}); - -test("markdown title and summary extraction skip non-body content and clean formatting", () => { - const markdown = ` -![cover](cover.png) -## “My Title” - -Body paragraph -`; - assert.equal(extractTitleFromMarkdown(markdown), "My Title"); - - const summary = extractSummaryFromBody( - ` -# Heading -> quote -- list -1. ordered -\`\`\` -code -\`\`\` -This is **the first paragraph** with [a link](https://example.com) and \`inline code\` that should be summarized cleanly. -`, - 70, - ); - - assert.equal( - summary, - "This is the first paragraph with a link and inline code that should...", - ); -}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/document.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/document.test.ts deleted file mode 100644 index bfa6533..0000000 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/document.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import assert from "node:assert/strict"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { COLOR_PRESETS, FONT_FAMILY_MAP } from "./constants.ts"; -import { - buildMarkdownDocumentMeta, - formatTimestamp, - renderMarkdownDocument, - resolveColorToken, - resolveFontFamilyToken, - resolveMarkdownStyle, - resolveRenderOptions, -} from "./document.ts"; - -function escapeRegExp(value: string): string { - return value.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`); -} - -function findInlineStyle(html: string, tagName: string, text: string): string { - const pattern = new RegExp( - `<${tagName}[^>]*style="([^"]*)"[^>]*>${escapeRegExp(text)}</${tagName}>`, - ); - const match = html.match(pattern); - assert.ok(match, `Expected inline style for <${tagName}>${text}</${tagName}>`); - return match![1]!; -} - -function useCwd(t: TestContext, cwd: string): void { - const previous = process.cwd(); - process.chdir(cwd); - t.after(() => { - process.chdir(previous); - }); -} - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -test("document token resolvers map known presets and allow passthrough values", () => { - assert.equal(resolveColorToken("green"), COLOR_PRESETS.green); - assert.equal(resolveColorToken("#123456"), "#123456"); - assert.equal(resolveColorToken(), undefined); - - assert.equal(resolveFontFamilyToken("mono"), FONT_FAMILY_MAP.mono); - assert.equal(resolveFontFamilyToken("Custom Font"), "Custom Font"); - assert.equal(resolveFontFamilyToken(), undefined); -}); - -test("formatTimestamp uses compact sortable datetime output", () => { - const date = new Date("2026-03-13T21:04:05.000Z"); - const pad = (value: number) => String(value).padStart(2, "0"); - const expected = `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad( - date.getDate(), - )}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`; - - assert.equal(formatTimestamp(date), expected); -}); - -test("buildMarkdownDocumentMeta prefers frontmatter and falls back to markdown title and summary", () => { - const metaFromYaml = buildMarkdownDocumentMeta( - "# Markdown Title\n\nBody summary paragraph that should be ignored.", - { - title: `" YAML Title "`, - author: "'Baoyu'", - summary: `" YAML Summary "`, - }, - "fallback", - ); - - assert.deepEqual(metaFromYaml, { - title: "YAML Title", - author: "Baoyu", - description: "YAML Summary", - }); - - const metaFromMarkdown = buildMarkdownDocumentMeta( - `## “Markdown Title”\n\nThis is the first body paragraph that should become the summary because it is long enough.`, - {}, - "fallback", - ); - - assert.equal(metaFromMarkdown.title, "Markdown Title"); - assert.match(metaFromMarkdown.description ?? "", /^This is the first body paragraph/); -}); - -test("resolveMarkdownStyle merges theme defaults with explicit overrides", () => { - const style = resolveMarkdownStyle({ - theme: "modern", - primaryColor: "#112233", - fontFamily: "Custom Sans", - }); - - assert.equal(style.primaryColor, "#112233"); - assert.equal(style.fontFamily, "Custom Sans"); - assert.equal(style.fontSize, "15px"); - assert.equal(style.containerBg, "rgba(250, 249, 245, 1)"); -}); - -test("resolveRenderOptions loads workspace EXTEND settings and lets explicit options win", async (t) => { - const root = await makeTempDir("baoyu-md-render-options-"); - useCwd(t, root); - - const extendPath = path.join( - root, - ".baoyu-skills", - "baoyu-markdown-to-html", - "EXTEND.md", - ); - await fs.mkdir(path.dirname(extendPath), { recursive: true }); - await fs.writeFile( - extendPath, - `--- -default_theme: modern -default_color: green -default_font_family: mono -default_font_size: 17 -default_code_theme: nord -mac_code_block: false -show_line_number: true -cite: true -count: true -legend: title-alt -keep_title: true ---- -`, - ); - - const fromExtend = resolveRenderOptions(); - assert.equal(fromExtend.theme, "modern"); - assert.equal(fromExtend.primaryColor, COLOR_PRESETS.green); - assert.equal(fromExtend.fontFamily, FONT_FAMILY_MAP.mono); - assert.equal(fromExtend.fontSize, "17px"); - assert.equal(fromExtend.codeTheme, "nord"); - assert.equal(fromExtend.isMacCodeBlock, false); - assert.equal(fromExtend.isShowLineNumber, true); - assert.equal(fromExtend.citeStatus, true); - assert.equal(fromExtend.countStatus, true); - assert.equal(fromExtend.legend, "title-alt"); - assert.equal(fromExtend.keepTitle, true); - - const explicit = resolveRenderOptions({ - theme: "simple", - fontSize: "18px", - keepTitle: false, - }); - assert.equal(explicit.theme, "simple"); - assert.equal(explicit.fontSize, "18px"); - assert.equal(explicit.keepTitle, false); -}); - -test("renderMarkdownDocument layers default rules into grace theme before CSS inlining", async () => { - const { html } = await renderMarkdownDocument( - `## Section\n\nParagraph with **bold** text.`, - { keepTitle: true, theme: "grace" }, - ); - - const h2Style = findInlineStyle(html, "h2", "Section"); - assert.match(h2Style, /background: #92617E/); - assert.match(h2Style, /box-shadow: 0 4px 6px rgba\(0, 0, 0, 0\.1\)/); - - const pMatch = html.match(/<p[^>]*style="([^"]*)"[^>]*>/); - assert.ok(pMatch, "Expected inline style on <p> tag"); - assert.match(pMatch![1]!, /color:/); - - const strongPattern = /<strong[^>]*style="([^"]*)"[^>]*>bold<\/strong>/; - const strongMatch = html.match(strongPattern); - assert.ok(strongMatch, "Expected inline style for <strong>bold</strong>"); - assert.match(strongMatch![1]!, /font-weight:/); -}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/html-builder.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/html-builder.test.ts deleted file mode 100644 index b68de0d..0000000 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/html-builder.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { DEFAULT_STYLE } from "./constants.ts"; -import { - buildCss, - buildHtmlDocument, - modifyHtmlStructure, - normalizeCssText, - normalizeInlineCss, - removeFirstHeading, -} from "./html-builder.ts"; - -test("buildCss injects style variables and concatenates base and theme CSS", () => { - const css = buildCss("body { color: red; }", ".theme { color: blue; }"); - - assert.match(css, /--md-primary-color: #0F4C81;/); - assert.match(css, /body \{ color: red; \}/); - assert.match(css, /\.theme \{ color: blue; \}/); -}); - -test("buildHtmlDocument includes optional meta tags and code theme CSS", () => { - const html = buildHtmlDocument( - { - title: "Doc", - author: "Baoyu", - description: "Summary", - }, - "body { color: red; }", - "<article>Hello</article>", - ".hljs { color: blue; }", - ); - - assert.match(html, /<title>Doc<\/title>/); - assert.match(html, /meta name="author" content="Baoyu"/); - assert.match(html, /meta name="description" content="Summary"/); - assert.match(html, /<style>body \{ color: red; \}<\/style>/); - assert.match(html, /<style>\.hljs \{ color: blue; \}<\/style>/); - assert.match(html, /<article>Hello<\/article>/); -}); - -test("normalizeCssText and normalizeInlineCss replace variables and strip declarations", () => { - const rawCss = ` -:root { --md-primary-color: #000; --md-font-size: 12px; --foreground: 0 0% 5%; } -.box { color: var(--md-primary-color); font-size: var(--md-font-size); background: hsl(var(--foreground)); } -`; - - const normalizedCss = normalizeCssText(rawCss, DEFAULT_STYLE); - assert.match(normalizedCss, /color: #0F4C81/); - assert.match(normalizedCss, /font-size: 16px/); - assert.match(normalizedCss, /background: #3f3f3f/); - assert.doesNotMatch(normalizedCss, /--md-primary-color/); - - const normalizedHtml = normalizeInlineCss( - `<style>${rawCss}</style><div style="color: var(--md-primary-color)"></div>`, - DEFAULT_STYLE, - ); - assert.match(normalizedHtml, /color: #0F4C81/); - assert.doesNotMatch(normalizedHtml, /var\(--md-primary-color\)/); -}); - -test("normalizeInlineCss removes quoted custom property values without leaving fragments behind", () => { - const normalizedHtml = normalizeInlineCss( - `<html style="--md-font-family: Menlo, Monaco, 'Courier New', monospace; color: var(--md-primary-color)"></html>`, - DEFAULT_STYLE, - ); - - assert.match(normalizedHtml, /style=" color: #0F4C81"/); - assert.doesNotMatch(normalizedHtml, /Courier New/); - assert.doesNotMatch(normalizedHtml, /--md-font-family/); -}); - -test("HTML structure helpers hoist nested lists and remove the first heading", () => { - const nestedList = `<ul><li>Parent<ul><li>Child</li></ul></li></ul>`; - assert.equal( - modifyHtmlStructure(nestedList), - `<ul><li>Parent</li><ul><li>Child</li></ul></ul>`, - ); - - const html = `<h1>Title</h1><p>Intro</p><h2>Sub</h2>`; - assert.equal(removeFirstHeading(html), `<p>Intro</p><h2>Sub</h2>`); -}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/images.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/images.test.ts deleted file mode 100644 index cc187c2..0000000 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/images.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import assert from "node:assert/strict"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - getImageExtension, - replaceMarkdownImagesWithPlaceholders, - resolveContentImages, - resolveImagePath, -} from "./images.ts"; - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -test("replaceMarkdownImagesWithPlaceholders rewrites markdown and tracks image metadata", () => { - const result = replaceMarkdownImagesWithPlaceholders( - `![cover](images/cover.png)\n\nText\n\n![diagram](images/diagram.webp)`, - "IMG_", - ); - - assert.equal(result.markdown, `IMG_1\n\nText\n\nIMG_2`); - assert.deepEqual(result.images, [ - { alt: "cover", originalPath: "images/cover.png", placeholder: "IMG_1" }, - { alt: "diagram", originalPath: "images/diagram.webp", placeholder: "IMG_2" }, - ]); -}); - -test("image extension and local fallback resolution handle common path variants", async (t) => { - assert.equal(getImageExtension("https://example.com/a.jpeg?x=1"), "jpeg"); - assert.equal(getImageExtension("/tmp/figure"), "png"); - - const root = await makeTempDir("baoyu-md-images-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const baseDir = path.join(root, "article"); - const tempDir = path.join(root, "tmp"); - await fs.mkdir(baseDir, { recursive: true }); - await fs.mkdir(tempDir, { recursive: true }); - await fs.writeFile(path.join(baseDir, "figure.webp"), "webp"); - - const resolved = await resolveImagePath("figure.png", baseDir, tempDir, "test"); - assert.equal(resolved, path.join(baseDir, "figure.webp")); -}); - -test("resolveContentImages resolves image placeholders against the content directory", async (t) => { - const root = await makeTempDir("baoyu-md-content-images-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const baseDir = path.join(root, "article"); - const tempDir = path.join(root, "tmp"); - await fs.mkdir(baseDir, { recursive: true }); - await fs.mkdir(tempDir, { recursive: true }); - await fs.writeFile(path.join(baseDir, "cover.png"), "png"); - - const resolved = await resolveContentImages( - [ - { - alt: "cover", - originalPath: "cover.png", - placeholder: "IMG_1", - }, - ], - baseDir, - tempDir, - "test", - ); - - assert.deepEqual(resolved, [ - { - alt: "cover", - originalPath: "cover.png", - placeholder: "IMG_1", - localPath: path.join(baseDir, "cover.png"), - }, - ]); -}); diff --git a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts b/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts deleted file mode 100644 index 702804c..0000000 --- a/skills/baoyu-post-to-wechat/scripts/vendor/baoyu-md/src/renderer.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { initRenderer, renderMarkdown } from "./renderer.ts"; - -const render = (md: string) => { - const r = initRenderer(); - return renderMarkdown(md, r).html; -}; - -test("bold with inline code (no underscore)", () => { - const html = render("**算出 `logits`,算出 `loss`。**"); - assert.match(html, /<code[^>]*>logits<\/code>/); - assert.match(html, /<code[^>]*>loss<\/code>/); -}); - -test("bold with inline code (contains underscore)", () => { - const html = render("**变成 `input_ids`。**"); - assert.match(html, /<code[^>]*>input_ids<\/code>/); -}); - -test("emphasis with inline code", () => { - const html = render("*查看 `hidden_states`*"); - assert.match(html, /<code[^>]*>hidden_states<\/code>/); -}); - -test("plain inline code (regression)", () => { - const html = render("`lm_head`"); - assert.match(html, /<code[^>]*>lm_head<\/code>/); -}); - -test("bold without code (regression)", () => { - const html = render("**纯粗体文本**"); - assert.match(html, /<strong[^>]*>纯粗体文本<\/strong>/); - assert.doesNotMatch(html, /<code/); -}); - -test("bold with inline code containing backticks", () => { - const html = render("**``a`b``**"); - assert.match(html, /<code[^>]*>a`b<\/code>/); -}); - -test("emphasis with inline code containing backticks", () => { - const html = render("*``a`b``*"); - assert.match(html, /<em[^>]*><code[^>]*>a`b<\/code><\/em>/); -}); - -test("bold with inline code containing consecutive backticks", () => { - const html = render("**```a``b```**"); - assert.match(html, /<code[^>]*>a``b<\/code>/); -}); - -test("bold with inline code containing only backticks", () => { - const html = render("**```` `` ````**"); - assert.match(html, /<code[^>]*>``<\/code>/); -}); - -test("bold with inline code containing only spaces", () => { - const oneSpace = render("**`` ``**"); - assert.match(oneSpace, /<code[^>]*> <\/code>/); - - const twoSpaces = render("**`` ``**"); - assert.match(twoSpaces, /<code[^>]*> <\/code>/); -}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/package.json b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/package.json index 0014ad3..3fea2ee 100644 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/package.json +++ b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" } diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts deleted file mode 100644 index f745da5..0000000 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -import assert from "node:assert/strict"; -import { spawn, type ChildProcess } from "node:child_process"; -import fs from "node:fs/promises"; -import http from "node:http"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { - discoverRunningChromeDebugPort, - findChromeExecutable, - findExistingChromeDebugPort, - getFreePort, - openPageSession, - resolveSharedChromeProfileDir, - waitForChromeDebugPort, -} from "./index.ts"; - -function useEnv( - t: TestContext, - values: Record<string, string | null>, -): void { - const previous = new Map<string, string | undefined>(); - for (const [key, value] of Object.entries(values)) { - previous.set(key, process.env[key]); - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - - t.after(() => { - for (const [key, value] of previous.entries()) { - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - }); -} - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -async function startDebugServer(port: number): Promise<http.Server> { - const server = http.createServer((req, res) => { - if (req.url === "/json/version") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - webSocketDebuggerUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - })); - return; - } - - res.writeHead(404); - res.end(); - }); - - await new Promise<void>((resolve, reject) => { - server.once("error", reject); - server.listen(port, "127.0.0.1", () => resolve()); - }); - - return server; -} - -async function closeServer(server: http.Server): Promise<void> { - await new Promise<void>((resolve, reject) => { - server.close((error) => { - if (error) reject(error); - else resolve(); - }); - }); -} - -function shellPathForPlatform(): string | null { - if (process.platform === "win32") return null; - return "/bin/bash"; -} - -async function startFakeChromiumProcess(port: number): Promise<ChildProcess | null> { - const shell = shellPathForPlatform(); - if (!shell) return null; - - const child = spawn( - shell, - [ - "-lc", - `exec -a chromium-mock ${JSON.stringify(process.execPath)} -e 'setInterval(() => {}, 1000)' -- --remote-debugging-port=${port}`, - ], - { stdio: "ignore" }, - ); - - await new Promise((resolve) => setTimeout(resolve, 250)); - return child; -} - -async function stopProcess(child: ChildProcess | null): Promise<void> { - if (!child) return; - if (child.exitCode !== null || child.signalCode !== null) return; - - child.kill("SIGTERM"); - await new Promise((resolve) => setTimeout(resolve, 100)); - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - if (child.exitCode !== null || child.signalCode !== null) return; - await new Promise((resolve) => child.once("exit", resolve)); -} - -test("getFreePort honors a fixed environment override and otherwise allocates a TCP port", async (t) => { - useEnv(t, { TEST_FIXED_PORT: "45678" }); - assert.equal(await getFreePort("TEST_FIXED_PORT"), 45678); - - const dynamicPort = await getFreePort(); - assert.ok(Number.isInteger(dynamicPort)); - assert.ok(dynamicPort > 0); -}); - -test("findChromeExecutable prefers env overrides and falls back to candidate paths", async (t) => { - const root = await makeTempDir("baoyu-chrome-bin-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const envChrome = path.join(root, "env-chrome"); - const fallbackChrome = path.join(root, "fallback-chrome"); - await fs.writeFile(envChrome, ""); - await fs.writeFile(fallbackChrome, ""); - - useEnv(t, { BAOYU_CHROME_PATH: envChrome }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - envChrome, - ); - - useEnv(t, { BAOYU_CHROME_PATH: null }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - fallbackChrome, - ); -}); - -test("resolveSharedChromeProfileDir supports env overrides, WSL paths, and default suffixes", (t) => { - useEnv(t, { BAOYU_SHARED_PROFILE: "/tmp/custom-profile" }); - assert.equal( - resolveSharedChromeProfileDir({ - envNames: ["BAOYU_SHARED_PROFILE"], - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.resolve("/tmp/custom-profile"), - ); - - useEnv(t, { BAOYU_SHARED_PROFILE: null }); - assert.equal( - resolveSharedChromeProfileDir({ - wslWindowsHome: "/mnt/c/Users/demo", - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.join("/mnt/c/Users/demo", ".local", "share", "demo-app", "demo-profile"), - ); - - const fallback = resolveSharedChromeProfileDir({ - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }); - assert.match(fallback, /demo-app[\\/]demo-profile$/); -}); - -test("findExistingChromeDebugPort reads DevToolsActivePort and validates it against a live endpoint", async (t) => { - const root = await makeTempDir("baoyu-cdp-profile-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await findExistingChromeDebugPort({ profileDir: root, timeoutMs: 1000 }); - assert.equal(found, port); -}); - -test("discoverRunningChromeDebugPort reads DevToolsActivePort from the provided user-data dir", async (t) => { - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.deepEqual(found, { - port, - wsUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - }); -}); - -test("discoverRunningChromeDebugPort ignores unrelated debugging processes", async (t) => { - if (process.platform === "win32") { - t.skip("Process discovery fallback is not used on Windows."); - return; - } - - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - const fakeChromium = await startFakeChromiumProcess(port); - t.after(async () => { await stopProcess(fakeChromium); }); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.equal(found, null); -}); - -test("openPageSession reports whether it created a new target", async () => { - const calls: string[] = []; - const cdpExisting = { - send: async <T>(method: string): Promise<T> => { - calls.push(method); - if (method === "Target.getTargets") { - return { - targetInfos: [{ targetId: "existing-target", type: "page", url: "https://gemini.google.com/app" }], - } as T; - } - if (method === "Target.attachToTarget") return { sessionId: "session-existing" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const existing = await openPageSession({ - cdp: cdpExisting as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(existing, { - sessionId: "session-existing", - targetId: "existing-target", - createdTarget: false, - }); - assert.deepEqual(calls, ["Target.getTargets", "Target.attachToTarget"]); - - const createCalls: string[] = []; - const cdpCreated = { - send: async <T>(method: string): Promise<T> => { - createCalls.push(method); - if (method === "Target.getTargets") return { targetInfos: [] } as T; - if (method === "Target.createTarget") return { targetId: "created-target" } as T; - if (method === "Target.attachToTarget") return { sessionId: "session-created" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const created = await openPageSession({ - cdp: cdpCreated as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(created, { - sessionId: "session-created", - targetId: "created-target", - createdTarget: true, - }); - assert.deepEqual(createCalls, ["Target.getTargets", "Target.createTarget", "Target.attachToTarget"]); -}); - -test("waitForChromeDebugPort retries until the debug endpoint becomes available", async (t) => { - const port = await getFreePort(); - - const serverPromise = (async () => { - await new Promise((resolve) => setTimeout(resolve, 200)); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - })(); - - const websocketUrl = await waitForChromeDebugPort(port, 4000, { - includeLastError: true, - }); - await serverPromise; - - assert.equal(websocketUrl, `ws://127.0.0.1:${port}/devtools/browser/demo`); -}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/package.json b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/package.json index a6f7086..2adc131 100644 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/package.json +++ b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" }, diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/content.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/content.test.ts deleted file mode 100644 index 91dbd72..0000000 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/content.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - extractSummaryFromBody, - extractTitleFromMarkdown, - parseFrontmatter, - pickFirstString, - serializeFrontmatter, - stripWrappingQuotes, - toFrontmatterString, -} from "./content.ts"; - -test("parseFrontmatter extracts YAML fields and strips wrapping quotes", () => { - const input = `--- -title: "Hello World" -author: ‘Baoyu’ -summary: plain text ---- -# Heading - -Body`; - - const result = parseFrontmatter(input); - - assert.deepEqual(result.frontmatter, { - title: "Hello World", - author: "Baoyu", - summary: "plain text", - }); - assert.match(result.body, /^# Heading/); -}); - -test("parseFrontmatter returns original content when no frontmatter exists", () => { - const input = "# No frontmatter"; - assert.deepEqual(parseFrontmatter(input), { - frontmatter: {}, - body: input, - }); -}); - -test("serializeFrontmatter renders YAML only when fields exist", () => { - assert.equal(serializeFrontmatter({}), ""); - assert.equal( - serializeFrontmatter({ title: "Hello", author: "Baoyu" }), - "---\ntitle: Hello\nauthor: Baoyu\n---\n", - ); -}); - -test("quote and frontmatter string helpers normalize mixed scalar values", () => { - assert.equal(stripWrappingQuotes(`" quoted "`), "quoted"); - assert.equal(stripWrappingQuotes("“ 中文标题 ”"), "中文标题"); - assert.equal(stripWrappingQuotes("plain"), "plain"); - - assert.equal(toFrontmatterString("'hello'"), "hello"); - assert.equal(toFrontmatterString(42), "42"); - assert.equal(toFrontmatterString(false), "false"); - assert.equal(toFrontmatterString({}), undefined); - - assert.equal( - pickFirstString({ summary: 123, title: "" }, ["title", "summary"]), - "123", - ); -}); - -test("markdown title and summary extraction skip non-body content and clean formatting", () => { - const markdown = ` -![cover](cover.png) -## “My Title” - -Body paragraph -`; - assert.equal(extractTitleFromMarkdown(markdown), "My Title"); - - const summary = extractSummaryFromBody( - ` -# Heading -> quote -- list -1. ordered -\`\`\` -code -\`\`\` -This is **the first paragraph** with [a link](https://example.com) and \`inline code\` that should be summarized cleanly. -`, - 70, - ); - - assert.equal( - summary, - "This is the first paragraph with a link and inline code that should...", - ); -}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/document.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/document.test.ts deleted file mode 100644 index bfa6533..0000000 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/document.test.ts +++ /dev/null @@ -1,174 +0,0 @@ -import assert from "node:assert/strict"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { COLOR_PRESETS, FONT_FAMILY_MAP } from "./constants.ts"; -import { - buildMarkdownDocumentMeta, - formatTimestamp, - renderMarkdownDocument, - resolveColorToken, - resolveFontFamilyToken, - resolveMarkdownStyle, - resolveRenderOptions, -} from "./document.ts"; - -function escapeRegExp(value: string): string { - return value.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`); -} - -function findInlineStyle(html: string, tagName: string, text: string): string { - const pattern = new RegExp( - `<${tagName}[^>]*style="([^"]*)"[^>]*>${escapeRegExp(text)}</${tagName}>`, - ); - const match = html.match(pattern); - assert.ok(match, `Expected inline style for <${tagName}>${text}</${tagName}>`); - return match![1]!; -} - -function useCwd(t: TestContext, cwd: string): void { - const previous = process.cwd(); - process.chdir(cwd); - t.after(() => { - process.chdir(previous); - }); -} - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -test("document token resolvers map known presets and allow passthrough values", () => { - assert.equal(resolveColorToken("green"), COLOR_PRESETS.green); - assert.equal(resolveColorToken("#123456"), "#123456"); - assert.equal(resolveColorToken(), undefined); - - assert.equal(resolveFontFamilyToken("mono"), FONT_FAMILY_MAP.mono); - assert.equal(resolveFontFamilyToken("Custom Font"), "Custom Font"); - assert.equal(resolveFontFamilyToken(), undefined); -}); - -test("formatTimestamp uses compact sortable datetime output", () => { - const date = new Date("2026-03-13T21:04:05.000Z"); - const pad = (value: number) => String(value).padStart(2, "0"); - const expected = `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad( - date.getDate(), - )}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`; - - assert.equal(formatTimestamp(date), expected); -}); - -test("buildMarkdownDocumentMeta prefers frontmatter and falls back to markdown title and summary", () => { - const metaFromYaml = buildMarkdownDocumentMeta( - "# Markdown Title\n\nBody summary paragraph that should be ignored.", - { - title: `" YAML Title "`, - author: "'Baoyu'", - summary: `" YAML Summary "`, - }, - "fallback", - ); - - assert.deepEqual(metaFromYaml, { - title: "YAML Title", - author: "Baoyu", - description: "YAML Summary", - }); - - const metaFromMarkdown = buildMarkdownDocumentMeta( - `## “Markdown Title”\n\nThis is the first body paragraph that should become the summary because it is long enough.`, - {}, - "fallback", - ); - - assert.equal(metaFromMarkdown.title, "Markdown Title"); - assert.match(metaFromMarkdown.description ?? "", /^This is the first body paragraph/); -}); - -test("resolveMarkdownStyle merges theme defaults with explicit overrides", () => { - const style = resolveMarkdownStyle({ - theme: "modern", - primaryColor: "#112233", - fontFamily: "Custom Sans", - }); - - assert.equal(style.primaryColor, "#112233"); - assert.equal(style.fontFamily, "Custom Sans"); - assert.equal(style.fontSize, "15px"); - assert.equal(style.containerBg, "rgba(250, 249, 245, 1)"); -}); - -test("resolveRenderOptions loads workspace EXTEND settings and lets explicit options win", async (t) => { - const root = await makeTempDir("baoyu-md-render-options-"); - useCwd(t, root); - - const extendPath = path.join( - root, - ".baoyu-skills", - "baoyu-markdown-to-html", - "EXTEND.md", - ); - await fs.mkdir(path.dirname(extendPath), { recursive: true }); - await fs.writeFile( - extendPath, - `--- -default_theme: modern -default_color: green -default_font_family: mono -default_font_size: 17 -default_code_theme: nord -mac_code_block: false -show_line_number: true -cite: true -count: true -legend: title-alt -keep_title: true ---- -`, - ); - - const fromExtend = resolveRenderOptions(); - assert.equal(fromExtend.theme, "modern"); - assert.equal(fromExtend.primaryColor, COLOR_PRESETS.green); - assert.equal(fromExtend.fontFamily, FONT_FAMILY_MAP.mono); - assert.equal(fromExtend.fontSize, "17px"); - assert.equal(fromExtend.codeTheme, "nord"); - assert.equal(fromExtend.isMacCodeBlock, false); - assert.equal(fromExtend.isShowLineNumber, true); - assert.equal(fromExtend.citeStatus, true); - assert.equal(fromExtend.countStatus, true); - assert.equal(fromExtend.legend, "title-alt"); - assert.equal(fromExtend.keepTitle, true); - - const explicit = resolveRenderOptions({ - theme: "simple", - fontSize: "18px", - keepTitle: false, - }); - assert.equal(explicit.theme, "simple"); - assert.equal(explicit.fontSize, "18px"); - assert.equal(explicit.keepTitle, false); -}); - -test("renderMarkdownDocument layers default rules into grace theme before CSS inlining", async () => { - const { html } = await renderMarkdownDocument( - `## Section\n\nParagraph with **bold** text.`, - { keepTitle: true, theme: "grace" }, - ); - - const h2Style = findInlineStyle(html, "h2", "Section"); - assert.match(h2Style, /background: #92617E/); - assert.match(h2Style, /box-shadow: 0 4px 6px rgba\(0, 0, 0, 0\.1\)/); - - const pMatch = html.match(/<p[^>]*style="([^"]*)"[^>]*>/); - assert.ok(pMatch, "Expected inline style on <p> tag"); - assert.match(pMatch![1]!, /color:/); - - const strongPattern = /<strong[^>]*style="([^"]*)"[^>]*>bold<\/strong>/; - const strongMatch = html.match(strongPattern); - assert.ok(strongMatch, "Expected inline style for <strong>bold</strong>"); - assert.match(strongMatch![1]!, /font-weight:/); -}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/html-builder.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/html-builder.test.ts deleted file mode 100644 index b68de0d..0000000 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/html-builder.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { DEFAULT_STYLE } from "./constants.ts"; -import { - buildCss, - buildHtmlDocument, - modifyHtmlStructure, - normalizeCssText, - normalizeInlineCss, - removeFirstHeading, -} from "./html-builder.ts"; - -test("buildCss injects style variables and concatenates base and theme CSS", () => { - const css = buildCss("body { color: red; }", ".theme { color: blue; }"); - - assert.match(css, /--md-primary-color: #0F4C81;/); - assert.match(css, /body \{ color: red; \}/); - assert.match(css, /\.theme \{ color: blue; \}/); -}); - -test("buildHtmlDocument includes optional meta tags and code theme CSS", () => { - const html = buildHtmlDocument( - { - title: "Doc", - author: "Baoyu", - description: "Summary", - }, - "body { color: red; }", - "<article>Hello</article>", - ".hljs { color: blue; }", - ); - - assert.match(html, /<title>Doc<\/title>/); - assert.match(html, /meta name="author" content="Baoyu"/); - assert.match(html, /meta name="description" content="Summary"/); - assert.match(html, /<style>body \{ color: red; \}<\/style>/); - assert.match(html, /<style>\.hljs \{ color: blue; \}<\/style>/); - assert.match(html, /<article>Hello<\/article>/); -}); - -test("normalizeCssText and normalizeInlineCss replace variables and strip declarations", () => { - const rawCss = ` -:root { --md-primary-color: #000; --md-font-size: 12px; --foreground: 0 0% 5%; } -.box { color: var(--md-primary-color); font-size: var(--md-font-size); background: hsl(var(--foreground)); } -`; - - const normalizedCss = normalizeCssText(rawCss, DEFAULT_STYLE); - assert.match(normalizedCss, /color: #0F4C81/); - assert.match(normalizedCss, /font-size: 16px/); - assert.match(normalizedCss, /background: #3f3f3f/); - assert.doesNotMatch(normalizedCss, /--md-primary-color/); - - const normalizedHtml = normalizeInlineCss( - `<style>${rawCss}</style><div style="color: var(--md-primary-color)"></div>`, - DEFAULT_STYLE, - ); - assert.match(normalizedHtml, /color: #0F4C81/); - assert.doesNotMatch(normalizedHtml, /var\(--md-primary-color\)/); -}); - -test("normalizeInlineCss removes quoted custom property values without leaving fragments behind", () => { - const normalizedHtml = normalizeInlineCss( - `<html style="--md-font-family: Menlo, Monaco, 'Courier New', monospace; color: var(--md-primary-color)"></html>`, - DEFAULT_STYLE, - ); - - assert.match(normalizedHtml, /style=" color: #0F4C81"/); - assert.doesNotMatch(normalizedHtml, /Courier New/); - assert.doesNotMatch(normalizedHtml, /--md-font-family/); -}); - -test("HTML structure helpers hoist nested lists and remove the first heading", () => { - const nestedList = `<ul><li>Parent<ul><li>Child</li></ul></li></ul>`; - assert.equal( - modifyHtmlStructure(nestedList), - `<ul><li>Parent</li><ul><li>Child</li></ul></ul>`, - ); - - const html = `<h1>Title</h1><p>Intro</p><h2>Sub</h2>`; - assert.equal(removeFirstHeading(html), `<p>Intro</p><h2>Sub</h2>`); -}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/images.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/images.test.ts deleted file mode 100644 index cc187c2..0000000 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/images.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import assert from "node:assert/strict"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - getImageExtension, - replaceMarkdownImagesWithPlaceholders, - resolveContentImages, - resolveImagePath, -} from "./images.ts"; - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -test("replaceMarkdownImagesWithPlaceholders rewrites markdown and tracks image metadata", () => { - const result = replaceMarkdownImagesWithPlaceholders( - `![cover](images/cover.png)\n\nText\n\n![diagram](images/diagram.webp)`, - "IMG_", - ); - - assert.equal(result.markdown, `IMG_1\n\nText\n\nIMG_2`); - assert.deepEqual(result.images, [ - { alt: "cover", originalPath: "images/cover.png", placeholder: "IMG_1" }, - { alt: "diagram", originalPath: "images/diagram.webp", placeholder: "IMG_2" }, - ]); -}); - -test("image extension and local fallback resolution handle common path variants", async (t) => { - assert.equal(getImageExtension("https://example.com/a.jpeg?x=1"), "jpeg"); - assert.equal(getImageExtension("/tmp/figure"), "png"); - - const root = await makeTempDir("baoyu-md-images-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const baseDir = path.join(root, "article"); - const tempDir = path.join(root, "tmp"); - await fs.mkdir(baseDir, { recursive: true }); - await fs.mkdir(tempDir, { recursive: true }); - await fs.writeFile(path.join(baseDir, "figure.webp"), "webp"); - - const resolved = await resolveImagePath("figure.png", baseDir, tempDir, "test"); - assert.equal(resolved, path.join(baseDir, "figure.webp")); -}); - -test("resolveContentImages resolves image placeholders against the content directory", async (t) => { - const root = await makeTempDir("baoyu-md-content-images-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const baseDir = path.join(root, "article"); - const tempDir = path.join(root, "tmp"); - await fs.mkdir(baseDir, { recursive: true }); - await fs.mkdir(tempDir, { recursive: true }); - await fs.writeFile(path.join(baseDir, "cover.png"), "png"); - - const resolved = await resolveContentImages( - [ - { - alt: "cover", - originalPath: "cover.png", - placeholder: "IMG_1", - }, - ], - baseDir, - tempDir, - "test", - ); - - assert.deepEqual(resolved, [ - { - alt: "cover", - originalPath: "cover.png", - placeholder: "IMG_1", - localPath: path.join(baseDir, "cover.png"), - }, - ]); -}); diff --git a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts b/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts deleted file mode 100644 index 702804c..0000000 --- a/skills/baoyu-post-to-weibo/scripts/vendor/baoyu-md/src/renderer.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { initRenderer, renderMarkdown } from "./renderer.ts"; - -const render = (md: string) => { - const r = initRenderer(); - return renderMarkdown(md, r).html; -}; - -test("bold with inline code (no underscore)", () => { - const html = render("**算出 `logits`,算出 `loss`。**"); - assert.match(html, /<code[^>]*>logits<\/code>/); - assert.match(html, /<code[^>]*>loss<\/code>/); -}); - -test("bold with inline code (contains underscore)", () => { - const html = render("**变成 `input_ids`。**"); - assert.match(html, /<code[^>]*>input_ids<\/code>/); -}); - -test("emphasis with inline code", () => { - const html = render("*查看 `hidden_states`*"); - assert.match(html, /<code[^>]*>hidden_states<\/code>/); -}); - -test("plain inline code (regression)", () => { - const html = render("`lm_head`"); - assert.match(html, /<code[^>]*>lm_head<\/code>/); -}); - -test("bold without code (regression)", () => { - const html = render("**纯粗体文本**"); - assert.match(html, /<strong[^>]*>纯粗体文本<\/strong>/); - assert.doesNotMatch(html, /<code/); -}); - -test("bold with inline code containing backticks", () => { - const html = render("**``a`b``**"); - assert.match(html, /<code[^>]*>a`b<\/code>/); -}); - -test("emphasis with inline code containing backticks", () => { - const html = render("*``a`b``*"); - assert.match(html, /<em[^>]*><code[^>]*>a`b<\/code><\/em>/); -}); - -test("bold with inline code containing consecutive backticks", () => { - const html = render("**```a``b```**"); - assert.match(html, /<code[^>]*>a``b<\/code>/); -}); - -test("bold with inline code containing only backticks", () => { - const html = render("**```` `` ````**"); - assert.match(html, /<code[^>]*>``<\/code>/); -}); - -test("bold with inline code containing only spaces", () => { - const oneSpace = render("**`` ``**"); - assert.match(oneSpace, /<code[^>]*> <\/code>/); - - const twoSpaces = render("**`` ``**"); - assert.match(twoSpaces, /<code[^>]*> <\/code>/); -}); diff --git a/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/package.json b/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/package.json index 0014ad3..3fea2ee 100644 --- a/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/package.json +++ b/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/package.json @@ -3,6 +3,9 @@ "private": true, "version": "0.1.0", "type": "module", + "files": [ + "src" + ], "exports": { ".": "./src/index.ts" } diff --git a/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts b/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts deleted file mode 100644 index f745da5..0000000 --- a/skills/baoyu-post-to-x/scripts/vendor/baoyu-chrome-cdp/src/index.test.ts +++ /dev/null @@ -1,307 +0,0 @@ -import assert from "node:assert/strict"; -import { spawn, type ChildProcess } from "node:child_process"; -import fs from "node:fs/promises"; -import http from "node:http"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test, { type TestContext } from "node:test"; - -import { - discoverRunningChromeDebugPort, - findChromeExecutable, - findExistingChromeDebugPort, - getFreePort, - openPageSession, - resolveSharedChromeProfileDir, - waitForChromeDebugPort, -} from "./index.ts"; - -function useEnv( - t: TestContext, - values: Record<string, string | null>, -): void { - const previous = new Map<string, string | undefined>(); - for (const [key, value] of Object.entries(values)) { - previous.set(key, process.env[key]); - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - - t.after(() => { - for (const [key, value] of previous.entries()) { - if (value == null) { - delete process.env[key]; - } else { - process.env[key] = value; - } - } - }); -} - -async function makeTempDir(prefix: string): Promise<string> { - return fs.mkdtemp(path.join(os.tmpdir(), prefix)); -} - -async function startDebugServer(port: number): Promise<http.Server> { - const server = http.createServer((req, res) => { - if (req.url === "/json/version") { - res.writeHead(200, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ - webSocketDebuggerUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - })); - return; - } - - res.writeHead(404); - res.end(); - }); - - await new Promise<void>((resolve, reject) => { - server.once("error", reject); - server.listen(port, "127.0.0.1", () => resolve()); - }); - - return server; -} - -async function closeServer(server: http.Server): Promise<void> { - await new Promise<void>((resolve, reject) => { - server.close((error) => { - if (error) reject(error); - else resolve(); - }); - }); -} - -function shellPathForPlatform(): string | null { - if (process.platform === "win32") return null; - return "/bin/bash"; -} - -async function startFakeChromiumProcess(port: number): Promise<ChildProcess | null> { - const shell = shellPathForPlatform(); - if (!shell) return null; - - const child = spawn( - shell, - [ - "-lc", - `exec -a chromium-mock ${JSON.stringify(process.execPath)} -e 'setInterval(() => {}, 1000)' -- --remote-debugging-port=${port}`, - ], - { stdio: "ignore" }, - ); - - await new Promise((resolve) => setTimeout(resolve, 250)); - return child; -} - -async function stopProcess(child: ChildProcess | null): Promise<void> { - if (!child) return; - if (child.exitCode !== null || child.signalCode !== null) return; - - child.kill("SIGTERM"); - await new Promise((resolve) => setTimeout(resolve, 100)); - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - if (child.exitCode !== null || child.signalCode !== null) return; - await new Promise((resolve) => child.once("exit", resolve)); -} - -test("getFreePort honors a fixed environment override and otherwise allocates a TCP port", async (t) => { - useEnv(t, { TEST_FIXED_PORT: "45678" }); - assert.equal(await getFreePort("TEST_FIXED_PORT"), 45678); - - const dynamicPort = await getFreePort(); - assert.ok(Number.isInteger(dynamicPort)); - assert.ok(dynamicPort > 0); -}); - -test("findChromeExecutable prefers env overrides and falls back to candidate paths", async (t) => { - const root = await makeTempDir("baoyu-chrome-bin-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const envChrome = path.join(root, "env-chrome"); - const fallbackChrome = path.join(root, "fallback-chrome"); - await fs.writeFile(envChrome, ""); - await fs.writeFile(fallbackChrome, ""); - - useEnv(t, { BAOYU_CHROME_PATH: envChrome }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - envChrome, - ); - - useEnv(t, { BAOYU_CHROME_PATH: null }); - assert.equal( - findChromeExecutable({ - envNames: ["BAOYU_CHROME_PATH"], - candidates: { default: [fallbackChrome] }, - }), - fallbackChrome, - ); -}); - -test("resolveSharedChromeProfileDir supports env overrides, WSL paths, and default suffixes", (t) => { - useEnv(t, { BAOYU_SHARED_PROFILE: "/tmp/custom-profile" }); - assert.equal( - resolveSharedChromeProfileDir({ - envNames: ["BAOYU_SHARED_PROFILE"], - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.resolve("/tmp/custom-profile"), - ); - - useEnv(t, { BAOYU_SHARED_PROFILE: null }); - assert.equal( - resolveSharedChromeProfileDir({ - wslWindowsHome: "/mnt/c/Users/demo", - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }), - path.join("/mnt/c/Users/demo", ".local", "share", "demo-app", "demo-profile"), - ); - - const fallback = resolveSharedChromeProfileDir({ - appDataDirName: "demo-app", - profileDirName: "demo-profile", - }); - assert.match(fallback, /demo-app[\\/]demo-profile$/); -}); - -test("findExistingChromeDebugPort reads DevToolsActivePort and validates it against a live endpoint", async (t) => { - const root = await makeTempDir("baoyu-cdp-profile-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await findExistingChromeDebugPort({ profileDir: root, timeoutMs: 1000 }); - assert.equal(found, port); -}); - -test("discoverRunningChromeDebugPort reads DevToolsActivePort from the provided user-data dir", async (t) => { - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - await fs.writeFile(path.join(root, "DevToolsActivePort"), `${port}\n/devtools/browser/demo\n`); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.deepEqual(found, { - port, - wsUrl: `ws://127.0.0.1:${port}/devtools/browser/demo`, - }); -}); - -test("discoverRunningChromeDebugPort ignores unrelated debugging processes", async (t) => { - if (process.platform === "win32") { - t.skip("Process discovery fallback is not used on Windows."); - return; - } - - const root = await makeTempDir("baoyu-cdp-user-data-"); - t.after(() => fs.rm(root, { recursive: true, force: true })); - - const port = await getFreePort(); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - - const fakeChromium = await startFakeChromiumProcess(port); - t.after(async () => { await stopProcess(fakeChromium); }); - - const found = await discoverRunningChromeDebugPort({ - userDataDirs: [root], - timeoutMs: 1000, - }); - assert.equal(found, null); -}); - -test("openPageSession reports whether it created a new target", async () => { - const calls: string[] = []; - const cdpExisting = { - send: async <T>(method: string): Promise<T> => { - calls.push(method); - if (method === "Target.getTargets") { - return { - targetInfos: [{ targetId: "existing-target", type: "page", url: "https://gemini.google.com/app" }], - } as T; - } - if (method === "Target.attachToTarget") return { sessionId: "session-existing" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const existing = await openPageSession({ - cdp: cdpExisting as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(existing, { - sessionId: "session-existing", - targetId: "existing-target", - createdTarget: false, - }); - assert.deepEqual(calls, ["Target.getTargets", "Target.attachToTarget"]); - - const createCalls: string[] = []; - const cdpCreated = { - send: async <T>(method: string): Promise<T> => { - createCalls.push(method); - if (method === "Target.getTargets") return { targetInfos: [] } as T; - if (method === "Target.createTarget") return { targetId: "created-target" } as T; - if (method === "Target.attachToTarget") return { sessionId: "session-created" } as T; - throw new Error(`Unexpected method: ${method}`); - }, - }; - - const created = await openPageSession({ - cdp: cdpCreated as never, - reusing: false, - url: "https://gemini.google.com/app", - matchTarget: (target) => target.url.includes("gemini.google.com"), - activateTarget: false, - }); - - assert.deepEqual(created, { - sessionId: "session-created", - targetId: "created-target", - createdTarget: true, - }); - assert.deepEqual(createCalls, ["Target.getTargets", "Target.createTarget", "Target.attachToTarget"]); -}); - -test("waitForChromeDebugPort retries until the debug endpoint becomes available", async (t) => { - const port = await getFreePort(); - - const serverPromise = (async () => { - await new Promise((resolve) => setTimeout(resolve, 200)); - const server = await startDebugServer(port); - t.after(() => closeServer(server)); - })(); - - const websocketUrl = await waitForChromeDebugPort(port, 4000, { - includeLastError: true, - }); - await serverPromise; - - assert.equal(websocketUrl, `ws://127.0.0.1:${port}/devtools/browser/demo`); -});