CoolFace
Apppublic

delqhi/sin-github-issues

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
runtime.ts229 linesDownload Raw Back to src
1import { exec, execFile } from 'node:child_process';2import { mkdtemp, rm, writeFile } from 'node:fs/promises';3import { tmpdir } from 'node:os';4import { join } from 'node:path';5import { promisify } from 'node:util';6import { createClient } from '@supabase/supabase-js';7import { commentIssueAsGitHubApp, getGitHubAppRoutingStatus, routeGitHubWebhook } from './github-app-routing.js';8 9const execAsync = promisify(exec);10const execFileAsync = promisify(execFile);11 12export type GitHubAgentAction =13  | { action: 'agent.help' }14  | { action: 'sin.github.health' }15  | { action: 'sin.github.app.routing.status' }16  | { action: 'sin.github.webhook.route'; payload?: unknown; rawBody?: string; routePath?: string; signature256?: string; eventName?: string; deliveryId?: string }17  | { action: 'sin.github.issue.comment.as_app'; repo: string; issueNumber: number; body: string; agentSlug?: string; appId?: number; installationId: number }18  | { action: 'sin.github.project.orchestrate'; prompt: string; contextDir?: string }19  | { action: 'sin.github.issue.manage'; prompt: string; issueNumber?: number }20  | { action: 'sin.github.wiki.sync'; prompt: string; contextDir?: string }21  | { action: 'sin.github.discussion.start'; prompt: string; category?: string }22  | { action: 'sin.github.gist.publish'; prompt: string; isPublic?: boolean }23  | { action: 'sin.github.security.audit'; prompt: string; contextDir?: string }24  | { action: 'sin.github.pr.review'; prNumber: number; contextDir?: string }25  | { action: 'sin.github.issue.pool.enqueue'; repoName: string; issueNumber: number; title: string; body?: string; labels?: string[]; issueUrl?: string; assignedTeam?: string; assignedAgent?: string; status?: string; state?: string; routingStrategy?: string; fanoutPlan?: unknown[] }26  | { action: 'sin.github.ledger.log'; agentName: string; activityTitle: string; details: string };27 28export async function executeGitHubAgentAction(action: GitHubAgentAction): Promise<unknown> {29  switch (action.action) {30    case 'agent.help':31      return {32        ok: true,33        agent: 'sin-github-issues',34        mandate: 'CEO Elite GitHub Operations. Orchestrates Projects, Issues, Wikis, Discussions, Gists, Security, PR Reviews, and public Showcase Ledgers.',35        actions: [36          'sin.github.health',37          'sin.github.app.routing.status',38          'sin.github.webhook.route',39          'sin.github.issue.comment.as_app',40          'sin.github.project.orchestrate',41          'sin.github.issue.manage',42          'sin.github.wiki.sync',43          'sin.github.discussion.start',44          'sin.github.gist.publish',45          'sin.github.security.audit',46          'sin.github.pr.review',47          'sin.github.issue.pool.enqueue',48          'sin.github.ledger.log'49        ],50      };51 52    case 'sin.github.health':53      return {54        ok: true,55        agent: 'sin-github-issues',56        primaryModel: 'openai/gpt-5.4',57        fallbackModel: 'opencode/minimax-m2.5-free',58        team: 'Team - Coding',59        status: 'Elite 2026 GitHub Operations Architect Online',60        capabilities: ['projects', 'wikis', 'discussions', 'gists', 'security', 'prs', 'issues', 'ledger', 'github-app-routing'],61        githubAppRouting: await getGitHubAppRoutingStatus(),62      };63 64    case 'sin.github.app.routing.status':65      return await getGitHubAppRoutingStatus();66 67    case 'sin.github.webhook.route':68      return await routeGitHubWebhook(action);69 70    case 'sin.github.issue.comment.as_app':71      return await commentIssueAsGitHubApp(action);72 73    case 'sin.github.project.orchestrate':74      return await executeOpenCode(75        `Use the GitHub CLI ('gh project create/link/item-add') to orchestrate the following project board requirements: ${action.prompt}. Ensure the board is linked to the repository and items are properly assigned.`,76        action.contextDir77      );78 79    case 'sin.github.issue.manage':80      return await executeOpenCode(81        `Manage GitHub issues based on: ${action.prompt}. ${action.issueNumber ? `Target issue: #${action.issueNumber}` : 'Create a new Epic/Task.'} Ensure proper labeling, assignment, and milestone linking.`82      );83 84    case 'sin.github.wiki.sync':85      return await executeOpenCode(86        `Synchronize the repository's Wiki with the following documentation update: ${action.prompt}. Generate standard Markdown and push it to the wiki repository (.wiki.git).`,87        action.contextDir88      );89 90    case 'sin.github.discussion.start':91      return await executeOpenCode(92        `Start or manage a GitHub Discussion to keep issues clean. Requirements: ${action.prompt}. Category: ${action.category || 'General'}.`93      );94 95    case 'sin.github.gist.publish':96      return await executeOpenCode(97        `Create a GitHub Gist (public: ${action.isPublic ?? false}) for the following payload (long log, snippet, or config): ${action.prompt}. Return the Gist URL for embedding in an issue or PR.`98      );99 100    case 'sin.github.security.audit':101      return await executeOpenCode(102        `Audit the repository for security vulnerabilities (Dependabot/CodeQL). Generate or update '.github/dependabot.yml' and review any active alerts based on: ${action.prompt}.`,103        action.contextDir104      );105 106    case 'sin.github.pr.review':107      return await executeOpenCode(108        `Perform a rigorous Code Review on Pull Request #${action.prNumber}. Check for 2026 architectural compliance, security vulnerabilities, performance regressions, and test coverage. If it passes 100%, approve it ('gh pr review --approve') and merge it ('gh pr merge --auto').`,109        action.contextDir110      );111 112    case 'sin.github.issue.pool.enqueue':113      return await enqueueIssuePoolItem(action);114 115    case 'sin.github.ledger.log':116      return await publishLedgerLog(action.agentName, action.activityTitle, action.details);117  }118}119 120async function executeOpenCode(prompt: string, dir?: string) {121  await execAsync('python3 scripts/hf_pull_script.py').catch(() => console.warn('Warning: hf_pull_script failed. Proceeding with cached credentials.'));122  const options = dir ? { cwd: dir } : {};123 124  try {125    const { stdout, stderr } = await execFileAsync('opencode', ['run', prompt, '--model', 'openai/gpt-5.4'], options);126    return {127      ok: true,128      expertAnalysis: stdout,129      warnings: stderr || undefined,130    };131  } catch (error: any) {132    throw new Error(`GitHub Operations Execution Failed: ${error.message}`);133  }134}135 136async function publishLedgerLog(agentName: string, activityTitle: string, details: string) {137  const title = `[${agentName}] ${activityTitle}`;138  const body = [139    `# ${activityTitle}`,140    '',141    `- Agent: ${agentName}`,142    `- Published: ${new Date().toISOString()}`,143    '',144    '## Details',145    details,146  ].join('\n');147  const tempDir = await mkdtemp(join(tmpdir(), 'sin-github-ledger-'));148  const bodyPath = join(tempDir, 'ledger-body.md');149 150  try {151    await writeFile(bodyPath, body, 'utf8');152    const { stdout, stderr } = await execFileAsync('gh', [153      'issue',154      'create',155      '-R',156      'Delqhi/OpenSIN-Ledger',157      '--title',158      title,159      '--body-file',160      bodyPath,161    ]);162    return {163      ok: true,164      repo: 'Delqhi/OpenSIN-Ledger',165      title,166      url: stdout.trim(),167      warnings: stderr || undefined,168    };169  } catch (error: any) {170    throw new Error(`GitHub Ledger Publish Failed: ${error.message}`);171  } finally {172    await rm(tempDir, { recursive: true, force: true }).catch(() => undefined);173  }174}175 176async function enqueueIssuePoolItem(action: Extract<GitHubAgentAction, { action: 'sin.github.issue.pool.enqueue' }>) {177  const supabaseUrl = (process.env.SUPABASE_URL || process.env.SIN_SUPABASE_URL || '').trim();178  const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SIN_SUPABASE_SERVICE_ROLE_KEY || '').trim();179 180  if (!supabaseUrl || !serviceRoleKey) {181    throw new Error('sin_supabase_config_missing: set SUPABASE_URL/SUPABASE_SERVICE_ROLE_KEY or SIN_SUPABASE_URL/SIN_SUPABASE_SERVICE_ROLE_KEY before enqueueing issue-pool items');182  }183 184  const supabase = createClient(supabaseUrl, serviceRoleKey, {185    auth: { persistSession: false, autoRefreshToken: false },186  });187 188  const payload = {189    issue_number: action.issueNumber,190    repo_name: action.repoName,191    title: action.title,192    body: action.body || null,193    labels: action.labels || [],194    issue_url: action.issueUrl || null,195    state: action.state || 'open',196    assigned_team: action.assignedTeam || 'team-coding',197    assigned_agent: action.assignedAgent || null,198    status: action.status || 'open',199    routing_strategy: action.routingStrategy || 'single-dispatch',200    fanout_plan: action.fanoutPlan || [],201    updated_at: new Date().toISOString(),202  };203 204  let { data, error } = await supabase.from('sin_issues_pool').insert(payload).select('*').single();205  if (error && /column/i.test(error.message)) {206    const fallbackPayload = {207      issue_number: action.issueNumber,208      repo_name: action.repoName,209      title: action.title,210      body: action.body || null,211      state: action.state || 'open',212      assigned_team: action.assignedTeam || 'team-coding',213      assigned_agent: action.assignedAgent || null,214      status: action.status || 'pending',215      updated_at: new Date().toISOString(),216    };217    ({ data, error } = await supabase.from('sin_issues_pool').insert(fallbackPayload).select('*').single());218  }219  if (error) {220    throw new Error(`sin_issue_pool_enqueue_failed: ${error.message}`);221  }222 223  return {224    ok: true,225    table: 'sin_issues_pool',226    item: data,227  };228}229