Skip to content

Commit dad62c9

Browse files
committed
fix: skills list output
1 parent 6aab45f commit dad62c9

File tree

8 files changed

+51
-19
lines changed

8 files changed

+51
-19
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'incur': patch
3+
---
4+
5+
Fixed `skills list` not including root command skill.

src/Cli.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ async function serveImpl(
697697
depth: options.sync?.depth ?? 1,
698698
description: options.description,
699699
include: options.sync?.include,
700+
rootCommand: options.rootCommand,
700701
})
701702
if (result.length === 0) {
702703
writeln('No skills found.')

src/Help.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,10 @@ function envEntries(schema: z.ZodObject<any>) {
261261
}
262262

263263
/** Extracts option entries from a Zod object schema. */
264-
function optionEntries(schema: z.ZodObject<any>, alias?: Partial<Record<string, string>> | undefined) {
264+
function optionEntries(
265+
schema: z.ZodObject<any>,
266+
alias?: Partial<Record<string, string>> | undefined,
267+
) {
265268
const entries: {
266269
flag: string
267270
description: string

src/Skill.test.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ describe('split', () => {
286286
expect(files[0]!.content).toMatchInlineSnapshot(`
287287
"---
288288
name: gh-auth
289-
description: Authenticate with GitHub. Log in, Check status. Run \`gh auth --help\` for usage details.
289+
description: Authenticate with GitHub. Run \`gh auth --help\` for usage details.
290290
requires_bin: gh
291291
command: gh auth
292292
---
@@ -304,7 +304,7 @@ describe('split', () => {
304304
expect(files[1]!.content).toMatchInlineSnapshot(`
305305
"---
306306
name: gh-pr
307-
description: Manage pull requests. List PRs, Create PR. Run \`gh pr --help\` for usage details.
307+
description: Manage pull requests. Run \`gh pr --help\` for usage details.
308308
requires_bin: gh
309309
command: gh pr
310310
---
@@ -321,11 +321,9 @@ describe('split', () => {
321321
`)
322322
})
323323

324-
test('depth 1 without group descriptions uses child descriptions', () => {
324+
test('depth 1 without group descriptions uses fallback hint', () => {
325325
const files = Skill.split('gh', commands, 1)
326-
expect(files[0]!.content).toContain(
327-
'description: Log in, Check status. Run `gh auth --help` for usage details.',
328-
)
326+
expect(files[0]!.content).toContain('description: Run `gh auth --help` for usage details.')
329327
})
330328

331329
test('depth 2 groups by first two segments', () => {

src/Skill.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,9 @@ function renderGroup(
130130
prefix?: string | undefined,
131131
): string {
132132
const groupDesc = prefix ? groups.get(prefix) : undefined
133-
const childDescs = cmds.map((c) => c.description).filter(Boolean) as string[]
134-
const descParts: string[] = []
135-
if (groupDesc) descParts.push(groupDesc.replace(/\.$/, ''))
136-
if (childDescs.length > 0)
137-
descParts.push(childDescs.map((d) => d.replace(/\.$/, '')).join(', '))
138-
const description =
139-
descParts.length > 0
140-
? `${descParts.join('. ')}. Run \`${title} --help\` for usage details.`
141-
: `Run \`${title} --help\` for usage details.`
133+
const description = groupDesc
134+
? `${groupDesc.replace(/\.$/, '')}. Run \`${title} --help\` for usage details.`
135+
: `Run \`${title} --help\` for usage details.`
142136

143137
const fm = ['---', `name: ${slugify(title)}`]
144138
fm.push(`description: ${description}`)

src/SyncSkills.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,25 @@ test('list returns empty for CLI with no commands', async () => {
177177
expect(result).toHaveLength(0)
178178
})
179179

180+
test('list includes root command skill', async () => {
181+
const cli = Cli.create('test', {
182+
description: 'A test CLI',
183+
run: () => ({ ok: true }),
184+
})
185+
cli.command('ping', { description: 'Health check', run: () => ({}) })
186+
187+
const commands = Cli.toCommands.get(cli)!
188+
const rootCommand = Cli.toRootDefinition.get(cli as any)!
189+
const result = await SyncSkills.list('test', commands, {
190+
description: 'A test CLI',
191+
rootCommand,
192+
})
193+
194+
const names = result.map((s) => s.name)
195+
expect(names).toContain('test')
196+
expect(names).toContain('test-ping')
197+
})
198+
180199
test('list results are sorted alphabetically', async () => {
181200
const cli = Cli.create('test')
182201
cli.command('zebra', { description: 'Z command', run: () => ({}) })

src/SyncSkills.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export async function list(
136136

137137
const groups = new Map<string, string>()
138138
if (description) groups.set(name, description)
139-
const entries = collectEntries(commands, [], groups)
139+
const entries = collectEntries(commands, [], groups, options.rootCommand)
140140
const files = Skill.split(name, entries, depth, groups)
141141

142142
const skills: list.Skill[] = []
@@ -191,6 +191,18 @@ export declare namespace list {
191191
description?: string | undefined
192192
/** Glob patterns for directories containing SKILL.md files to include. */
193193
include?: string[] | undefined
194+
/** Root command definition (when the CLI itself is a command). */
195+
rootCommand?:
196+
| {
197+
description?: string | undefined
198+
args?: any
199+
env?: any
200+
hint?: string | undefined
201+
options?: any
202+
output?: any
203+
examples?: any[] | undefined
204+
}
205+
| undefined
194206
}
195207
/** A skill entry with install status. */
196208
type Skill = {

src/e2e.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2909,7 +2909,7 @@ describe('.well-known/skills', () => {
29092909
`)
29102910
expect(result.body.skills[0]).toMatchInlineSnapshot(`
29112911
{
2912-
"description": "Proxy to HTTP API. Run \`app api --help\` for usage details.",
2912+
"description": "Run \`app api --help\` for usage details.",
29132913
"files": [
29142914
"SKILL.md",
29152915
],
@@ -2927,7 +2927,7 @@ describe('.well-known/skills', () => {
29272927
expect(result.body).toMatchInlineSnapshot(`
29282928
"---
29292929
name: app-ping
2930-
description: Health check. Run \`app ping --help\` for usage details.
2930+
description: Run \`app ping --help\` for usage details.
29312931
requires_bin: app
29322932
command: app ping
29332933
---

0 commit comments

Comments
 (0)