import { runCommand, runJsonCommand } from './command.js'; import { recordAuditEvent } from './audit.js'; export async function getProfile() { const profile = await runJsonCommand<{ login: string; id: number; name: string | null; company: string | null; blog: string | null; location: string | null; bio: string | null; twitter_username: string | null; hireable: boolean | null; public_repos: number; followers: number; following: number; html_url: string; }>('gh', ['api', 'user']); return { ok: true, profile }; } export async function updateProfile(input: { name?: string; company?: string; blog?: string; location?: string; bio?: string; twitter_username?: string; hireable?: boolean; }) { const args = ['api', 'user', '--method', 'PATCH']; if (input.name !== undefined) args.push('-f', `name=${input.name}`); if (input.company !== undefined) args.push('-f', `company=${input.company}`); if (input.blog !== undefined) args.push('-f', `blog=${input.blog}`); if (input.location !== undefined) args.push('-f', `location=${input.location}`); if (input.bio !== undefined) args.push('-f', `bio=${input.bio}`); if (input.twitter_username !== undefined) args.push('-f', `twitter_username=${input.twitter_username}`); if (input.hireable !== undefined) args.push('-F', `hireable=${input.hireable}`); const result = await runJsonCommand('gh', args); await recordAuditEvent({ kind: 'profile.update', result }); return { ok: true, profile: result }; } export async function listPinnedRepos() { const query = ` query { user(login: "Delqhi") { pinnedItems(first: 6, types: REPOSITORY) { nodes { ... on Repository { id name description url isFork stargazerCount primaryLanguage { name } } } } } } `.replace(/\s+/g, ' '); const response = await runJsonCommand<{ data: { user: { pinnedItems: { nodes: Array<{ id: string; name: string; description: string | null; url: string; isFork: boolean; stargazerCount: number; primaryLanguage: { name: string } | null }> } } } }>('gh', ['api', 'graphql', '-f', `query=${query}`]); const nodes = response.data?.user?.pinnedItems?.nodes ?? []; return { ok: true, pinned: nodes }; } export async function setPinnedRepos(repoIds?: string[]) { const current = await listPinnedRepos(); const existingIds = new Set(current.pinned.map((r) => r.id)); for (const existingId of existingIds) { try { await runCommand('gh', ['api', 'graphql', '-f', `query=mutation { unpinRepository(input: {repositoryId: "${existingId}"}) { repository { name } } }`], undefined); } catch {} } const desiredIds = repoIds ?? []; for (const repoId of desiredIds) { await runCommand('gh', ['api', 'graphql', '-f', `query=mutation { pinRepository(input: {repositoryId: "${repoId}"}) { repository { name } } }`], undefined); } await recordAuditEvent({ kind: 'profile.pinned_repos.set', result: { repoIds: desiredIds } }); return { ok: true, pinned: desiredIds }; } export async function updateRepoMetadata(input: { repo: string; description?: string; homepage?: string; topics?: string[]; visibility?: 'public' | 'private' }) { const args = ['api', `repos/${input.repo}`, '--method', 'PATCH']; if (input.description !== undefined) args.push('-f', `description=${input.description}`); if (input.homepage !== undefined) args.push('-f', `homepage=${input.homepage}`); if (input.visibility !== undefined) args.push('-f', `visibility=${input.visibility}`); await runCommand('gh', args, undefined); if (input.topics && input.topics.length > 0) { const topicArgs = ['api', `repos/${input.repo}/topics`, '--method', 'PUT', '-H', 'Accept: application/vnd.github+json']; for (const topic of input.topics) { topicArgs.push('-F', `names[]=${topic}`); } await runCommand('gh', topicArgs, undefined); } await recordAuditEvent({ kind: 'repo.metadata.update', result: input }); return { ok: true, repo: input.repo }; } export async function triggerQuickdraw(repo?: string) { const target = repo ?? 'Delqhi/Delqhi'; const issue = await runJsonCommand<{ number: number; html_url: string }>('gh', ['issue', 'create', '--repo', target, '--title', 'Quickdraw profile check', '--body', 'Triggering Quickdraw achievement via issue lifecycle.']); await runCommand('gh', ['issue', 'close', String(issue.number), '--repo', target, '--comment', 'Closed for Quickdraw verification.'], undefined); await recordAuditEvent({ kind: 'achievement.quickdraw.trigger', result: { repo: target, issueNumber: issue.number } }); return { ok: true, repo: target, issueNumber: issue.number, issueUrl: issue.html_url }; } export async function quickdrawStatus() { const issues = await runJsonCommand>('gh', ['issue', 'list', '--repo', 'Delqhi/Delqhi', '--state', 'all', '--limit', '10', '--json', 'number,state,closed_at']); const closed = issues.filter((i) => i.state === 'closed' && i.closed_at).length; return { ok: true, totalClosed: closed, likelyQuickdraw: closed >= 1 }; }