Add harness app: agent orchestrator with cluster deployment
- Next.js app for orchestrating coding agent benchmarks (Claude Code, Codex, OpenCode) - Dockerfile installs git, gh CLI, and agent CLIs for headless execution - K8s deployment with workspace volume, sealed credentials for Claude + OpenCode - Traefik IngressRoute at harness.coreworlds.io with internal-only middleware + TLS - CI pipeline path filter for harness builds - Fix OpenCode runtime flags (subcommand-based headless mode)
This commit is contained in:
100
apps/harness/src/lib/repo-search.ts
Normal file
100
apps/harness/src/lib/repo-search.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { getCredentialsByProvider } from "./credentials";
|
||||
|
||||
export interface RepoResult {
|
||||
provider: "github" | "gitlab";
|
||||
fullName: string;
|
||||
url: string;
|
||||
description: string;
|
||||
defaultBranch: string;
|
||||
private: boolean;
|
||||
}
|
||||
|
||||
export async function searchRepos(query: string): Promise<RepoResult[]> {
|
||||
if (!query || query.length < 2) return [];
|
||||
|
||||
const results = await Promise.allSettled([
|
||||
searchGitHub(query),
|
||||
searchGitLab(query),
|
||||
]);
|
||||
|
||||
return results.flatMap(r => r.status === "fulfilled" ? r.value : []);
|
||||
}
|
||||
|
||||
async function searchGitHub(query: string): Promise<RepoResult[]> {
|
||||
const creds = getCredentialsByProvider("github");
|
||||
if (creds.length === 0) return [];
|
||||
|
||||
const results: RepoResult[] = [];
|
||||
|
||||
for (const cred of creds) {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&per_page=10&sort=updated`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${cred.token}`,
|
||||
Accept: "application/vnd.github+json",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) continue;
|
||||
|
||||
const data = await res.json();
|
||||
for (const repo of data.items || []) {
|
||||
results.push({
|
||||
provider: "github",
|
||||
fullName: repo.full_name,
|
||||
url: repo.html_url,
|
||||
description: repo.description || "",
|
||||
defaultBranch: repo.default_branch || "main",
|
||||
private: repo.private,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// skip failed credential
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async function searchGitLab(query: string): Promise<RepoResult[]> {
|
||||
const creds = getCredentialsByProvider("gitlab");
|
||||
if (creds.length === 0) return [];
|
||||
|
||||
const results: RepoResult[] = [];
|
||||
|
||||
for (const cred of creds) {
|
||||
const baseUrl = cred.baseUrl || "https://gitlab.com";
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${baseUrl}/api/v4/projects?search=${encodeURIComponent(query)}&per_page=10&order_by=updated_at&membership=true`,
|
||||
{
|
||||
headers: {
|
||||
"PRIVATE-TOKEN": cred.token,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) continue;
|
||||
|
||||
const data = await res.json();
|
||||
for (const project of data) {
|
||||
results.push({
|
||||
provider: "gitlab",
|
||||
fullName: project.path_with_namespace,
|
||||
url: project.web_url,
|
||||
description: project.description || "",
|
||||
defaultBranch: project.default_branch || "main",
|
||||
private: project.visibility === "private",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// skip failed credential
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
Reference in New Issue
Block a user