feat: skills disable command + sync wizard pre-checks installed skills (#465)

This commit is contained in:
Cameron
2026-03-02 17:30:04 -08:00
committed by GitHub
parent 37d979cbe1
commit 72c2abacc0
4 changed files with 32 additions and 5 deletions

View File

@@ -335,7 +335,7 @@ async function main() {
break; break;
case 'skills': { case 'skills': {
const { showStatus, runSkillsSync, enableSkill } = await import('./skills/index.js'); const { showStatus, runSkillsSync, enableSkill, disableSkill } = await import('./skills/index.js');
switch (subCommand) { switch (subCommand) {
case 'status': case 'status':
await showStatus(); await showStatus();
@@ -347,6 +347,13 @@ async function main() {
} }
enableSkill(args[2]); enableSkill(args[2]);
break; break;
case 'disable':
if (!args[2]) {
console.error('Usage: lettabot skills disable <name>');
process.exit(1);
}
disableSkill(args[2]);
break;
default: default:
await runSkillsSync(); await runSkillsSync();
} }

View File

@@ -149,11 +149,12 @@ export async function runSkillsSync(): Promise<void> {
} }
} }
// Start with no skills selected (user must explicitly enable) // Pre-check currently installed skills so the user edits from current state
const currentlyInstalled = skills.filter(s => s.installed).map(s => s.name);
const selected = await p.multiselect({ const selected = await p.multiselect({
message: 'Enable skills (space=toggle, enter=confirm):', message: 'Enable skills (space=toggle, enter=confirm):',
options, options,
initialValues: [], // Disabled by default initialValues: currentlyInstalled,
required: false, required: false,
}); });
@@ -220,6 +221,24 @@ export async function runSkillsSync(): Promise<void> {
p.outro(`✨ Added ${toAdd.length}, removed ${toRemove.length} skill(s)`); p.outro(`✨ Added ${toAdd.length}, removed ${toRemove.length} skill(s)`);
} }
/**
* Non-interactively disable a single skill by name.
*/
export function disableSkill(name: string): void {
const dest = join(TARGET_DIR, name);
if (!existsSync(dest)) {
console.log(`Skill '${name}' is not enabled.`);
return;
}
try {
rmSync(dest, { recursive: true, force: true });
console.log(`Disabled skill '${name}'.`);
} catch (e) {
console.error(`Failed to disable '${name}': ${e}`);
process.exit(1);
}
}
/** /**
* Non-interactively enable a single skill by name. * Non-interactively enable a single skill by name.
* Searches BUNDLED_SKILLS_DIR, then GLOBAL_SKILLS_DIR, then SKILLS_SH_DIR. * Searches BUNDLED_SKILLS_DIR, then GLOBAL_SKILLS_DIR, then SKILLS_SH_DIR.

View File

@@ -293,6 +293,7 @@ export async function showStatus(): Promise<void> {
} }
log.info(''); log.info('');
log.info(` To enable: lettabot skills enable <name> (or run: lettabot skills)`); log.info(` To enable: lettabot skills enable <name> (or run: lettabot skills)`);
log.info(` To disable: lettabot skills disable <name>`);
log.info(` Skills dir: ${WORKING_SKILLS_DIR}`); log.info(` Skills dir: ${WORKING_SKILLS_DIR}`);
} }

View File

@@ -2,7 +2,7 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({ export default defineConfig({
test: { test: {
exclude: ['dist/**', 'node_modules/**'], exclude: ['dist/**', 'node_modules/**', '.git/**'],
}, },
}); });