#!/usr/bin/env node import { Command } from 'commander'; import { AppState, Config } from './types.js'; import { TuiEngine } from './tui.js'; import { validateConnection, normalizeUrl } from './api.js'; import chalk from 'chalk'; const program = new Command(); program .name('gitea-tui') .description('A premium CLI TUI Dashboard for exploring Gitea and Forgejo issues') .version('1.0.0') .option('-u, --url ', 'Forgejo/Gitea instance base URL (e.g. https://forgejo.freshbrewed.science)') .option('-i, --userid ', 'Forgejo/Gitea user ID / username') .option('-r, --repo ', 'Repository path (e.g. owner/repo)') .option('-t, --token ', 'Personal Access Token (optional for public repositories)'); program.parse(process.argv); const options = program.opts(); async function bootstrap() { // Initialize default state const state: AppState = { screen: 'setup', config: { url: '', token: null, userid: '', owner: '', repo: '', }, issues: [], currentPage: 1, issuesPerPage: 15, // matches standard screen sizes perfectly totalIssuesCount: 0, loading: false, error: null, selectedIssueIndex: 0, searchQuery: '', stateFilter: 'open', typeFilter: 'all', sortField: 'created', sortOrder: 'desc', selectedIssue: null, selectedIssueComments: [], commentsLoading: false, detailScrollOffset: 0, repos: [], selectedRepoIndex: 0, repoSearchQuery: '', repoPickerActiveSearch: false, setupForm: { url: options.url || 'https://forgejo.freshbrewed.science', userid: options.userid || '', token: options.token || '', activeField: options.url ? (options.userid ? 'token' : 'userid') : 'url', }, }; // If parameters are provided, try direct connection first if (options.url && options.repo) { const repoParts = options.repo.split('/'); if (repoParts.length === 2 && repoParts[0].trim() && repoParts[1].trim()) { const normalized = normalizeUrl(options.url); const config: Config = { url: normalized, token: options.token ? options.token.trim() : null, userid: options.userid || repoParts[0].trim(), owner: repoParts[0].trim(), repo: repoParts[1].trim(), }; console.log(chalk.cyan(`Connecting to Gitea/Forgejo instance at ${normalized}...`)); try { await validateConnection(config); // Valid connection! Go straight to list screen state.config = config; state.screen = 'list'; } catch (err: any) { // Validation failed, let's load setup form with the entered values and show error! state.error = `Connection failed: ${err.message}`; state.screen = 'setup'; state.setupForm = { url: options.url, userid: options.userid || '', token: options.token || '', activeField: 'url', }; } } else { state.error = 'Invalid --repo option. Must be in owner/repo format.'; state.screen = 'setup'; } } // Create and start the TUI engine const engine = new TuiEngine(state); engine.start(() => { // Perform cleanup and exit cleanly console.log(chalk.bold.green('\nThank you for using Forgejo TUI Issue Explorer! Goodbye.')); process.exit(0); }); } bootstrap().catch((err) => { console.error(chalk.bold.red('Fatal Error on Bootstrap:'), err); process.exit(1); });