import { getBackend } from './backend.ts'
import {
ensureSchema,
listFilesForSkill,
listSkillsIndex,
sqlRows,
type SkillRow,
} from './db.ts'
import {
listSkillIdsFromRepo,
parseSkillMeta,
readRepoFile,
skillMetaPath,
withSkillsRepoSession,
} from './repo.ts'
export type SkillListItem = {
id: string
name: string
description: string
files: string[]
updated_at: string
}
async function listFromLegacy(): Promise<SkillListItem[]> {
await ensureSchema()
const skills = await sqlRows<SkillRow>(
`SELECT id, name, description, created_at, updated_at
FROM skills
ORDER BY id ASC`,
)
const items: SkillListItem[] = []
for (const skill of skills) {
const files = await listFilesForSkill(skill.id)
items.push({
id: skill.id,
name: skill.name,
description: skill.description,
files: files.map((file) => file.path),
updated_at: skill.updated_at,
})
}
return items
}
async function listFromRepo(): Promise<SkillListItem[]> {
const indexed = await listSkillsIndex()
if (indexed.length > 0) {
return indexed.map((row) => {
let files: string[] = []
try {
const parsed = JSON.parse(row.files_json) as unknown
if (Array.isArray(parsed)) {
files = parsed.filter((value): value is string => typeof value === 'string')
}
} catch {
files = []
}
return {
id: row.id,
name: row.name,
description: row.description,
files,
updated_at: row.updated_at,
}
})
}
// Index empty (fresh install / before migrate sync): discover from repo.
return withSkillsRepoSession(async (session) => {
const ids = await listSkillIdsFromRepo(session.id)
const items: SkillListItem[] = []
for (const id of ids) {
const meta = parseSkillMeta(
await readRepoFile(session.id, skillMetaPath(id)),
)
if (!meta) continue
items.push({
id,
name: meta.name,
description: meta.description,
files: meta.files,
updated_at: meta.updated_at,
})
}
return items
})
}
/**
* List all skills in the registry with descriptions and file paths.
* This is the agents' index — descriptions are complete enough to choose a skill.
*
* @example
* import skillList from 'kody:@kody/skills/skill-list'
* const skills = await skillList()
* // => [{ id: 'writing-style', name: '...', description: '...', files: ['SKILL.md', ...], updated_at }]
*/
export default async function skillList(): Promise<SkillListItem[]> {
const backend = await getBackend()
return backend === 'repo' ? listFromRepo() : listFromLegacy()
}