← Public packages
@kentcdodds/skills
Store, retrieve, edit, version, and revert reusable agent skill documents via skillList then skillGet.
src/skill-history.ts
106 lines · 2.4 KB · TypeScriptimport { getBackend } from './backend.ts'
import {
ensureSchema,
getSkillOrThrow,
listSkillRevisions,
sqlRows,
} from './db.ts'
export type SkillHistoryInput = {
id: string
path?: string
limit?: number
}
export type SkillHistoryItem = {
versionId: number
path: string
replacedAt: string
contentLength: number
/** Present on the repo backend: git commit that holds the restored content. */
commitOid?: string
}
type SqlVersionRow = {
id: number
skill_id: string
path: string
content: string
replaced_at: string
}
async function historyLegacy(
id: string,
path: string,
limit: number,
): Promise<SkillHistoryItem[]> {
await ensureSchema()
await getSkillOrThrow(id)
const rows = path
? await sqlRows<SqlVersionRow>(
`SELECT id, skill_id, path, content, replaced_at
FROM skill_versions
WHERE skill_id = ? AND path = ?
ORDER BY id DESC
LIMIT ?`,
[id, path, limit],
)
: await sqlRows<SqlVersionRow>(
`SELECT id, skill_id, path, content, replaced_at
FROM skill_versions
WHERE skill_id = ?
ORDER BY id DESC
LIMIT ?`,
[id, limit],
)
return rows.map((row) => ({
versionId: Number(row.id),
path: row.path,
replacedAt: row.replaced_at,
contentLength: String(row.content ?? '').length,
}))
}
async function historyRepo(
id: string,
path: string,
limit: number,
): Promise<SkillHistoryItem[]> {
await getSkillOrThrow(id)
const rows = await listSkillRevisions({
skillId: id,
path: path || undefined,
limit,
})
return rows.map((row) => ({
versionId: Number(row.id),
path: row.path,
replacedAt: row.replacedAt,
contentLength: Number(row.contentLength),
commitOid: row.commitOid,
}))
}
/**
* Recent skill version metadata (not full content).
* On the repo backend, each version maps to a git commit (`commitOid`).
*
* @example
* import skillHistory from 'kody:@kentcdodds/skills/skill-history'
* const history = await skillHistory({ id: 'kent-writing-voice', limit: 10 })
*/
export default async function skillHistory(
params: SkillHistoryInput = {} as SkillHistoryInput,
): Promise<SkillHistoryItem[]> {
const id = String(params.id ?? '').trim()
if (!id) throw new Error('skillHistory requires `id`.')
const path = params.path == null ? '' : String(params.path).trim()
const limit = Math.max(1, Math.min(200, Number(params.limit ?? 50) || 50))
const backend = await getBackend()
return backend === 'repo'
? historyRepo(id, path, limit)
: historyLegacy(id, path, limit)
}