@chat-adapter/github 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vercel, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # @chat-adapter/github
2
+
3
+ GitHub adapter for the [chat](https://github.com/vercel-labs/chat) SDK. Enables bots to respond to @mentions in GitHub PR comment threads.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install chat @chat-adapter/github
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { Chat } from "chat";
15
+ import { createGitHubAdapter } from "@chat-adapter/github";
16
+ import { MemoryState } from "@chat-adapter/state-memory";
17
+
18
+ const chat = new Chat({
19
+ userName: "my-bot",
20
+ adapters: {
21
+ github: createGitHubAdapter({
22
+ token: process.env.GITHUB_TOKEN!,
23
+ webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
24
+ userName: "my-bot",
25
+ logger: console,
26
+ }),
27
+ },
28
+ state: new MemoryState(),
29
+ logger: "info",
30
+ });
31
+
32
+ // Handle @mentions in PR comments
33
+ chat.onNewMention(async (thread, message) => {
34
+ await thread.post("Hello from GitHub!");
35
+ });
36
+ ```
37
+
38
+ ## Configuration
39
+
40
+ | Option | Required | Description |
41
+ | ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42
+ | `token` | Yes\* | [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) with `repo` scope |
43
+ | `appId` | Yes\* | [GitHub App](https://docs.github.com/en/apps/creating-github-apps) ID |
44
+ | `privateKey` | For Apps | GitHub App private key (PEM format) |
45
+ | `installationId` | No | Installation ID (omit for multi-tenant) |
46
+ | `webhookSecret` | Yes | [Webhook secret](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries) for signature verification |
47
+ | `userName` | Yes | Bot username for @mention detection |
48
+ | `botUserId` | No | Bot's numeric user ID (auto-detected if not provided) |
49
+
50
+ \*Either `token` or `appId`/`privateKey` is required.
51
+
52
+ ## Environment Variables
53
+
54
+ ```bash
55
+ # Personal Access Token auth
56
+ GITHUB_TOKEN=ghp_xxxxxxxxxxxx
57
+
58
+ # OR GitHub App auth
59
+ GITHUB_APP_ID=123456
60
+ GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----..."
61
+ GITHUB_INSTALLATION_ID=12345678 # Optional for multi-tenant apps
62
+
63
+ # Webhook secret (required)
64
+ GITHUB_WEBHOOK_SECRET=your-webhook-secret
65
+ ```
66
+
67
+ ## GitHub Setup
68
+
69
+ ### Option A: Personal Access Token (PAT)
70
+
71
+ Best for personal projects, testing, or simple single-repo bots.
72
+
73
+ 1. Go to [Settings → Developer settings → Personal access tokens](https://github.com/settings/tokens)
74
+ 2. Create a new token with `repo` scope
75
+ 3. Set `GITHUB_TOKEN` environment variable
76
+
77
+ ### Option B: GitHub App (Recommended)
78
+
79
+ Better rate limits, security, and supports multiple installations.
80
+
81
+ #### 1. Create the App
82
+
83
+ 1. Go to [Settings → Developer settings → GitHub Apps → New GitHub App](https://github.com/settings/apps/new)
84
+ 2. Fill in:
85
+ - **Name**: Your bot's name
86
+ - **Homepage URL**: Your app's website
87
+ - **Webhook URL**: `https://your-domain.com/api/webhooks/github`
88
+ - **Webhook secret**: Generate a secure secret
89
+ 3. Set **Permissions**:
90
+ - Repository -> Issues: Read & write
91
+ - Repository -> Pull requests: Read & write
92
+ - Repository -> Metadata: Read-only
93
+ 4. Subscribe to **events**:
94
+ - Issue comment
95
+ - Pull request review comment
96
+ 5. Under "Where can this GitHub App be installed?":
97
+ - **Only on this account** - For private/testing apps
98
+ - **Any account** - For public apps others can install
99
+ 6. Click **"Create GitHub App"**
100
+ 7. Note your **App ID** from the app settings page (shown at the top)
101
+ 8. Scroll down and click **"Generate a private key"** - save the downloaded `.pem` file
102
+
103
+ #### 2. Install the App
104
+
105
+ 1. After creating the app, go to your app's settings page
106
+ 2. Click **"Install App"** in the left sidebar
107
+ 3. Click **"Install"** next to your organization or account
108
+ 4. Choose which repositories to grant access:
109
+ - **All repositories** - App can access all current and future repos
110
+ - **Only select repositories** - Pick specific repos (recommended for testing)
111
+ 5. Click **"Install"**
112
+ 6. Note the **Installation ID** from the URL after installation:
113
+ ```
114
+ https://github.com/settings/installations/12345678
115
+ ^^^^^^^^
116
+ This is your Installation ID
117
+ ```
118
+
119
+ #### 3. Configure the Adapter
120
+
121
+ **Single-tenant (fixed installation):**
122
+
123
+ ```typescript
124
+ createGitHubAdapter({
125
+ appId: process.env.GITHUB_APP_ID!,
126
+ privateKey: process.env.GITHUB_PRIVATE_KEY!,
127
+ installationId: parseInt(process.env.GITHUB_INSTALLATION_ID!),
128
+ webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
129
+ userName: "my-bot[bot]",
130
+ logger: console,
131
+ });
132
+ ```
133
+
134
+ **Multi-tenant (public app anyone can install):**
135
+
136
+ Simply omit `installationId`. The adapter automatically extracts it from webhooks and caches API clients per-installation:
137
+
138
+ ```typescript
139
+ import { Chat } from "chat";
140
+ import { createGitHubAdapter } from "@chat-adapter/github";
141
+ import { RedisState } from "@chat-adapter/state-redis";
142
+
143
+ const chat = new Chat({
144
+ userName: "my-bot[bot]",
145
+ adapters: {
146
+ github: createGitHubAdapter({
147
+ appId: process.env.GITHUB_APP_ID!,
148
+ privateKey: process.env.GITHUB_PRIVATE_KEY!,
149
+ // No installationId - handled automatically!
150
+ webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
151
+ userName: "my-bot[bot]",
152
+ logger: console,
153
+ }),
154
+ },
155
+ // Use Redis to persist installation mappings
156
+ state: new RedisState({ url: process.env.REDIS_URL! }),
157
+ logger: "info",
158
+ });
159
+ ```
160
+
161
+ ### Webhook Setup
162
+
163
+ See the [GitHub Webhooks documentation](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks) for detailed instructions.
164
+
165
+ **For repository/org webhooks:**
166
+
167
+ 1. Go to repository/org **Settings → Webhooks → Add webhook**
168
+ 2. Set **Payload URL** to `https://your-domain.com/api/webhooks/github`
169
+ 3. Set **Content type** to `application/json` (**required** - the default `application/x-www-form-urlencoded` will not work)
170
+ 4. Set **Secret** to match your `webhookSecret`
171
+ 5. Select events:
172
+ - [Issue comments](https://docs.github.com/en/webhooks/webhook-events-and-payloads#issue_comment) (PR-level)
173
+ - [Pull request review comments](https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request_review_comment) (line-specific)
174
+
175
+ **For GitHub Apps:** Webhooks are configured during app creation. Make sure to select `application/json` as the content type.
176
+
177
+ ## Features
178
+
179
+ - Message posting and editing
180
+ - Message deletion
181
+ - [Reaction handling](https://docs.github.com/en/rest/reactions) (add/remove)
182
+ - PR-level comments (Conversation tab)
183
+ - Review comment threads (Files Changed tab - line-specific)
184
+ - Cards (rendered as [GitHub Flavored Markdown](https://github.github.com/gfm/))
185
+ - Multi-tenant support (automatic installation ID handling)
186
+
187
+ ## Thread Model
188
+
189
+ GitHub has two types of comment threads:
190
+
191
+ | Type | Tab | API | Thread ID Format |
192
+ | --------------- | ------------- | -------------------------------------------------------------------- | ------------------------------------------------- |
193
+ | PR-level | Conversation | [Issue Comments](https://docs.github.com/en/rest/issues/comments) | `github:{owner}/{repo}:{prNumber}` |
194
+ | Review comments | Files Changed | [PR Review Comments](https://docs.github.com/en/rest/pulls/comments) | `github:{owner}/{repo}:{prNumber}:rc:{commentId}` |
195
+
196
+ Example thread IDs:
197
+
198
+ - `github:acme/app:123` (PR-level)
199
+ - `github:acme/app:123:rc:456789` (line-specific review comment)
200
+
201
+ ## Reactions
202
+
203
+ Supports [GitHub's reaction emoji](https://docs.github.com/en/rest/reactions/reactions#about-reactions):
204
+
205
+ | SDK Emoji | GitHub Reaction |
206
+ | ------------- | --------------- |
207
+ | `thumbs_up` | 👍 (+1) |
208
+ | `thumbs_down` | 👎 (-1) |
209
+ | `laugh` | 😄 |
210
+ | `confused` | 😕 |
211
+ | `heart` | ❤️ |
212
+ | `hooray` | 🎉 |
213
+ | `rocket` | 🚀 |
214
+ | `eyes` | 👀 |
215
+
216
+ ## Limitations
217
+
218
+ - **No typing indicators** - GitHub doesn't support typing indicators
219
+ - **No streaming** - Messages posted in full (editing supported for updates)
220
+ - **No DMs** - GitHub doesn't have direct messages
221
+ - **No modals** - GitHub doesn't support interactive modals
222
+ - **Action buttons** - Rendered as text; use link buttons for clickable actions
223
+
224
+ ## Troubleshooting
225
+
226
+ ### "Invalid signature" error
227
+
228
+ - Verify `GITHUB_WEBHOOK_SECRET` matches your webhook configuration
229
+ - Ensure the request body isn't being modified before verification
230
+
231
+ ### "Invalid JSON" error
232
+
233
+ - Change webhook **Content type** to `application/json` (GitHub defaults to `application/x-www-form-urlencoded` which doesn't work)
234
+
235
+ ### Bot not responding to mentions
236
+
237
+ - Verify webhook events are configured (issue_comment, pull_request_review_comment)
238
+ - Check that the webhook URL is correct and accessible
239
+ - Ensure the bot has been installed on the repository
240
+ - Verify the `userName` config matches your bot's GitHub username
241
+
242
+ ### "Installation ID required" error
243
+
244
+ - This occurs when making API calls outside webhook context in multi-tenant mode
245
+ - Ensure you're using a persistent state adapter (Redis) to store installation mappings
246
+ - The first interaction must come from a webhook to establish the mapping
247
+
248
+ ### Rate limiting
249
+
250
+ - [PATs have lower rate limits](https://docs.github.com/en/rest/overview/rate-limits-for-the-rest-api) than GitHub Apps
251
+ - Consider switching to a GitHub App for production use
252
+
253
+ ## License
254
+
255
+ MIT
@@ -0,0 +1,377 @@
1
+ import { Logger, Adapter, ChatInstance, WebhookOptions, AdapterPostableMessage, RawMessage, EmojiValue, FetchOptions, FetchResult, ThreadInfo, Message, FormattedContent } from 'chat';
2
+
3
+ /**
4
+ * Type definitions for the GitHub adapter.
5
+ */
6
+
7
+ /**
8
+ * Base configuration options shared by all auth methods.
9
+ */
10
+ interface GitHubAdapterBaseConfig {
11
+ /** Logger instance for error reporting */
12
+ logger: Logger;
13
+ /**
14
+ * Webhook secret for HMAC-SHA256 verification.
15
+ * Set this in your GitHub webhook settings.
16
+ */
17
+ webhookSecret: string;
18
+ /**
19
+ * Bot username (e.g., "my-bot" or "my-bot[bot]" for GitHub Apps).
20
+ * Used for @-mention detection.
21
+ */
22
+ userName: string;
23
+ /**
24
+ * Bot's GitHub user ID (numeric).
25
+ * Used for self-message detection. If not provided, will be fetched on first API call.
26
+ */
27
+ botUserId?: number;
28
+ }
29
+ /**
30
+ * Configuration using a Personal Access Token (PAT).
31
+ * Simpler setup, suitable for personal bots or testing.
32
+ */
33
+ interface GitHubAdapterPATConfig extends GitHubAdapterBaseConfig {
34
+ /** Personal Access Token with appropriate scopes (repo, write:discussion) */
35
+ token: string;
36
+ appId?: never;
37
+ privateKey?: never;
38
+ installationId?: never;
39
+ }
40
+ /**
41
+ * Configuration using a GitHub App with a fixed installation.
42
+ * Use this when your bot is only installed on a single org/repo.
43
+ */
44
+ interface GitHubAdapterAppConfig extends GitHubAdapterBaseConfig {
45
+ /** GitHub App ID */
46
+ appId: string;
47
+ /** GitHub App private key (PEM format) */
48
+ privateKey: string;
49
+ /** Installation ID for the app (for single-tenant apps) */
50
+ installationId: number;
51
+ token?: never;
52
+ }
53
+ /**
54
+ * Configuration using a GitHub App for multi-tenant (public) apps.
55
+ * The installation ID is automatically extracted from each webhook payload.
56
+ * Use this when your bot can be installed by anyone.
57
+ */
58
+ interface GitHubAdapterMultiTenantAppConfig extends GitHubAdapterBaseConfig {
59
+ /** GitHub App ID */
60
+ appId: string;
61
+ /** GitHub App private key (PEM format) */
62
+ privateKey: string;
63
+ /** Omit installationId to enable multi-tenant mode */
64
+ installationId?: never;
65
+ token?: never;
66
+ }
67
+ /**
68
+ * GitHub adapter configuration - PAT, single-tenant App, or multi-tenant App.
69
+ */
70
+ type GitHubAdapterConfig = GitHubAdapterPATConfig | GitHubAdapterAppConfig | GitHubAdapterMultiTenantAppConfig;
71
+ /**
72
+ * Decoded thread ID for GitHub.
73
+ *
74
+ * Thread types:
75
+ * - PR-level: Comments in the "Conversation" tab (issue_comment API)
76
+ * - Review comment: Line-specific comments in "Files changed" tab (pull request review comment API)
77
+ */
78
+ interface GitHubThreadId {
79
+ /** Repository owner (user or organization) */
80
+ owner: string;
81
+ /** Repository name */
82
+ repo: string;
83
+ /** Pull request number */
84
+ prNumber: number;
85
+ /**
86
+ * Root review comment ID for line-specific threads.
87
+ * If present, this is a review comment thread.
88
+ * If absent, this is a PR-level (issue comment) thread.
89
+ */
90
+ reviewCommentId?: number;
91
+ }
92
+ /**
93
+ * GitHub user object (simplified).
94
+ */
95
+ interface GitHubUser {
96
+ id: number;
97
+ login: string;
98
+ avatar_url?: string;
99
+ type: "User" | "Bot" | "Organization";
100
+ }
101
+ /**
102
+ * GitHub repository object (simplified).
103
+ */
104
+ interface GitHubRepository {
105
+ id: number;
106
+ name: string;
107
+ full_name: string;
108
+ owner: GitHubUser;
109
+ }
110
+ /**
111
+ * GitHub issue comment (PR-level comment in Conversation tab).
112
+ */
113
+ interface GitHubIssueComment {
114
+ id: number;
115
+ body: string;
116
+ user: GitHubUser;
117
+ created_at: string;
118
+ updated_at: string;
119
+ html_url: string;
120
+ /** Reactions summary */
121
+ reactions?: {
122
+ url: string;
123
+ total_count: number;
124
+ "+1": number;
125
+ "-1": number;
126
+ laugh: number;
127
+ hooray: number;
128
+ confused: number;
129
+ heart: number;
130
+ rocket: number;
131
+ eyes: number;
132
+ };
133
+ }
134
+ /**
135
+ * GitHub pull request review comment (line-specific comment in Files Changed tab).
136
+ */
137
+ interface GitHubReviewComment {
138
+ id: number;
139
+ body: string;
140
+ user: GitHubUser;
141
+ created_at: string;
142
+ updated_at: string;
143
+ html_url: string;
144
+ /** The commit SHA the comment is associated with */
145
+ commit_id: string;
146
+ /** The original commit SHA (for outdated comments) */
147
+ original_commit_id: string;
148
+ /** The diff hunk the comment applies to */
149
+ diff_hunk: string;
150
+ /** Path to the file being commented on */
151
+ path: string;
152
+ /** Line number in the diff */
153
+ line?: number;
154
+ /** Original line number */
155
+ original_line?: number;
156
+ /** Side of the diff (LEFT or RIGHT) */
157
+ side?: "LEFT" | "RIGHT";
158
+ /** Start line for multi-line comments */
159
+ start_line?: number | null;
160
+ /** Start side for multi-line comments */
161
+ start_side?: "LEFT" | "RIGHT" | null;
162
+ /**
163
+ * The ID of the comment this is a reply to.
164
+ * If present, this is a reply in an existing thread.
165
+ * If absent, this is the root of a new thread.
166
+ */
167
+ in_reply_to_id?: number;
168
+ /** Reactions summary */
169
+ reactions?: GitHubIssueComment["reactions"];
170
+ }
171
+ /**
172
+ * Platform-specific raw message type for GitHub.
173
+ * Can be either an issue comment or a review comment.
174
+ */
175
+ type GitHubRawMessage = {
176
+ type: "issue_comment";
177
+ comment: GitHubIssueComment;
178
+ repository: GitHubRepository;
179
+ prNumber: number;
180
+ } | {
181
+ type: "review_comment";
182
+ comment: GitHubReviewComment;
183
+ repository: GitHubRepository;
184
+ prNumber: number;
185
+ };
186
+
187
+ /**
188
+ * GitHub adapter for chat SDK.
189
+ *
190
+ * Supports both PR-level comments (Conversation tab) and review comment threads
191
+ * (Files Changed tab - line-specific).
192
+ *
193
+ * @example Single-tenant (your own org)
194
+ * ```typescript
195
+ * import { Chat } from "chat";
196
+ * import { GitHubAdapter } from "@chat-adapter/github";
197
+ * import { MemoryState } from "@chat-adapter/state-memory";
198
+ *
199
+ * const chat = new Chat({
200
+ * userName: "my-bot",
201
+ * adapters: {
202
+ * github: new GitHubAdapter({
203
+ * token: process.env.GITHUB_TOKEN!,
204
+ * webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
205
+ * userName: "my-bot",
206
+ * logger: console,
207
+ * }),
208
+ * },
209
+ * state: new MemoryState(),
210
+ * logger: "info",
211
+ * });
212
+ * ```
213
+ *
214
+ * @example Multi-tenant (public app anyone can install)
215
+ * ```typescript
216
+ * const chat = new Chat({
217
+ * userName: "my-bot[bot]",
218
+ * adapters: {
219
+ * github: new GitHubAdapter({
220
+ * appId: process.env.GITHUB_APP_ID!,
221
+ * privateKey: process.env.GITHUB_PRIVATE_KEY!,
222
+ * // No installationId - automatically extracted from webhooks
223
+ * webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
224
+ * userName: "my-bot[bot]",
225
+ * logger: console,
226
+ * }),
227
+ * },
228
+ * state: new MemoryState(),
229
+ * logger: "info",
230
+ * });
231
+ * ```
232
+ */
233
+ declare class GitHubAdapter implements Adapter<GitHubThreadId, GitHubRawMessage> {
234
+ readonly name = "github";
235
+ readonly userName: string;
236
+ private octokit;
237
+ private appCredentials;
238
+ private installationClients;
239
+ private webhookSecret;
240
+ private chat;
241
+ private logger;
242
+ private _botUserId;
243
+ private formatConverter;
244
+ /** Bot user ID (numeric) used for self-message detection */
245
+ get botUserId(): string | undefined;
246
+ /** Whether this adapter is in multi-tenant mode (no fixed installation ID) */
247
+ get isMultiTenant(): boolean;
248
+ constructor(config: GitHubAdapterConfig);
249
+ /**
250
+ * Get or create an Octokit instance for a specific installation.
251
+ * For single-tenant mode, returns the single instance.
252
+ * For multi-tenant mode, creates/caches instances per installation.
253
+ */
254
+ private getOctokit;
255
+ initialize(chat: ChatInstance): Promise<void>;
256
+ /**
257
+ * Get the state key for storing installation ID for a repository.
258
+ */
259
+ private getInstallationKey;
260
+ /**
261
+ * Store the installation ID for a repository (for multi-tenant mode).
262
+ */
263
+ private storeInstallationId;
264
+ /**
265
+ * Get the installation ID for a repository (for multi-tenant mode).
266
+ */
267
+ private getInstallationId;
268
+ /**
269
+ * Handle incoming webhook from GitHub.
270
+ */
271
+ handleWebhook(request: Request, options?: WebhookOptions): Promise<Response>;
272
+ /**
273
+ * Verify GitHub webhook signature using HMAC-SHA256.
274
+ */
275
+ private verifySignature;
276
+ /**
277
+ * Handle issue_comment webhook (PR-level comments in Conversation tab).
278
+ */
279
+ private handleIssueComment;
280
+ /**
281
+ * Handle pull_request_review_comment webhook (line-specific comments).
282
+ */
283
+ private handleReviewComment;
284
+ /**
285
+ * Parse an issue comment into a normalized Message.
286
+ */
287
+ private parseIssueComment;
288
+ /**
289
+ * Parse a review comment into a normalized Message.
290
+ */
291
+ private parseReviewComment;
292
+ /**
293
+ * Parse a GitHub user into an Author.
294
+ */
295
+ private parseAuthor;
296
+ /**
297
+ * Get the Octokit client for a specific thread.
298
+ * In multi-tenant mode, looks up the installation ID from state.
299
+ */
300
+ private getOctokitForThread;
301
+ /**
302
+ * Post a message to a thread.
303
+ */
304
+ postMessage(threadId: string, message: AdapterPostableMessage): Promise<RawMessage<GitHubRawMessage>>;
305
+ /**
306
+ * Edit an existing message.
307
+ */
308
+ editMessage(threadId: string, messageId: string, message: AdapterPostableMessage): Promise<RawMessage<GitHubRawMessage>>;
309
+ /**
310
+ * Delete a message.
311
+ */
312
+ deleteMessage(threadId: string, messageId: string): Promise<void>;
313
+ /**
314
+ * Add a reaction to a message.
315
+ */
316
+ addReaction(threadId: string, messageId: string, emoji: EmojiValue | string): Promise<void>;
317
+ /**
318
+ * Remove a reaction from a message.
319
+ */
320
+ removeReaction(threadId: string, messageId: string, emoji: EmojiValue | string): Promise<void>;
321
+ /**
322
+ * Convert SDK emoji to GitHub reaction content.
323
+ */
324
+ private emojiToGitHubReaction;
325
+ /**
326
+ * Show typing indicator (no-op for GitHub).
327
+ */
328
+ startTyping(_threadId: string): Promise<void>;
329
+ /**
330
+ * Fetch messages from a thread.
331
+ */
332
+ fetchMessages(threadId: string, options?: FetchOptions): Promise<FetchResult<GitHubRawMessage>>;
333
+ /**
334
+ * Fetch thread metadata.
335
+ */
336
+ fetchThread(threadId: string): Promise<ThreadInfo>;
337
+ /**
338
+ * Encode platform data into a thread ID string.
339
+ *
340
+ * Thread ID formats:
341
+ * - PR-level: `github:{owner}/{repo}:{prNumber}`
342
+ * - Review comment: `github:{owner}/{repo}:{prNumber}:rc:{reviewCommentId}`
343
+ */
344
+ encodeThreadId(platformData: GitHubThreadId): string;
345
+ /**
346
+ * Decode thread ID string back to platform data.
347
+ */
348
+ decodeThreadId(threadId: string): GitHubThreadId;
349
+ /**
350
+ * Parse a raw message into normalized format.
351
+ */
352
+ parseMessage(raw: GitHubRawMessage): Message<GitHubRawMessage>;
353
+ /**
354
+ * Render formatted content to GitHub markdown.
355
+ */
356
+ renderFormatted(content: FormattedContent): string;
357
+ }
358
+ /**
359
+ * Create a new GitHub adapter instance.
360
+ *
361
+ * @example
362
+ * ```typescript
363
+ * const chat = new Chat({
364
+ * adapters: {
365
+ * github: createGitHubAdapter({
366
+ * token: process.env.GITHUB_TOKEN!,
367
+ * webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
368
+ * userName: "my-bot",
369
+ * logger: console,
370
+ * }),
371
+ * },
372
+ * });
373
+ * ```
374
+ */
375
+ declare function createGitHubAdapter(config: GitHubAdapterConfig): GitHubAdapter;
376
+
377
+ export { GitHubAdapter, type GitHubAdapterAppConfig, type GitHubAdapterConfig, type GitHubAdapterMultiTenantAppConfig, type GitHubAdapterPATConfig, type GitHubRawMessage, type GitHubThreadId, createGitHubAdapter };