From 089be62bfcaa9865b0265305377ec26db0e7e54a Mon Sep 17 00:00:00 2001 From: Herve Labas Date: Fri, 3 Jul 2026 14:15:38 +0200 Subject: [PATCH 1/3] fix(cli): list skills references in help --- packages/cli/e2e/__tests__/skills.spec.ts | 27 +++++++++ .../__tests__/command-metadata.spec.ts | 2 + packages/cli/src/commands/skills/index.ts | 58 +++++++++++++++++-- 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/packages/cli/e2e/__tests__/skills.spec.ts b/packages/cli/e2e/__tests__/skills.spec.ts index ca911b315..45ed1255d 100644 --- a/packages/cli/e2e/__tests__/skills.spec.ts +++ b/packages/cli/e2e/__tests__/skills.spec.ts @@ -8,6 +8,16 @@ import { runCheckly } from '../run-checkly' const actionIds = ACTIONS.map(a => a.id) const referenceShortIds = REFERENCES.map(r => r.id.replace('configure-', '')) const investigateReferenceShortIds = INVESTIGATE_REFERENCES.map(r => r.id.replace('investigate-', '')) +const referencesByAction = ACTIONS.flatMap(action => { + if (!('references' in action)) { + return [] + } + + return action.references.map(reference => ({ + actionId: action.id, + shortId: reference.id.replace(`${action.id}-`, ''), + })) +}) describe('checkly skills', () => { let fixt: FixtureSandbox @@ -44,6 +54,23 @@ describe('checkly skills', () => { expect(stdout).toContain(`$ checkly skills investigate ${investigateReferenceShortIds[0]}`) }) + it('should list all actions and references in help output', async () => { + const { stdout } = await runCheckly(fixt, ['skills', '--help']) + + expect(stdout).toContain('Available actions:') + expect(stdout).toContain('Available references:') + + for (const id of actionIds) { + expect(stdout).toContain(id) + expect(stdout).toContain(`checkly skills ${id}`) + } + + for (const { actionId, shortId } of referencesByAction) { + expect(stdout).toContain(`${actionId} ${shortId}`) + expect(stdout).toContain(`checkly skills ${actionId} ${shortId}`) + } + }) + it('should show the initialize action content', async () => { const { stdout } = await runCheckly(fixt, ['skills', 'initialize']) expect(stdout).toBeTruthy() diff --git a/packages/cli/src/commands/__tests__/command-metadata.spec.ts b/packages/cli/src/commands/__tests__/command-metadata.spec.ts index 76830669b..8b5bf11e5 100644 --- a/packages/cli/src/commands/__tests__/command-metadata.spec.ts +++ b/packages/cli/src/commands/__tests__/command-metadata.spec.ts @@ -38,6 +38,7 @@ import ImportCommit from '../import/commit.js' import ImportCancel from '../import/cancel.js' import PwTest from '../pw-test.js' import SyncPlaywright from '../sync-playwright.js' +import Skills from '../skills/index.js' import SkillsInstall from '../skills/install.js' import AccountPlan from '../account/plan.js' import Members from '../members.js' @@ -91,6 +92,7 @@ const commands: Array<[string, typeof BaseCommand]> = [ ['import cancel', ImportCancel], ['pw-test', PwTest], ['sync-playwright', SyncPlaywright], + ['skills', Skills], ['skills install', SkillsInstall], ] diff --git a/packages/cli/src/commands/skills/index.ts b/packages/cli/src/commands/skills/index.ts index 9a39fb506..aefd948c1 100644 --- a/packages/cli/src/commands/skills/index.ts +++ b/packages/cli/src/commands/skills/index.ts @@ -10,18 +10,66 @@ const __dirname = dirname(fileURLToPath(import.meta.url)) const REFERENCES_DIR = join(__dirname, '../../ai-context/skills-command/references') +function referenceShortId (actionId: string, referenceId: string): string { + return referenceId.replace(`${actionId}-`, '') +} + +function formatAvailableActions (): string { + return ACTIONS + .map(action => ` ${action.id} - ${action.description}`) + .join('\n') +} + +function formatAvailableReferences (): string { + return ACTIONS + .flatMap(action => { + if (!('references' in action)) { + return [` checkly skills ${action.id} - no references`] + } + + return action.references.map(reference => ( + ` checkly skills ${action.id} ${referenceShortId(action.id, reference.id)} - ${reference.description}` + )) + }) + .join('\n') +} + export default class Skills extends BaseCommand { static hidden = false - static description = 'Show Checkly AI skills, actions and their references.' + static readOnly = true + static destructive = false + static idempotent = true + static description = [ + 'Show Checkly AI skills, actions and their references.', + '', + 'Run `checkly skills` to print the full catalog, `checkly skills ` for an action guide, or `checkly skills ` for a specific reference.', + '', + 'Available actions:', + formatAvailableActions(), + '', + 'Available references:', + formatAvailableReferences(), + ].join('\n') + + static examples = [ + 'checkly skills', + ...ACTIONS.flatMap(action => { + const examples = [`checkly skills ${action.id}`] + if ('references' in action) { + examples.push(`checkly skills ${action.id} ${referenceShortId(action.id, action.references[0].id)}`) + } + return examples + }), + ] static args = { action: Args.string({ required: false, - description: 'The action name (e.g. "configure", "initialize").', + description: `Action to open. Available: ${ACTIONS.map(action => action.id).join(', ')}.`, }), reference: Args.string({ required: false, - description: 'A specific reference within the action (e.g. "api-checks").', + description: 'Reference to open for the selected action. Available references are listed below.', }), } @@ -75,7 +123,7 @@ export default class Skills extends BaseCommand { this.log(` $ checkly skills ${action.id}`) if ('references' in action) { const firstRef = action.references[0] - const refId = firstRef.id.replace(`${action.id}-`, '') + const refId = referenceShortId(action.id, firstRef.id) this.log(` $ checkly skills ${action.id} ${refId}`) } } @@ -98,7 +146,7 @@ export default class Skills extends BaseCommand { this.log(`References for "${action.id}":\n`) const refs = action.references.map(r => ({ - shortId: r.id.replace(`${action.id}-`, ''), + shortId: referenceShortId(action.id, r.id), description: r.description, })) const maxRefLen = Math.max(...refs.map(r => r.shortId.length)) From 6fa761ef77a4cc11b1836b15f1fa68d195eac695 Mon Sep 17 00:00:00 2001 From: Herve Labas Date: Fri, 3 Jul 2026 14:41:14 +0200 Subject: [PATCH 2/3] fix(cli): streamline skills help output --- packages/cli/e2e/__tests__/skills.spec.ts | 10 +++++--- packages/cli/src/commands/skills/index.ts | 29 ++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/cli/e2e/__tests__/skills.spec.ts b/packages/cli/e2e/__tests__/skills.spec.ts index 45ed1255d..f777baaec 100644 --- a/packages/cli/e2e/__tests__/skills.spec.ts +++ b/packages/cli/e2e/__tests__/skills.spec.ts @@ -59,16 +59,20 @@ describe('checkly skills', () => { expect(stdout).toContain('Available actions:') expect(stdout).toContain('Available references:') + expect(stdout).toContain('checkly skills configure api-checks') + expect(stdout).toContain('checkly skills investigate alerting') for (const id of actionIds) { expect(stdout).toContain(id) - expect(stdout).toContain(`checkly skills ${id}`) } for (const { actionId, shortId } of referencesByAction) { - expect(stdout).toContain(`${actionId} ${shortId}`) - expect(stdout).toContain(`checkly skills ${actionId} ${shortId}`) + expect(stdout).toContain(`${actionId}:`) + expect(stdout).toContain(shortId) } + + expect(stdout).not.toContain(REFERENCES[0].description) + expect(stdout).not.toContain(INVESTIGATE_REFERENCES[0].description) }) it('should show the initialize action content', async () => { diff --git a/packages/cli/src/commands/skills/index.ts b/packages/cli/src/commands/skills/index.ts index aefd948c1..630b2a01e 100644 --- a/packages/cli/src/commands/skills/index.ts +++ b/packages/cli/src/commands/skills/index.ts @@ -15,21 +15,20 @@ function referenceShortId (actionId: string, referenceId: string): string { } function formatAvailableActions (): string { - return ACTIONS - .map(action => ` ${action.id} - ${action.description}`) - .join('\n') + return ` ${ACTIONS.map(action => action.id).join(', ')}` } function formatAvailableReferences (): string { return ACTIONS - .flatMap(action => { + .map(action => { if (!('references' in action)) { - return [` checkly skills ${action.id} - no references`] + return ` ${action.id}: none` } - return action.references.map(reference => ( - ` checkly skills ${action.id} ${referenceShortId(action.id, reference.id)} - ${reference.description}` - )) + const references = action.references + .map(reference => referenceShortId(action.id, reference.id)) + .join(', ') + return ` ${action.id}: ${references}` }) .join('\n') } @@ -49,23 +48,21 @@ export default class Skills extends BaseCommand { '', 'Available references:', formatAvailableReferences(), + '', + 'Use `checkly skills ` or `checkly skills ` to open the detailed guidance.', ].join('\n') static examples = [ 'checkly skills', - ...ACTIONS.flatMap(action => { - const examples = [`checkly skills ${action.id}`] - if ('references' in action) { - examples.push(`checkly skills ${action.id} ${referenceShortId(action.id, action.references[0].id)}`) - } - return examples - }), + 'checkly skills configure', + 'checkly skills configure api-checks', + 'checkly skills investigate alerting', ] static args = { action: Args.string({ required: false, - description: `Action to open. Available: ${ACTIONS.map(action => action.id).join(', ')}.`, + description: 'Action to open. Available actions are listed below.', }), reference: Args.string({ required: false, From e71cc2d27e1c8749b3400ddb2d58b57e5c0b1dd8 Mon Sep 17 00:00:00 2001 From: Herve Labas Date: Fri, 3 Jul 2026 14:52:56 +0200 Subject: [PATCH 3/3] fix(cli): render skills help as tree --- packages/cli/e2e/__tests__/skills.spec.ts | 9 +++---- packages/cli/src/commands/skills/index.ts | 30 +++++++++-------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/cli/e2e/__tests__/skills.spec.ts b/packages/cli/e2e/__tests__/skills.spec.ts index f777baaec..ad5a796b1 100644 --- a/packages/cli/e2e/__tests__/skills.spec.ts +++ b/packages/cli/e2e/__tests__/skills.spec.ts @@ -57,18 +57,17 @@ describe('checkly skills', () => { it('should list all actions and references in help output', async () => { const { stdout } = await runCheckly(fixt, ['skills', '--help']) - expect(stdout).toContain('Available actions:') - expect(stdout).toContain('Available references:') + expect(stdout).toContain('Available actions and references:') expect(stdout).toContain('checkly skills configure api-checks') expect(stdout).toContain('checkly skills investigate alerting') for (const id of actionIds) { - expect(stdout).toContain(id) + expect(stdout).toContain(`|- ${id}`) } for (const { actionId, shortId } of referencesByAction) { - expect(stdout).toContain(`${actionId}:`) - expect(stdout).toContain(shortId) + expect(stdout).toContain(`|- ${actionId}`) + expect(stdout).toContain(`| |- ${shortId}`) } expect(stdout).not.toContain(REFERENCES[0].description) diff --git a/packages/cli/src/commands/skills/index.ts b/packages/cli/src/commands/skills/index.ts index 630b2a01e..a4fd117ef 100644 --- a/packages/cli/src/commands/skills/index.ts +++ b/packages/cli/src/commands/skills/index.ts @@ -14,23 +14,20 @@ function referenceShortId (actionId: string, referenceId: string): string { return referenceId.replace(`${actionId}-`, '') } -function formatAvailableActions (): string { - return ` ${ACTIONS.map(action => action.id).join(', ')}` -} - -function formatAvailableReferences (): string { - return ACTIONS - .map(action => { +function formatAvailableActionTree (): string { + return [ + ' checkly skills', + ...ACTIONS.flatMap(action => { + const actionLine = ` |- ${action.id}` if (!('references' in action)) { - return ` ${action.id}: none` + return [actionLine] } const references = action.references - .map(reference => referenceShortId(action.id, reference.id)) - .join(', ') - return ` ${action.id}: ${references}` - }) - .join('\n') + .map(reference => ` | |- ${referenceShortId(action.id, reference.id)}`) + return [actionLine, ...references] + }), + ].join('\n') } export default class Skills extends BaseCommand { @@ -43,11 +40,8 @@ export default class Skills extends BaseCommand { '', 'Run `checkly skills` to print the full catalog, `checkly skills ` for an action guide, or `checkly skills ` for a specific reference.', '', - 'Available actions:', - formatAvailableActions(), - '', - 'Available references:', - formatAvailableReferences(), + 'Available actions and references:', + formatAvailableActionTree(), '', 'Use `checkly skills ` or `checkly skills ` to open the detailed guidance.', ].join('\n')