Files
ui-ux-pro-max-skill/cli/src/commands/uninstall.ts
T
红尘 d5334df59c
Check asset sync / cli/assets must match src/ui-ux-pro-max (push) Has been cancelled
Release / Semantic release (push) Has been cancelled
Smoke test data / smoke (push) Has been cancelled
Initial import from GitHub
2026-07-08 22:47:26 +08:00

157 lines
4.6 KiB
TypeScript

import { rm, stat } from 'node:fs/promises';
import { join, dirname } from 'node:path';
import { homedir } from 'node:os';
import chalk from 'chalk';
import ora from 'ora';
import prompts from 'prompts';
import type { AIType, ConcreteAIType } from '../types/index.js';
import { AI_TYPES, AI_FOLDERS } from '../types/index.js';
import { detectAIType, getAITypeDescription } from '../utils/detect.js';
import { listBundledSubSkills, loadPlatformConfig } from '../utils/template.js';
import { logger } from '../utils/logger.js';
interface UninstallOptions {
ai?: AIType;
global?: boolean;
}
/**
* Remove skill directory for a given AI type
*/
async function removeSkillDir(baseDir: string, aiType: ConcreteAIType): Promise<string[]> {
const removed: string[] = [];
// The orchestrator plus the bundled sibling sub-skills installed by init.
const skillNames = ['ui-ux-pro-max', ...(await listBundledSubSkills())];
// Parent directories to clean. Derive the real install location from the
// platform config's skillPath (same source the installer uses), so
// non-`skills/` platforms are handled — copilot installs under
// `.github/prompts/`, kiro under `.kiro/steering/`. Also clean the legacy
// `<folder>/skills/` layout (incl. `.shared/`) so older installs are removed.
const parents = new Set<string>();
try {
const { folderStructure } = await loadPlatformConfig(aiType);
parents.add(join(folderStructure.root, dirname(folderStructure.skillPath)));
} catch {
// No platform config — fall back to the legacy folders below.
}
for (const folder of AI_FOLDERS[aiType]) {
parents.add(join(folder, 'skills'));
}
for (const parent of parents) {
for (const name of skillNames) {
const skillDir = join(baseDir, parent, name);
try {
await stat(skillDir);
await rm(skillDir, { recursive: true, force: true });
removed.push(`${parent.replaceAll('\\', '/')}/${name}`);
} catch (err: unknown) {
// Skip non-existent dirs; re-throw permission or other errors
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;
}
}
}
return removed;
}
export async function uninstallCommand(options: UninstallOptions): Promise<void> {
logger.title('UI/UX Pro Max Uninstaller');
const isGlobal = !!options.global;
const baseDir = isGlobal ? homedir() : process.cwd();
const locationLabel = isGlobal ? '~/ (global)' : process.cwd();
let aiType = options.ai;
const { detected: initialDetected } = detectAIType(baseDir);
// Auto-detect or prompt for AI type
if (!aiType) {
const detected = initialDetected;
if (detected.length === 0) {
logger.warn('No installed AI skill directories detected.');
return;
}
logger.info(`Detected installations: ${detected.map(t => chalk.cyan(t)).join(', ')}`);
const choices = [
...detected.map(type => ({
title: getAITypeDescription(type),
value: type,
})),
{ title: 'All detected', value: 'all' as AIType },
];
const response = await prompts({
type: 'select',
name: 'aiType',
message: 'Select which AI skill to uninstall:',
choices,
});
if (!response.aiType) {
logger.warn('Uninstall cancelled');
return;
}
aiType = response.aiType as AIType;
}
// Confirm before removing
const { confirmed } = await prompts({
type: 'confirm',
name: 'confirmed',
message: `Remove UI/UX Pro Max skill for ${chalk.cyan(getAITypeDescription(aiType))} from ${locationLabel}?`,
initial: false,
});
if (!confirmed) {
logger.warn('Uninstall cancelled');
return;
}
const spinner = ora('Removing skill files...').start();
try {
const allRemoved: string[] = [];
if (aiType === 'all') {
// Remove for all detected platforms
for (const type of initialDetected) {
const removed = await removeSkillDir(baseDir, type);
allRemoved.push(...removed);
}
} else {
const removed = await removeSkillDir(baseDir, aiType);
allRemoved.push(...removed);
}
if (allRemoved.length === 0) {
spinner.warn('No skill files found to remove');
return;
}
spinner.succeed('Skill files removed!');
console.log();
logger.info('Removed:');
allRemoved.forEach(folder => {
console.log(` ${chalk.red('-')} ${folder}`);
});
console.log();
logger.success('UI/UX Pro Max uninstalled successfully!');
console.log();
} catch (error) {
spinner.fail('Uninstall failed');
if (error instanceof Error) {
logger.error(error.message);
}
process.exit(1);
}
}