feat: add uxpro-cli for easy skill installation (#4)
* feat: add uxpro-cli for easy skill installation - Add CLI tool (uxpro-cli) with commands: init, versions, update - Support multiple AI assistants: claude, cursor, windsurf, antigravity, all - Update README with CLI installation guide and usage examples - Add CC BY-NC 4.0 license - Update feature counts to accurate numbers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename CLI from uxpro to uipro - Package: uxpro-cli -> uipro-cli - Command: uxpro -> uipro 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
72
cli/src/utils/extract.ts
Normal file
72
cli/src/utils/extract.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import type { AIType } from '../types/index.js';
|
||||
import { AI_FOLDERS } from '../types/index.js';
|
||||
|
||||
export async function extractZip(zipPath: string, destDir: string): Promise<void> {
|
||||
const proc = Bun.spawn(['unzip', '-o', zipPath, '-d', destDir], {
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
});
|
||||
|
||||
const exitCode = await proc.exited;
|
||||
if (exitCode !== 0) {
|
||||
throw new Error(`Failed to extract zip: exit code ${exitCode}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function copyFolders(
|
||||
sourceDir: string,
|
||||
targetDir: string,
|
||||
aiType: AIType
|
||||
): Promise<string[]> {
|
||||
const copiedFolders: string[] = [];
|
||||
|
||||
const foldersToCopy = aiType === 'all'
|
||||
? ['.claude', '.cursor', '.windsurf', '.agent', '.shared']
|
||||
: AI_FOLDERS[aiType];
|
||||
|
||||
// Deduplicate folders (e.g., .shared might be listed multiple times)
|
||||
const uniqueFolders = [...new Set(foldersToCopy)];
|
||||
|
||||
for (const folder of uniqueFolders) {
|
||||
const sourcePath = join(sourceDir, folder);
|
||||
const targetPath = join(targetDir, folder);
|
||||
|
||||
// Check if source folder exists
|
||||
const sourceExists = await Bun.file(sourcePath).exists().catch(() => false);
|
||||
if (!sourceExists) {
|
||||
// Try checking if it's a directory
|
||||
try {
|
||||
const proc = Bun.spawn(['test', '-d', sourcePath]);
|
||||
await proc.exited;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Create target directory if needed
|
||||
await mkdir(targetPath, { recursive: true });
|
||||
|
||||
// Copy using cp -r
|
||||
const proc = Bun.spawn(['cp', '-r', `${sourcePath}/.`, targetPath], {
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
});
|
||||
|
||||
const exitCode = await proc.exited;
|
||||
if (exitCode === 0) {
|
||||
copiedFolders.push(folder);
|
||||
}
|
||||
}
|
||||
|
||||
return copiedFolders;
|
||||
}
|
||||
|
||||
export async function cleanup(tempDir: string): Promise<void> {
|
||||
const proc = Bun.spawn(['rm', '-rf', tempDir], {
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
});
|
||||
await proc.exited;
|
||||
}
|
||||
Reference in New Issue
Block a user