Files
2026-05-17 16:07:41 +08:00

58 lines
2.6 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import path from "node:path";
import test from "node:test";
const skillPath = path.resolve("skills", "wechat-bridge", "SKILL.md");
const apiPath = path.resolve("skills", "wechat-bridge", "references", "api.md");
async function readSkillFiles() {
const [skill, api] = await Promise.all([
readFile(skillPath, "utf8"),
readFile(apiPath, "utf8")
]);
return { skill, api, combined: `${skill}\n${api}` };
}
test("wechat bridge skill has valid frontmatter and required workflow", async () => {
const { skill } = await readSkillFiles();
assert.match(skill, /^---\nname: wechat-bridge\ndescription: .+\n---/s);
assert.match(skill, /wxb fetch --json/);
assert.match(skill, /wxb send --account <data\.accountId> --user <fromUserId> --text/);
assert.match(skill, /wxb queue list --json/);
assert.match(skill, /Do not ask the user for it, do not store it, and do not pass it manually/);
});
test("wechat bridge skill documents proactive and media boundaries", async () => {
const { skill } = await readSkillFiles();
assert.match(skill, /Send proactive WeChat messages only when there is a clear work reason/);
assert.match(skill, /Only send to opaque `fromUserId` values previously returned by `wxb fetch`/);
assert.match(skill, /do not send to WeChat nicknames, phone numbers, remarks/);
assert.match(skill, /Aliases are local convenience labels/);
assert.match(skill, /wxb fetch --download-media --json/);
assert.match(skill, /attachments\[\]/);
assert.match(skill, /CDN URLs, or signed query parameters/);
assert.match(skill, /download\.ok/);
});
test("wechat bridge docs include required error guidance", async () => {
const { combined } = await readSkillFiles();
for (const code of ["NO_CONTEXT_TOKEN", "SESSION_EXPIRED", "ACCOUNT_REQUIRED", "INVALID_CONTEXT_TOKEN", "TEXT_TOO_LONG", "OUTGOING_HISTORY_WRITE_FAILED"]) {
assert.match(combined, new RegExp(code));
}
assert.match(combined, /Do not blindly retry/);
assert.match(combined, /attempts only the first queued item/);
assert.match(combined, /Do not expect `aesKey`, CDN download URLs, or signed query parameters in stdout/);
assert.match(combined, /Treat `attachments\[\]\.path` as the only media payload handoff/);
});
test("wechat bridge docs do not include live credential-looking examples", async () => {
const { combined } = await readSkillFiles();
assert.equal(/bot_secret|ctx_secret|bearer\s+[A-Za-z0-9._~+/=-]{8,}/i.test(combined), false);
assert.equal(/ABEiM0RVZneImaq7zN3u\/w==|00112233445566778899aabbccddeeff/i.test(combined), false);
});