mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
Add install guards and prefix support to skills install
- Check for existing installation (looks for teach-impeccable skill), bail with message unless --force is passed - After npx skills add, prompt to prefix commands (default: i-) with custom prefix support; renames folders and updates frontmatter Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
da8a59e981
commit
62349fa4f7
+77
-3
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
import { execSync } from 'node:child_process';
|
||||
import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, writeFileSync, rmSync, createWriteStream } from 'node:fs';
|
||||
import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, writeFileSync, rmSync, renameSync, createWriteStream } from 'node:fs';
|
||||
import { join, resolve, dirname } from 'node:path';
|
||||
import { createInterface } from 'node:readline';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
@@ -59,13 +59,87 @@ async function showHelp() {
|
||||
|
||||
// ─── skills install ───────────────────────────────────────────────────────────
|
||||
|
||||
async function install() {
|
||||
// Check if impeccable skills are already present in any provider folder
|
||||
function isAlreadyInstalled(root) {
|
||||
for (const d of PROVIDER_DIRS) {
|
||||
const skillsDir = join(root, d, 'skills');
|
||||
if (!existsSync(skillsDir)) continue;
|
||||
try {
|
||||
const entries = readdirSync(skillsDir);
|
||||
// Look for teach-impeccable (or any prefixed variant like i-teach-impeccable)
|
||||
if (entries.some(e => e === 'teach-impeccable' || e.endsWith('-teach-impeccable'))) {
|
||||
return d;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function renameSkillsWithPrefix(root, prefix) {
|
||||
let count = 0;
|
||||
for (const d of PROVIDER_DIRS) {
|
||||
const skillsDir = join(root, d, 'skills');
|
||||
if (!existsSync(skillsDir)) continue;
|
||||
try {
|
||||
const entries = readdirSync(skillsDir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
// Skip if already prefixed or not an impeccable skill
|
||||
const skillMd = join(skillsDir, entry.name, 'SKILL.md');
|
||||
if (!existsSync(skillMd)) continue;
|
||||
if (entry.name.startsWith(prefix)) continue;
|
||||
|
||||
const newName = prefix + entry.name;
|
||||
const src = join(skillsDir, entry.name);
|
||||
const dest = join(skillsDir, newName);
|
||||
|
||||
renameSync(src, dest);
|
||||
|
||||
// Update the name in SKILL.md frontmatter
|
||||
let content = readFileSync(join(dest, 'SKILL.md'), 'utf8');
|
||||
content = content.replace(/^name:\s*(.+)$/m, (_, name) => `name: ${prefix}${name.trim()}`);
|
||||
writeFileSync(join(dest, 'SKILL.md'), content);
|
||||
count++;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
async function install(flags) {
|
||||
const force = flags.includes('--force');
|
||||
const root = findProjectRoot();
|
||||
const existing = isAlreadyInstalled(root);
|
||||
|
||||
if (existing && !force) {
|
||||
console.log(`Impeccable skills are already installed (found in ${existing}/).`);
|
||||
console.log('Run with --force to reinstall.\n');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('Installing impeccable skills via npx skills...\n');
|
||||
try {
|
||||
execSync('npx skills add pbakaus/impeccable', { stdio: 'inherit' });
|
||||
} catch (e) {
|
||||
process.exit(e.status ?? 1);
|
||||
}
|
||||
|
||||
// Ask about prefixing
|
||||
let prefix = '';
|
||||
console.log();
|
||||
const wantPrefix = await ask('Prefix commands to avoid conflicts? e.g. /i-audit instead of /audit (y/N) ');
|
||||
if (wantPrefix === 'y' || wantPrefix === 'yes') {
|
||||
const custom = await ask('Prefix (default: i-): ');
|
||||
prefix = custom || 'i-';
|
||||
|
||||
const count = renameSkillsWithPrefix(root, prefix);
|
||||
if (count > 0) {
|
||||
console.log(`\nRenamed ${count} skills with "${prefix}" prefix.`);
|
||||
console.log(`Commands are now available as /${prefix}<command> (e.g. /${prefix}audit).`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nDone! Run /${prefix}teach-impeccable in your AI harness to set up design context.\n`);
|
||||
}
|
||||
|
||||
// ─── skills update ────────────────────────────────────────────────────────────
|
||||
@@ -270,7 +344,7 @@ export async function run(args) {
|
||||
if (!sub || sub === 'help' || sub === '--help' || sub === '-h') {
|
||||
await showHelp();
|
||||
} else if (sub === 'install') {
|
||||
await install();
|
||||
await install(args.slice(1));
|
||||
} else if (sub === 'update') {
|
||||
await update();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user