import { existsSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs' import { join } from 'node:path' export const LEGACY_SHIM_MARKER = '// tela-skills compatibility shim: the skill now lives in ../tela-studio/. Kept so previously copied commands keep working.' const shims = { 'preload.ts': `${LEGACY_SHIM_MARKER}\nimport '../tela-studio/preload.ts'\n`, 'localhost-utils.ts': `${LEGACY_SHIM_MARKER}\nexport * from '../tela-studio/localhost-utils.ts'\n`, } /** * The skill used to install to ~/.claude/skills/tela/. Instead of deleting that directory, drop its * SKILL.md so Claude Code stops registering a second skill and turn the two documented entry points * into forwarders, leaving every other file (including anything the user added) in place. */ export function migrateLegacySkillDir(legacyDir: string) { if (!existsSync(legacyDir)) return 'absent' const preload = join(legacyDir, 'preload.ts') const skillFile = join(legacyDir, 'SKILL.md') const hasSkillFile = existsSync(skillFile) const isShim = (file: keyof typeof shims) => { const path = join(legacyDir, file) return statSync(path, { throwIfNoEntry: false })?.isFile() && readFileSync(path, 'utf8') === shims[file] } const hasPreloadShim = isShim('preload.ts') if (!hasSkillFile && hasPreloadShim && isShim('localhost-utils.ts')) return 'already-migrated' // A partial migration may have removed SKILL.md already. Only our exact preload // shim can establish ownership in that case; never override a foreign SKILL.md. const isOurs = hasSkillFile ? existsSync(preload) && /^name: tela$/m.test(readFileSync(skillFile, 'utf8')) : hasPreloadShim if (!isOurs) return 'skipped' for (const [file, content] of Object.entries(shims)) writeFileSync(join(legacyDir, file), content) rmSync(skillFile, { force: true }) return 'migrated' }