ソースを参照

fix(skill): allow missing descriptions (#26391)

Dax 4 ヶ月 前
コミット
fed221e0b0

+ 7 - 6
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 [
       "<available_skills>",
-      ...list
-        .sort((a, b) => a.name.localeCompare(b.name))
+      ...described
+        .toSorted((a, b) => a.name.localeCompare(b.name))
         .flatMap((skill) => [
           "  <skill>",
           `    <name>${skill.name}</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")

+ 6 - 0
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")
     }),
   )
 })

+ 31 - 0
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) =>

+ 1 - 1
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
   }>