"use strict"; /** * GitHub API Module * Core functions for interacting with GitHub API */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getAuthHeaders = getAuthHeaders; exports.getUsername = getUsername; exports.listRepos = listRepos; exports.getRepo = getRepo; exports.checkCIStatus = checkCIStatus; exports.getRecentActivity = getRecentActivity; exports.createIssue = createIssue; exports.createRepo = createRepo; exports.searchRepos = searchRepos; exports.createPullRequest = createPullRequest; const GITHUB_API = 'https://api.github.com'; // Cached user info let cachedUser = null; /** * Get auth headers for API requests */ function getAuthHeaders(context) { const headers = { 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'OpenClaw-GitHub-Skill' }; // 1. Check environment variable first if (process.env.GITHUB_TOKEN) { headers['Authorization'] = `token ${process.env.GITHUB_TOKEN}`; return headers; } // 2. Fall back to OpenClaw config const config = context.config?.github || {}; if (config.token) { headers['Authorization'] = `token ${config.token}`; } return headers; } /** * Get GitHub username */ async function getUsername(context) { // 1. Check environment variable first if (process.env.GITHUB_USERNAME) { return process.env.GITHUB_USERNAME; } // 2. Check OpenClaw config const config = context.config?.github || {}; if (config.username) { return config.username; } // 3. Fetch from API if not configured if (!cachedUser) { const response = await fetch(`${GITHUB_API}/user`, { headers: getAuthHeaders(context) }); const data = await response.json(); cachedUser = data.login; } return cachedUser; } /** * List repositories */ async function listRepos(args, context) { const username = await getUsername(context); const { type = 'owner', sort = 'updated', direction = 'desc', limit = 30 } = args; const url = `${GITHUB_API}/users/${username}/repos?type=${type}&sort=${sort}&direction=${direction}&per_page=${limit}`; const response = await fetch(url, { headers: getAuthHeaders(context) }); if (!response.ok) { throw new Error(`GitHub API error: ${response.status}`); } const repos = await response.json(); // Filter by language if specified let filtered = repos; if (args.language) { filtered = repos.filter(r => r.language?.toLowerCase() === args.language.toLowerCase()); } // Limit results filtered = filtered.slice(0, limit); return { total: filtered.length, repos: filtered }; } /** * Get repository details */ async function getRepo(args, context) { const { owner, repo } = args; const url = `${GITHUB_API}/repos/${owner}/${repo}`; const response = await fetch(url, { headers: getAuthHeaders(context) }); if (!response.ok) { throw new Error(`Repo not found: ${owner}/${repo}`); } const data = await response.json(); return { name: data.name, full_name: data.full_name, description: data.description, stars: data.stargazers_count, forks: data.forks_count, watchers: data.watchers_count, language: data.language, open_issues: data.open_issues_count, created: data.created_at, updated: data.updated_at, pushed: data.pushed_at, url: data.html_url, default_branch: data.default_branch, private: data.private }; } /** * Check CI/CD status */ async function checkCIStatus(args, context) { const { owner, repo } = args; // Get recent workflows/runs const runsUrl = `${GITHUB_API}/repos/${owner}/${repo}/actions/runs?per_page=5`; const response = await fetch(runsUrl, { headers: getAuthHeaders(context) }); if (!response.ok) { throw new Error(`Failed to get CI status: ${response.status}`); } const data = await response.json(); const runs = (data.workflow_runs || []).map((run) => ({ name: run.name, status: run.status, conclusion: run.conclusion, branch: run.head_branch, commit: run.head_sha?.substring(0, 7) || '', created: run.created_at, url: run.html_url })); return { repo: `${owner}/${repo}`, runs }; } /** * Get recent activity (commits) */ async function getRecentActivity(args, context) { const username = await getUsername(context); const { repo, limit = 10 } = args; if (!repo) { throw new Error('Repository name required'); } // Get recent commits const commitsUrl = `${GITHUB_API}/repos/${username}/${repo}/commits?per_page=${limit}`; const commitsRes = await fetch(commitsUrl, { headers: getAuthHeaders(context) }); if (!commitsRes.ok) { throw new Error(`Failed to get activity: ${commitsRes.status}`); } const commits = await commitsRes.json(); return { repo: `${username}/${repo}`, commits: commits.map((c) => ({ sha: c.sha.substring(0, 7), message: c.commit.message.split('\n')[0], author: c.commit.author.name, date: c.commit.author.date, url: c.html_url })) }; } /** * Create an issue */ async function createIssue(args, context) { const username = await getUsername(context); const { repo, title, body } = args; if (!title) { throw new Error('Issue title required'); } const url = `${GITHUB_API}/repos/${username}/${repo}/issues`; const response = await fetch(url, { method: 'POST', headers: getAuthHeaders(context), body: JSON.stringify({ title, body: body || '', ...(args.extra || {}) }) }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to create issue: ${error.message || response.status}`); } const issue = await response.json(); return { number: issue.number, title: issue.title, url: issue.html_url, state: issue.state }; } /** * Create a new repository */ async function createRepo(args, context) { const username = await getUsername(context); const { name, description, private: isPrivate = false, auto_init = true } = args; if (!name) { throw new Error('Repository name required'); } const url = `${GITHUB_API}/user/repos`; const response = await fetch(url, { method: 'POST', headers: getAuthHeaders(context), body: JSON.stringify({ name, description: description || '', private: isPrivate, auto_init }) }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to create repo: ${error.message || response.status}`); } const repo = await response.json(); return { name: repo.name, full_name: repo.full_name, description: repo.description, stars: repo.stargazers_count || 0, forks: repo.forks_count || 0, language: repo.language || null, updated: repo.updated_at || '', url: repo.html_url, private: repo.private }; } /** * Search repositories */ async function searchRepos(args, context) { const username = await getUsername(context); const { query, sort = 'updated', limit = 30 } = args; if (!query) { throw new Error('Search query required'); } // Search user's repos const url = `${GITHUB_API}/search/repositories?q=${encodeURIComponent(query)}+user:${username}&sort=${sort}&per_page=${limit}`; const response = await fetch(url, { headers: getAuthHeaders(context) }); if (!response.ok) { throw new Error(`Search failed: ${response.status}`); } const data = await response.json(); return { total: data.total_count, repos: (data.items || []).map((r) => ({ name: r.name, full_name: r.full_name, description: r.description, stars: r.stargazers_count, language: r.language, url: r.html_url, forks: 0, updated: '', private: false })) }; } /** * Create a pull request */ async function createPullRequest(args, context) { const username = await getUsername(context); const { owner, repo, title, body, head, base = 'main' } = args; // Use username if owner not specified const prOwner = owner || username; if (!prOwner || !repo || !title || !head) { throw new Error('owner, repo, title, and head are required'); } const url = `${GITHUB_API}/repos/${prOwner}/${repo}/pulls`; const response = await fetch(url, { method: 'POST', headers: getAuthHeaders(context), body: JSON.stringify({ title, body: body || '', head, base }) }); if (!response.ok) { const error = await response.json(); throw new Error(`Failed to create PR: ${error.message || response.status}`); } const pr = await response.json(); return { number: pr.number, title: pr.title, url: pr.html_url, state: pr.state, head: pr.head.ref, base: pr.base.ref }; } //# sourceMappingURL=api.js.map