Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions cli/src/commands/uninstall.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { rm, stat } from 'node:fs/promises';
import { join } from 'node:path';
import { join, relative } from 'node:path';
import { homedir } from 'node:os';
import chalk from 'chalk';
import ora from 'ora';
Expand All @@ -8,25 +8,54 @@ import type { AIType } from '../types/index.js';
import { AI_TYPES, AI_FOLDERS } from '../types/index.js';
import { detectAIType, getAITypeDescription } from '../utils/detect.js';
import { logger } from '../utils/logger.js';
import { loadPlatformConfig } from '../utils/template.js';

interface UninstallOptions {
ai?: AIType;
global?: boolean;
}

/**
* Get all known install directories for a given AI type.
* This covers both template-generated installs and older shared-folder layouts.
*/
async function getCandidateSkillDirs(
baseDir: string,
aiType: Exclude<AIType, 'all'>
): Promise<string[]> {
const candidates = new Set<string>();

try {
const config = await loadPlatformConfig(aiType);
candidates.add(join(baseDir, config.folderStructure.root, config.folderStructure.skillPath));
} catch {
// Skip template path lookup if this platform has no config.
}

for (const folder of AI_FOLDERS[aiType]) {
if (folder === '.shared') {
candidates.add(join(baseDir, folder, 'ui-ux-pro-max'));
continue;
}

candidates.add(join(baseDir, folder, 'skills', 'ui-ux-pro-max'));
}

return Array.from(candidates);
}

/**
* Remove skill directory for a given AI type
*/
async function removeSkillDir(baseDir: string, aiType: Exclude<AIType, 'all'>): Promise<string[]> {
const folders = AI_FOLDERS[aiType];
const skillDirs = await getCandidateSkillDirs(baseDir, aiType);
const removed: string[] = [];

for (const folder of folders) {
const skillDir = join(baseDir, folder, 'skills', 'ui-ux-pro-max');
for (const skillDir of skillDirs) {
try {
await stat(skillDir);
await rm(skillDir, { recursive: true, force: true });
removed.push(`${folder}/skills/ui-ux-pro-max`);
removed.push(relative(baseDir, skillDir));
} catch (err: unknown) {
// Skip non-existent dirs; re-throw permission or other errors
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;
Expand Down