






















@@ -3,6 +3,8 @@ import { buildWorkspaceSkillStatus } from "./skills-status.js";
33import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
44import type { SkillEntry } from "./skills/types.js";
556+type SkillStatus = ReturnType<typeof buildWorkspaceSkillStatus>["skills"][number];
7+68describe("buildWorkspaceSkillStatus", () => {
79it("does not surface install options for OS-scoped skills on unsupported platforms", () => {
810if (process.platform === "win32") {
@@ -157,18 +159,9 @@ describe("buildWorkspaceSkillStatus", () => {
157159expect(report.agentId).toBe("specialist");
158160expect(report.agentSkillFilter).toEqual(["alpha"]);
159161expect(report.skills.find((skill) => skill.name === "alpha")?.blockedByAgentFilter).toBe(false);
160-expect(report.skills).toContainEqual(
161-expect.objectContaining({
162-name: "alpha",
163-modelVisible: true,
164-}),
165-);
166-expect(report.skills).toContainEqual(
167-expect.objectContaining({
168-name: "beta",
169-blockedByAgentFilter: true,
170-}),
171-);
162+const byName = skillStatusByName(report.skills);
163+expect(requireSkillStatus(byName, "alpha").modelVisible).toBe(true);
164+expect(requireSkillStatus(byName, "beta").blockedByAgentFilter).toBe(true);
172165expect(report.skills.find((skill) => skill.name === "beta")?.modelVisible).toBe(false);
173166});
174167@@ -241,7 +234,7 @@ describe("buildWorkspaceSkillStatus", () => {
241234],
242235});
243236244-const byName = new Map(report.skills.map((skill) => [skill.name, skill]));
237+const byName = skillStatusByName(report.skills);
245238expect(report.agentSkillFilter).toEqual([
246239"ready",
247240"needs-bin",
@@ -251,61 +244,103 @@ describe("buildWorkspaceSkillStatus", () => {
251244"disabled",
252245"bundled-blocked",
253246]);
254-expect(byName.get("ready")).toMatchObject({
247+expectStatusFlags(requireSkillStatus(byName, "ready"), {
255248eligible: true,
256249modelVisible: true,
257250commandVisible: true,
258251});
259-expect(byName.get("needs-bin")).toMatchObject({
252+const needsBin = requireSkillStatus(byName, "needs-bin");
253+expectStatusFlags(needsBin, {
260254eligible: false,
261255modelVisible: false,
262256commandVisible: false,
263-missing: { bins: [missingBin] },
264-install: [
265-{
266-kind: "node",
267-label: "Install @openclaw/missing-skill-bin (pnpm)",
268-bins: [missingBin],
269-},
270-],
271257});
272-expect(byName.get("needs-env")).toMatchObject({
273-eligible: false,
274-primaryEnv: "OPENCLAW_TEST_MISSING_SKILL_KEY",
275-missing: { env: ["OPENCLAW_TEST_MISSING_SKILL_KEY"] },
258+expect(needsBin.missing).toStrictEqual({
259+anyBins: [],
260+bins: [missingBin],
261+config: [],
262+env: [],
263+os: [],
276264});
277-expect(byName.get("prompt-hidden")).toMatchObject({
265+expect(needsBin.install).toStrictEqual([
266+{
267+kind: "node",
268+id: "node-0",
269+label: "Install @openclaw/missing-skill-bin (pnpm)",
270+bins: [missingBin],
271+},
272+]);
273+const needsEnv = requireSkillStatus(byName, "needs-env");
274+expect(needsEnv.eligible).toBe(false);
275+expect(needsEnv.primaryEnv).toBe("OPENCLAW_TEST_MISSING_SKILL_KEY");
276+expect(needsEnv.missing).toStrictEqual({
277+anyBins: [],
278+bins: [],
279+config: [],
280+env: ["OPENCLAW_TEST_MISSING_SKILL_KEY"],
281+os: [],
282+});
283+expectStatusFlags(requireSkillStatus(byName, "prompt-hidden"), {
278284eligible: true,
279285modelVisible: false,
280286commandVisible: true,
281287});
282-expect(byName.get("slash-hidden")).toMatchObject({
288+const slashHidden = requireSkillStatus(byName, "slash-hidden");
289+expectStatusFlags(slashHidden, {
283290eligible: true,
284291modelVisible: true,
285-userInvocable: false,
286292commandVisible: false,
287293});
288-expect(byName.get("agent-filtered")).toMatchObject({
294+expect(slashHidden.userInvocable).toBe(false);
295+const agentFiltered = requireSkillStatus(byName, "agent-filtered");
296+expectStatusFlags(agentFiltered, {
289297eligible: true,
290-blockedByAgentFilter: true,
291298modelVisible: false,
292299commandVisible: false,
293300});
294-expect(byName.get("disabled")).toMatchObject({
301+expect(agentFiltered.blockedByAgentFilter).toBe(true);
302+const disabled = requireSkillStatus(byName, "disabled");
303+expectStatusFlags(disabled, {
295304eligible: false,
296-disabled: true,
297305modelVisible: false,
298306commandVisible: false,
299307});
300-expect(byName.get("bundled-blocked")).toMatchObject({
308+expect(disabled.disabled).toBe(true);
309+const bundledBlocked = requireSkillStatus(byName, "bundled-blocked");
310+expectStatusFlags(bundledBlocked, {
301311eligible: false,
302-blockedByAllowlist: true,
303312modelVisible: false,
304313commandVisible: false,
305314});
315+expect(bundledBlocked.blockedByAllowlist).toBe(true);
306316});
307317});
308318319+function skillStatusByName(skills: readonly SkillStatus[]): Map<string, SkillStatus> {
320+return new Map(skills.map((skill) => [skill.name, skill]));
321+}
322+323+function requireSkillStatus(byName: ReadonlyMap<string, SkillStatus>, name: string): SkillStatus {
324+const status = byName.get(name);
325+if (!status) {
326+throw new Error(`expected skill status ${name}`);
327+}
328+return status;
329+}
330+331+function expectStatusFlags(
332+status: SkillStatus,
333+expected: {
334+eligible: boolean;
335+modelVisible: boolean;
336+commandVisible: boolean;
337+},
338+): void {
339+expect(status.eligible).toBe(expected.eligible);
340+expect(status.modelVisible).toBe(expected.modelVisible);
341+expect(status.commandVisible).toBe(expected.commandVisible);
342+}
343+309344function createEntry(
310345name: string,
311346params: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。