sin-github-issues / src /profile.ts
delqhi's picture
Deploy A2A-SIN-GitHub-Issues with a2a HTTP server fix
5a8fc31 verified
Raw
History Blame Contribute Delete
5.28 kB
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<object>('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<Array<{ number: number; state: string; closed_at: string | null }>>('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 };
}