#!/usr/bin/env node /** * Gitea CLI — standalone command-line interface * * Usage: gitea [options] * Replaces gitea-scripts/gitea.js with the consolidated core. */ import { GiteaClient } from "./src/client.js"; import * as repos from "./src/repos.js"; import * as issues from "./src/issues.js"; import * as pulls from "./src/pulls.js"; import * as actions from "./src/actions.js"; import * as webhooks from "./src/webhooks.js"; import * as files from "./src/files.js"; const client = new GiteaClient(); function parseArgs(argv: string[]): { positional: string[]; flags: Record } { const positional: string[] = []; const flags: Record = {}; for (let i = 0; i < argv.length; i++) { if (argv[i].startsWith("--")) { const key = argv[i].slice(2); const next = argv[i + 1]; if (next && !next.startsWith("--")) { flags[key] = next; i++; } else { flags[key] = true; } } else { positional.push(argv[i]); } } return { positional, flags }; } function splitOwnerRepo(input: string): { owner: string; repo: string } { const parts = input.split("/"); if (parts.length === 2) return { owner: parts[0], repo: parts[1] }; return { owner: client.defaultOwner, repo: input }; } const commands: Record Promise> = { async whoami() { const user = await client.get<{ login: string; email: string }>("/user"); console.log(JSON.stringify(user, null, 2)); }, async repos(args) { const { flags } = parseArgs(args); const result = await repos.listRepos(client, { owner: flags.owner as string, limit: flags.limit ? parseInt(flags.limit as string) : undefined, }); for (const r of result) { console.log(`${r.full_name} [${r.private ? "private" : "public"}]`); } }, async "create-repo"(args) { const { positional, flags } = parseArgs(args); const name = positional[0]; if (!name) { console.error("Usage: create-repo [--private] [--description ...]"); process.exit(1); } const repo = await repos.createRepo(client, { name, private: !!flags.private, description: flags.description as string, }); console.log(`✅ Created: ${repo.html_url}`); }, async "ensure-repo"(args) { const { positional, flags } = parseArgs(args); const name = positional[0]; if (!name) { console.error("Usage: ensure-repo [--private]"); process.exit(1); } const { repo, created } = await repos.ensureRepo(client, client.defaultOwner, name, { private: !!flags.private, }); console.log(`${created ? "created" : "exists"}: ${repo.clone_url}`); }, async issues(args) { const { positional } = parseArgs(args); const target = positional[0]; if (!target) { console.error("Usage: issues "); process.exit(1); } const { owner, repo } = splitOwnerRepo(target); const list = await issues.listIssues(client, owner, repo); for (const i of list) { console.log(`#${i.number} [${i.state}] ${i.title}`); } }, async "create-issue"(args) { const { positional, flags } = parseArgs(args); const target = positional[0]; const title = positional[1]; if (!target || !title) { console.error("Usage: create-issue [--body ...]"); process.exit(1); } const { owner, repo } = splitOwnerRepo(target); const issue = await issues.createIssue(client, owner, repo, { title, body: flags.body as string, }); console.log(`✅ Issue #${issue.number}: ${issue.html_url}`); }, async prs(args) { const { positional } = parseArgs(args); const target = positional[0]; if (!target) { console.error("Usage: prs <owner/repo>"); process.exit(1); } const { owner, repo } = splitOwnerRepo(target); const list = await pulls.listPullRequests(client, owner, repo); for (const p of list) { console.log(`#${p.number} [${p.state}] ${p.title} (${p.head?.label} → ${p.base?.label})`); } }, async runs(args) { const { positional } = parseArgs(args); const target = positional[0]; if (!target) { console.error("Usage: runs <owner/repo>"); process.exit(1); } const { owner, repo } = splitOwnerRepo(target); const { runs } = await actions.listRuns(client, owner, repo); for (const r of runs) { console.log(`#${r.run_number} [${r.id}] ${r.conclusion ?? r.status} — ${r.display_title} (${r.head_branch})`); } }, async "add-webhook"(args) { const { positional, flags } = parseArgs(args); const target = positional[0]; const webhookUrl = positional[1]; if (!target || !webhookUrl) { console.error("Usage: add-webhook <owner/repo> <url> [--token ...]"); process.exit(1); } const { owner, repo } = splitOwnerRepo(target); const hook = await webhooks.createWebhook(client, owner, repo, { url: webhookUrl, token: flags.token as string, }); console.log(`✅ Webhook created: ${hook.id}`); }, async help() { console.log(` Gitea CLI — ${client.url} Commands: whoami Show current user repos [--owner ...] [--limit N] List repos create-repo <name> [--private] [--description "..."] ensure-repo <name> [--private] Create if not exists issues <owner/repo> List issues create-issue <owner/repo> <title> [--body "..."] prs <owner/repo> List pull requests runs <owner/repo> List workflow runs add-webhook <owner/repo> <url> [--token "..."] Env: GITEA_URL, GITEA_TOKEN, GITEA_OWNER, GITEA_REPO `); }, }; async function main() { if (!client.token) { console.error("❌ No GITEA_TOKEN found. Set GITEA_TOKEN in environment."); process.exit(1); } const cmd = process.argv[2]; if (!cmd || cmd === "--help" || cmd === "help") { await commands.help([]); return; } const fn = commands[cmd]; if (!fn) { console.error(`Unknown command: ${cmd}`); process.exit(1); } await fn(process.argv.slice(3)); } main().catch((err) => { console.error("Error:", err.message); process.exit(1); });