repo.ts
1 import { Command } from 'commander'; 2 import { get, post, request } from '../http.js'; 3 import { confirm } from '@inquirer/prompts'; 4 import ora from 'ora'; 5 6 export function repoCommand(): Command { 7 const repo = new Command('repo').description('Work with AtomGit repositories'); 8 9 repo 10 .command('create <name>') 11 .description('Create a new repository') 12 .option('-d, --description <desc>', 'Description of the repository') 13 .option('--public', 'Make the new repository public') 14 .option('--private', 'Make the new repository private') 15 .action(async (name: string, options: { description?: string; public?: boolean; private?: boolean }) => { 16 const spinner = ora('Creating repository...').start(); 17 18 const body = { 19 name, 20 description: options.description || '', 21 private: options.private ?? false, 22 auto_init: true 23 }; 24 25 try { 26 const result = await post('/user/repos', body) as { html_url?: string; full_name?: string }; 27 spinner.succeed(`Created repository ${result.full_name}`); 28 // eslint-disable-next-line no-console 29 console.log(`\n ${result.html_url}`); 30 } catch (error) { 31 spinner.fail('Failed to create repository'); 32 // eslint-disable-next-line no-console 33 console.error(error instanceof Error ? error.message : error); 34 process.exitCode = 1; 35 } 36 }); 37 38 repo 39 .command('delete <repository>') 40 .description('Delete a repository') 41 .option('-y, --yes', 'Skip confirmation prompt') 42 .action(async (repository: string, options: { yes?: boolean }) => { 43 if (!options.yes) { 44 const confirmed = await confirm({ 45 message: `Are you sure you want to delete ${repository}? This cannot be undone.`, 46 default: false 47 }); 48 if (!confirmed) { 49 // eslint-disable-next-line no-console 50 console.log('Aborted.'); 51 return; 52 } 53 } 54 55 const spinner = ora(`Deleting ${repository}...`).start(); 56 57 try { 58 const response = await request(`/repos/${repository}`, { method: 'DELETE' }); 59 if (response.ok || response.status === 204) { 60 spinner.succeed(`Deleted repository ${repository}`); 61 } else { 62 throw new Error(`HTTP ${response.status}: ${response.statusText}`); 63 } 64 } catch (error) { 65 spinner.fail('Failed to delete repository'); 66 // eslint-disable-next-line no-console 67 console.error(error instanceof Error ? error.message : error); 68 process.exitCode = 1; 69 } 70 }); 71 72 repo 73 .command('list') 74 .description('List your repositories') 75 .action(async () => { 76 try { 77 // AtomGit API v5 endpoint for user repos 78 const data = await get('/user/repos'); 79 // eslint-disable-next-line no-console 80 console.log(JSON.stringify(data, null, 2)); 81 } catch (error) { 82 // eslint-disable-next-line no-console 83 console.error('Failed to list repos:', error instanceof Error ? error.message : error); 84 process.exitCode = 1; 85 } 86 }); 87 88 repo 89 .command('view') 90 .description('View repository details') 91 .argument('[owner/repo]', 'Repository in owner/repo format') 92 .action(async (repoPath?: string) => { 93 try { 94 if (!repoPath) { 95 // eslint-disable-next-line no-console 96 console.error('Repository path required (e.g., owner/repo)'); 97 process.exitCode = 1; 98 return; 99 } 100 // AtomGit API v5 endpoint 101 const data = await get(`/repos/${repoPath}`); 102 // eslint-disable-next-line no-console 103 console.log(JSON.stringify(data, null, 2)); 104 } catch (error) { 105 // eslint-disable-next-line no-console 106 console.error('Failed to view repo:', error instanceof Error ? error.message : error); 107 process.exitCode = 1; 108 } 109 }); 110 111 return repo; 112 }