/** * Provider factory — auto-detects GitHub vs GitLab vs Gitea from git remote. */ import type { IssueProvider } from "./provider.js"; import { GitLabProvider } from "./gitlab.js"; import { GitHubProvider } from "./github.js"; import { GiteaProvider } from "./gitea.js"; import { resolveRepoPath } from "../projects.js"; import { runCommand } from "../run-command.js"; export type ProviderOptions = { provider?: "gitlab" | "github" | "gitea"; repo?: string; repoPath?: string; }; export type ProviderWithType = { provider: IssueProvider; type: "github" | "gitlab" | "gitea"; }; async function detectProvider(repoPath: string): Promise<"gitlab" | "github" | "gitea"> { try { const result = await runCommand(["git", "remote", "get-url", "origin"], { timeoutMs: 5_000, cwd: repoPath }); const remote = result.stdout.trim(); if (remote.includes("github.com")) { return "github"; } else if (remote.includes("192.168.1.150:3000")) { return "gitea"; } else { return "gitlab"; } } catch { return "gitlab"; } } export async function createProvider(opts: ProviderOptions): Promise { const repoPath = opts.repoPath ?? (opts.repo ? resolveRepoPath(opts.repo) : null); if (!repoPath) throw new Error("Either repoPath or repo must be provided"); const type = opts.provider ?? await detectProvider(repoPath); let provider: IssueProvider; switch (type) { case "github": provider = new GitHubProvider({ repoPath }); break; case "gitea": provider = new GiteaProvider({ repoPath }); break; case "gitlab": default: provider = new GitLabProvider({ repoPath }); break; } return { provider, type }; }