• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

agentic-dev-library / thumbcode / 21933683492

12 Feb 2026 04:34AM UTC coverage: 27.141%. First build
21933683492

Pull #121

github

web-flow
Merge 20f2805fa into 8afd60302
Pull Request #121: feat: credential validation, project creation, syntax highlighting

388 of 2235 branches covered (17.36%)

Branch coverage included in aggregate %.

0 of 113 new or added lines in 5 files covered. (0.0%)

1038 of 3019 relevant lines covered (34.38%)

7.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/core/src/github/GitHubApiService.ts
1
import { API_URLS } from '@thumbcode/config';
2
import type { Repository } from '@thumbcode/types';
3
import { CredentialService } from '../credentials';
4

5
interface GitHubRepoResponse {
6
  id: number;
7
  name: string;
8
  full_name: string;
9
  owner: { login: string };
10
  private: boolean;
11
  description: string | null;
12
  default_branch: string;
13
  clone_url: string;
14
  stargazers_count: number;
15
  forks_count: number;
16
  language: string | null;
17
  updated_at: string;
18
}
19

20
class GitHubApiServiceClass {
21
  private async getToken(): Promise<string> {
22
    const { secret } = await CredentialService.retrieve('github');
×
23
    if (!secret) {
×
24
      throw new Error('Missing GitHub credential. Connect GitHub first.');
×
25
    }
26
    return secret;
×
27
  }
28

29
  private async request<T>(path: string, init: RequestInit = {}): Promise<T> {
×
30
    const token = await this.getToken();
×
31
    const url = `${API_URLS.github}${path}`;
×
32
    const res = await fetch(url, {
×
33
      ...init,
34
      headers: {
35
        Accept: 'application/vnd.github.v3+json',
36
        Authorization: `Bearer ${token}`,
37
        ...init.headers,
38
      },
39
    });
40

41
    if (!res.ok) {
×
42
      const text = await res.text().catch(() => '');
×
43
      throw new Error(`GitHub API error: ${res.status} ${text}`.trim());
×
44
    }
45

46
    return (await res.json()) as T;
×
47
  }
48

49
  async listRepositories(options?: {
50
    perPage?: number;
51
    sort?: 'updated' | 'created' | 'pushed' | 'full_name';
52
    affiliation?: string;
53
  }): Promise<Repository[]> {
54
    const perPage = options?.perPage ?? 100;
×
55
    const sort = options?.sort ?? 'updated';
×
56
    const affiliation = options?.affiliation ?? 'owner,collaborator,organization_member';
×
57

58
    const repos = await this.request<GitHubRepoResponse[]>(
×
59
      `/user/repos?per_page=${perPage}&sort=${sort}&direction=desc&affiliation=${encodeURIComponent(affiliation)}`
60
    );
61

62
    return repos.map((r) => ({
×
63
      provider: 'github',
64
      owner: r.owner.login,
65
      name: r.name,
66
      fullName: r.full_name,
67
      defaultBranch: r.default_branch,
68
      cloneUrl: r.clone_url,
69
      isPrivate: r.private,
70
      description: r.description ?? undefined,
×
71
      language: r.language ?? undefined,
×
72
      stars: r.stargazers_count,
73
      forks: r.forks_count,
74
      updatedAt: r.updated_at,
75
    }));
76
  }
77

78
  async createRepository(options: {
79
    name: string;
80
    description?: string;
81
    isPrivate?: boolean;
82
  }): Promise<Repository> {
NEW
83
    const repo = await this.request<GitHubRepoResponse>('/user/repos', {
×
84
      method: 'POST',
85
      headers: { 'Content-Type': 'application/json' },
86
      body: JSON.stringify({
87
        name: options.name,
88
        description: options.description || '',
×
89
        private: options.isPrivate ?? true,
×
90
        auto_init: true,
91
      }),
92
    });
93

NEW
94
    return {
×
95
      provider: 'github',
96
      owner: repo.owner.login,
97
      name: repo.name,
98
      fullName: repo.full_name,
99
      defaultBranch: repo.default_branch,
100
      cloneUrl: repo.clone_url,
101
      isPrivate: repo.private,
102
      description: repo.description ?? undefined,
×
103
      language: repo.language ?? undefined,
×
104
      stars: repo.stargazers_count,
105
      forks: repo.forks_count,
106
      updatedAt: repo.updated_at,
107
    };
108
  }
109
}
110

111
export const GitHubApiService = new GitHubApiServiceClass();
×
112

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc