termcode
Version:
Superior terminal AI coding agent with enterprise-grade security, intelligent error recovery, performance monitoring, and plugin system - Advanced Claude Code alternative
81 lines (80 loc) • 2.68 kB
JavaScript
import { spawnSync } from "node:child_process";
import { CFG } from "../config.js";
import { log } from "../util/logging.js";
function safeGitSync(args, cwd) {
try {
const result = spawnSync("git", args, {
cwd,
encoding: "utf8",
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
timeout: 30000 // 30 second timeout
});
if (result.status === 0) {
return result.stdout.trim();
}
return null;
}
catch (error) {
return null;
}
}
export async function createPullRequest(repoPath, branchName, title, body) {
// Get repo info from git remote
const remote = safeGitSync(["config", "--get", "remote.origin.url"], repoPath);
if (!remote) {
throw new Error("No git remote origin found");
}
// Parse GitHub repo from remote URL
const match = remote.match(/github\.com[:/](.+?)(?:\.git)?$/);
if (!match) {
throw new Error("Not a GitHub repo or unsupported remote URL");
}
const [owner, repo] = match[1].split("/");
if (!CFG.GITHUB_TOKEN) {
throw new Error("GITHUB_TOKEN not set in environment");
}
// Create PR via GitHub API
const url = `https://api.github.com/repos/${owner}/${repo}/pulls`;
try {
const response = await fetch(url, {
method: "POST",
headers: {
"Authorization": `token ${CFG.GITHUB_TOKEN}`,
"Accept": "application/vnd.github+json",
"Content-Type": "application/json"
},
body: JSON.stringify({
title,
head: branchName,
base: "main", // Could be configurable
body
})
});
if (!response.ok) {
const error = await response.text();
throw new Error(`GitHub API error (${response.status}): ${error}`);
}
const data = await response.json();
log.info(`✅ Created PR: ${data.html_url}`);
return data.html_url;
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Failed to create PR: ${error.message}`);
}
throw error;
}
}
export function getRepoInfo(repoPath) {
const remote = safeGitSync(["config", "--get", "remote.origin.url"], repoPath);
if (!remote)
return null;
const match = remote.match(/github\.com[:/](.+?)(?:\.git)?$/);
if (!match)
return null;
const [owner, repo] = match[1].split("/");
return { owner, repo };
}
export function getCurrentBranch(repoPath) {
return safeGitSync(["branch", "--show-current"], repoPath);
}