From fed221e0b0c3c027d3671228653abf47d4ff0f81 Mon Sep 17 00:00:00 2001 From: Dax Date: Fri, 8 May 2026 14:50:06 -0400 Subject: [PATCH] fix(skill): allow missing descriptions (#26391) --- packages/opencode/src/skill/index.ts | 13 ++++---- packages/opencode/test/session/system.test.ts | 6 ++++ packages/opencode/test/skill/skill.test.ts | 31 +++++++++++++++++++ packages/sdk/js/src/v2/gen/types.gen.ts | 2 +- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/skill/index.ts b/packages/opencode/src/skill/index.ts index a4e3fb6d93..696ab887a7 100644 --- a/packages/opencode/src/skill/index.ts +++ b/packages/opencode/src/skill/index.ts @@ -27,7 +27,7 @@ const SKILL_PATTERN = "**/SKILL.md" export const Info = Schema.Struct({ name: Schema.String, - description: Schema.String, + description: Schema.optional(Schema.String), location: Schema.String, content: Schema.String, }).pipe(withStatics((s) => ({ zod: zod(s) }))) @@ -93,7 +93,7 @@ const add = Effect.fnUntraced(function* (state: State, match: string, bus: Bus.I if (!md) return - const parsed = z.object({ name: z.string(), description: z.string() }).safeParse(md.data) + const parsed = z.object({ name: z.string(), description: z.string().optional() }).safeParse(md.data) if (!parsed.success) return if (state.skills[parsed.data.name]) { @@ -269,12 +269,13 @@ export const defaultLayer = layer.pipe( ) export function fmt(list: Info[], opts: { verbose: boolean }) { - if (list.length === 0) return "No skills are currently available." + const described = list.filter((skill) => skill.description !== undefined) + if (described.length === 0) return "No skills are currently available." if (opts.verbose) { return [ "", - ...list - .sort((a, b) => a.name.localeCompare(b.name)) + ...described + .toSorted((a, b) => a.name.localeCompare(b.name)) .flatMap((skill) => [ " ", ` ${skill.name}`, @@ -288,7 +289,7 @@ export function fmt(list: Info[], opts: { verbose: boolean }) { return [ "## Available Skills", - ...list + ...described .toSorted((a, b) => a.name.localeCompare(b.name)) .map((skill) => `- **${skill.name}**: ${skill.description}`), ].join("\n") diff --git a/packages/opencode/test/session/system.test.ts b/packages/opencode/test/session/system.test.ts index 6e5439da58..1cf9026725 100644 --- a/packages/opencode/test/session/system.test.ts +++ b/packages/opencode/test/session/system.test.ts @@ -26,6 +26,11 @@ const skills: Skill.Info[] = [ location: "/tmp/middle-skill/SKILL.md", content: "# middle-skill", }, + { + name: "manual-skill", + location: "/tmp/manual-skill/SKILL.md", + content: "# manual-skill", + }, ] const build: Agent.Info = { @@ -68,6 +73,7 @@ describe("session.system", () => { expect(alpha).toBeGreaterThan(-1) expect(middle).toBeGreaterThan(alpha) expect(zeta).toBeGreaterThan(middle) + expect(output).not.toContain("manual-skill") }), ) }) diff --git a/packages/opencode/test/skill/skill.test.ts b/packages/opencode/test/skill/skill.test.ts index bfcb0dcd67..d73750b083 100644 --- a/packages/opencode/test/skill/skill.test.ts +++ b/packages/opencode/test/skill/skill.test.ts @@ -163,6 +163,37 @@ Just some content without YAML frontmatter. ), ) + it.live("discovers skills without descriptions", () => + provideTmpdirInstance( + (dir) => + Effect.gen(function* () { + yield* Effect.promise(() => + Bun.write( + path.join(dir, ".opencode", "skill", "manual-skill", "SKILL.md"), + `--- +name: manual-skill +--- + +# Manual Skill + +Instructions here. +`, + ), + ) + + const skill = yield* Skill.Service + const list = yield* skill.all() + expect(list.length).toBe(1) + const item = list.find((x) => x.name === "manual-skill") + expect(item).toBeDefined() + expect(item!.description).toBeUndefined() + expect(Skill.fmt(list, { verbose: false })).toBe("No skills are currently available.") + expect(Skill.fmt(list, { verbose: true })).toBe("No skills are currently available.") + }), + { git: true }, + ), + ) + it.live("discovers skills from .claude/skills/ directory", () => provideTmpdirInstance( (dir) => diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 3f6b802bc6..08051ba917 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -4195,7 +4195,7 @@ export type AppSkillsResponses = { */ 200: Array<{ name: string - description: string + description?: string location: string content: string }>