#!/usr/bin/env node
/**
* Update Skill Metadata
*
* Manually update skill metadata after creating or regenerating a skill.
*
* Usage:
* node scripts/update-skill-metadata.js hypercore # Mark hypercore as updated
* node scripts/update-skill-metadata.js --init # Initialize all skills
* node scripts/update-skill-metadata.js --batch skill1 skill2 skill3
*/
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const KB_ROOT = join(__dirname, '..')
const SKILLS_DIR = join(KB_ROOT, '.claude', 'skills')
const METADATA_FILE = join(SKILLS_DIR, '.skill-metadata.json')
// Load or create metadata
function loadMetadata() {
if (!existsSync(METADATA_FILE)) {
return {}
}
return JSON.parse(readFileSync(METADATA_FILE, 'utf-8'))
}
function saveMetadata(metadata) {
writeFileSync(METADATA_FILE, JSON.stringify(metadata, null, 2))
console.log(`Saved metadata for ${Object.keys(metadata).length} skills`)
}
// Get all skills
function getAllSkills() {
const skills = []
const entries = readdirSync(SKILLS_DIR, { withFileTypes: true })
for (const entry of entries) {
if (entry.isDirectory()) {
const skillFile = join(SKILLS_DIR, entry.name, 'SKILL.md')
if (existsSync(skillFile)) {
const stats = statSync(skillFile)
skills.push({
name: entry.name,
path: skillFile,
mtime: stats.mtime.getTime()
})
}
}
}
return skills
}
// Initialize metadata for all skills based on file mtime
function initializeMetadata() {
console.log('Initializing metadata for all skills...')
const skills = getAllSkills()
const metadata = {}
for (const skill of skills) {
metadata[skill.name] = {
lastUpdated: skill.mtime,
lastChecked: Date.now(),
source: 'file-mtime'
}
}
saveMetadata(metadata)
console.log(`✅ Initialized metadata for ${skills.length} skills`)
}
// Mark specific skill as updated
function markSkillUpdated(skillName) {
const metadata = loadMetadata()
const skillPath = join(SKILLS_DIR, skillName, 'SKILL.md')
if (!existsSync(skillPath)) {
console.error(`❌ Skill not found: ${skillName}`)
process.exit(1)
}
metadata[skillName] = {
lastUpdated: Date.now(),
lastChecked: Date.now(),
source: 'manual'
}
saveMetadata(metadata)
console.log(`✅ Marked ${skillName} as updated`)
}
// Mark multiple skills as updated
function markBatchUpdated(skillNames) {
const metadata = loadMetadata()
for (const skillName of skillNames) {
const skillPath = join(SKILLS_DIR, skillName, 'SKILL.md')
if (!existsSync(skillPath)) {
console.error(`❌ Skill not found: ${skillName}`)
continue
}
metadata[skillName] = {
lastUpdated: Date.now(),
lastChecked: Date.now(),
source: 'batch-update'
}
console.log(`✅ Marked ${skillName} as updated`)
}
saveMetadata(metadata)
}
// Main
function main() {
const args = process.argv.slice(2)
if (args.length === 0) {
console.error('Usage:')
console.error(' node update-skill-metadata.js <skill-name>')
console.error(' node update-skill-metadata.js --init')
console.error(' node update-skill-metadata.js --batch skill1 skill2 ...')
process.exit(1)
}
if (args[0] === '--init') {
initializeMetadata()
return
}
if (args[0] === '--batch') {
const skillNames = args.slice(1)
if (skillNames.length === 0) {
console.error('No skills specified for batch update')
process.exit(1)
}
markBatchUpdated(skillNames)
return
}
// Single skill update
const skillName = args[0]
markSkillUpdated(skillName)
}
main()