@chat-adapter/linear 4.8.0

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,254 @@
1
+ # @chat-adapter/linear
2
+
3
+ Linear adapter for the [chat](https://github.com/vercel-labs/chat) SDK. Enables bots to respond to @mentions in Linear issue comment threads.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install chat @chat-adapter/linear
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { Chat } from "chat";
15
+ import { createLinearAdapter } from "@chat-adapter/linear";
16
+ import { MemoryState } from "@chat-adapter/state-memory";
17
+
18
+ const chat = new Chat({
19
+ userName: "my-bot",
20
+ adapters: {
21
+ linear: createLinearAdapter({
22
+ apiKey: process.env.LINEAR_API_KEY!,
23
+ webhookSecret: process.env.LINEAR_WEBHOOK_SECRET!,
24
+ userName: "my-bot",
25
+ logger: console,
26
+ }),
27
+ },
28
+ state: new MemoryState(),
29
+ logger: "info",
30
+ });
31
+
32
+ // Handle @mentions in issue comments
33
+ chat.onNewMention(async (thread, message) => {
34
+ await thread.post("Hello from Linear!");
35
+ });
36
+ ```
37
+
38
+ ## Configuration
39
+
40
+ | Option | Required | Description |
41
+ | --------------- | -------- | --------------------------------------------------------------------------------------------------- |
42
+ | `apiKey` | Yes\* | [Personal API key](https://linear.app/docs/api-and-webhooks) from Settings > Security & Access |
43
+ | `clientId` | Yes\* | [OAuth app](https://linear.app/developers/oauth-2-0-authentication) client ID |
44
+ | `clientSecret` | Yes\* | OAuth app client secret |
45
+ | `accessToken` | Yes\* | Pre-obtained [OAuth access token](https://linear.app/developers/oauth-2-0-authentication) |
46
+ | `webhookSecret` | Yes | [Webhook signing secret](https://linear.app/developers/webhooks#securing-webhooks) for verification |
47
+ | `userName` | Yes | Bot display name for @mention detection |
48
+
49
+ \*One of: `apiKey`, `clientId`/`clientSecret`, or `accessToken` is required.
50
+
51
+ ## Environment Variables
52
+
53
+ ```bash
54
+ # API Key auth (simplest)
55
+ LINEAR_API_KEY=lin_api_xxxxxxxxxxxx
56
+
57
+ # OR OAuth app auth (recommended for production)
58
+ LINEAR_CLIENT_ID=your-client-id
59
+ LINEAR_CLIENT_SECRET=your-client-secret
60
+
61
+ # Webhook secret (required for all auth methods)
62
+ LINEAR_WEBHOOK_SECRET=your-webhook-secret
63
+ ```
64
+
65
+ ## Linear Setup
66
+
67
+ ### Option A: Personal API Key
68
+
69
+ Best for personal projects, testing, or single-workspace bots.
70
+
71
+ 1. Go to [Settings > Security & Access](https://linear.app/settings/account/security) in Linear
72
+ 2. Scroll to **Personal API keys** and click **Create key**
73
+ 3. Select **Only select permissions** and enable:
74
+ - **Create issues** - Create and update issues
75
+ - **Create comments** - Create and update issue comments
76
+ 4. Under **Team access**, choose **All teams** or select specific teams
77
+ 5. Click **Create** and set `LINEAR_API_KEY` environment variable
78
+
79
+ > **Note:** When using a personal API key, all actions are attributed to you as an individual.
80
+
81
+ ### Option B: OAuth Application (Recommended for Apps)
82
+
83
+ Use this if you want the bot to have its **own identity** in Linear (not attributed to you personally), or if you're building a public integration. The adapter handles token management internally -- no need to store tokens.
84
+
85
+ 1. Go to [Settings > API > Applications](https://linear.app/settings/api/applications/new) in Linear
86
+ 2. Create a new OAuth2 application with your bot's name and icon
87
+ 3. **Enable client credentials tokens** in the app settings
88
+ 4. Note your **Client ID** and **Client Secret**
89
+ 5. Set `LINEAR_CLIENT_ID` and `LINEAR_CLIENT_SECRET` environment variables
90
+
91
+ ```typescript
92
+ createLinearAdapter({
93
+ clientId: process.env.LINEAR_CLIENT_ID!,
94
+ clientSecret: process.env.LINEAR_CLIENT_SECRET!,
95
+ webhookSecret: process.env.LINEAR_WEBHOOK_SECRET!,
96
+ userName: "my-bot",
97
+ logger: console,
98
+ });
99
+ ```
100
+
101
+ The adapter uses the [client credentials grant](https://linear.app/developers/oauth-2-0-authentication#client-credentials-tokens) to obtain tokens automatically. Tokens are valid for 30 days and auto-refresh when expired.
102
+
103
+ > **When to use which?**
104
+ >
105
+ > - **API Key** -- Personal projects, testing, single workspace. Actions attributed to you.
106
+ > - **OAuth App** -- Production bots, public integrations, bot has its own identity.
107
+ > - For making the bot `@`-mentionable as an [Agent](https://linear.app/developers/agents), see the [OAuth setup guide](#oauth-setup-guide) below.
108
+
109
+ ### Webhook Setup
110
+
111
+ See the [Linear Webhooks documentation](https://linear.app/developers/webhooks) for detailed instructions.
112
+
113
+ > **Note:** Webhook management requires **workspace admin** access. If you don't see the API settings page, ask a workspace admin to create the webhook for you.
114
+
115
+ 1. Go to **Settings > API** in your Linear workspace and click **Create webhook**
116
+ 2. Fill in:
117
+ - **Label**: A descriptive name (e.g., "Chat Bot")
118
+ - **URL**: `https://your-domain.com/api/webhooks/linear`
119
+ 3. Copy the **Signing secret** and set it as `LINEAR_WEBHOOK_SECRET`
120
+ 4. Under **Data change events**, select:
121
+ - **Comments** (required - for issue comments)
122
+ - **Issues** (recommended - for mentions in issue descriptions)
123
+ - **Emoji reactions** (optional - for reaction handling)
124
+ 5. Under **Team selection**, choose **All public teams** or a specific team
125
+ 6. Click **Create webhook**
126
+
127
+ ## Features
128
+
129
+ - Message posting and editing
130
+ - Message deletion
131
+ - [Reaction handling](https://linear.app/docs/comment-on-issues) (add reactions via emoji)
132
+ - Issue comment threads
133
+ - Cards (rendered as [Markdown](https://linear.app/docs/comment-on-issues))
134
+
135
+ ## Thread Model
136
+
137
+ Linear has two levels of comment threading:
138
+
139
+ | Type | Description | Thread ID Format |
140
+ | -------------- | --------------------------------------- | -------------------------------- |
141
+ | Issue-level | Top-level comments on an issue | `linear:{issueId}` |
142
+ | Comment thread | Replies nested under a specific comment | `linear:{issueId}:c:{commentId}` |
143
+
144
+ When a user writes a comment, the bot replies **within the same comment thread** (nested under the same card). This matches the expected Linear UX where conversations are grouped.
145
+
146
+ Example thread IDs:
147
+
148
+ - `linear:2174add1-f7c8-44e3-bbf3-2d60b5ea8bc9` (issue-level)
149
+ - `linear:2174add1-f7c8-44e3-bbf3-2d60b5ea8bc9:c:comment-abc123` (comment thread)
150
+
151
+ ## Reactions
152
+
153
+ Linear supports standard [emoji reactions](https://linear.app/docs/comment-on-issues) on comments. The adapter maps SDK emoji names to unicode:
154
+
155
+ | SDK Emoji | Linear Emoji |
156
+ | ------------- | ------------ |
157
+ | `thumbs_up` | 👍 |
158
+ | `thumbs_down` | 👎 |
159
+ | `heart` | ❤️ |
160
+ | `fire` | 🔥 |
161
+ | `rocket` | 🚀 |
162
+ | `eyes` | 👀 |
163
+ | `sparkles` | ✨ |
164
+ | `wave` | 👋 |
165
+
166
+ ## Limitations
167
+
168
+ - **No typing indicators** - Linear doesn't support typing indicators
169
+ - **No streaming** - Messages posted in full (editing supported for updates)
170
+ - **No DMs** - Linear doesn't have direct messages
171
+ - **No modals** - Linear doesn't support interactive modals
172
+ - **Action buttons** - Rendered as text; use link buttons for clickable actions
173
+ - **Remove reaction** - Requires reaction ID lookup (not directly supported)
174
+
175
+ ## Troubleshooting
176
+
177
+ ### "Invalid signature" error
178
+
179
+ - Verify `LINEAR_WEBHOOK_SECRET` matches the secret from your webhook configuration
180
+ - Ensure the request body isn't being modified before verification
181
+ - The webhook secret is shown only once at creation - regenerate if lost
182
+
183
+ ### Bot not responding to mentions
184
+
185
+ - Verify webhook events are configured with `Comment` resource type
186
+ - Check that the webhook URL is correct and accessible
187
+ - Ensure the `userName` config matches how users mention the bot
188
+ - Check that the webhook is enabled (Linear may auto-disable after repeated failures)
189
+
190
+ ### "Webhook expired" error
191
+
192
+ - This means the webhook timestamp is too old (> 5 minutes)
193
+ - Usually indicates a delivery delay or clock skew
194
+ - Check that your server time is synchronized
195
+
196
+ ### Rate limiting
197
+
198
+ - Linear API has [rate limits](https://linear.app/developers/graphql#rate-limiting)
199
+ - The SDK handles rate limiting automatically in most cases
200
+
201
+ ## OAuth Setup Guide
202
+
203
+ This section is only relevant if you chose [Option B: OAuth Application](#option-b-oauth-application-recommended-for-apps). If you're using a personal API key (Option A), you can skip this entirely.
204
+
205
+ Setting up an OAuth application gives the bot its own identity in Linear rather than acting as your personal account.
206
+
207
+ ### 1. Create the OAuth Application
208
+
209
+ 1. Go to [Settings > API > Applications](https://linear.app/settings/api/applications/new) in Linear (requires admin)
210
+ 2. Fill in:
211
+ - **Application name**: Your bot's name (e.g., "v0") -- this is how it appears in Linear
212
+ - **Application icon**: Upload an icon for the bot
213
+ - **Redirect callback URLs**: Add a placeholder URL (e.g., `https://your-domain.com/callback`) -- not needed for client credentials auth
214
+ 3. Click **Create**
215
+ 4. **Enable client credentials tokens** in the app settings
216
+ 5. Note your **Client ID** and **Client Secret**
217
+
218
+ ### 2. Configure the Adapter
219
+
220
+ ```typescript
221
+ createLinearAdapter({
222
+ clientId: process.env.LINEAR_CLIENT_ID!,
223
+ clientSecret: process.env.LINEAR_CLIENT_SECRET!,
224
+ webhookSecret: process.env.LINEAR_WEBHOOK_SECRET!,
225
+ userName: "v0",
226
+ logger: console,
227
+ });
228
+ ```
229
+
230
+ That's it. The adapter automatically obtains and refreshes tokens using the [client credentials grant](https://linear.app/developers/oauth-2-0-authentication#client-credentials-tokens). No callback endpoints, no token storage, no refresh logic on your end.
231
+
232
+ ### 3. Making the Bot @-Mentionable (Optional)
233
+
234
+ To make the bot appear in Linear's `@` mention dropdown as an [Agent](https://linear.app/developers/agents):
235
+
236
+ 1. In your OAuth app settings, enable **Agent session events** under webhooks
237
+ 2. Have a workspace admin install the app using `actor=app` with the `app:mentionable` scope:
238
+
239
+ ```
240
+ https://linear.app/oauth/authorize?
241
+ client_id=YOUR_CLIENT_ID&
242
+ redirect_uri=https://your-domain.com/callback&
243
+ response_type=code&
244
+ scope=read,write,comments:create,app:mentionable&
245
+ actor=app
246
+ ```
247
+
248
+ Once installed, the bot shows up as a mentionable user in the workspace. See the [Linear Agents docs](https://linear.app/developers/agents) for full details.
249
+
250
+ For more on Linear OAuth, see the [Linear OAuth 2.0 documentation](https://linear.app/developers/oauth-2-0-authentication).
251
+
252
+ ## License
253
+
254
+ MIT
@@ -0,0 +1,334 @@
1
+ import { Logger, Adapter, ChatInstance, WebhookOptions, AdapterPostableMessage, RawMessage, EmojiValue, FetchOptions, FetchResult, ThreadInfo, Message, FormattedContent } from 'chat';
2
+
3
+ /**
4
+ * Type definitions for the Linear adapter.
5
+ *
6
+ * Uses types from @linear/sdk wherever possible.
7
+ * Only defines adapter-specific config, thread IDs, and webhook payloads.
8
+ */
9
+
10
+ /**
11
+ * Base configuration options shared by all auth methods.
12
+ */
13
+ interface LinearAdapterBaseConfig {
14
+ /** Logger instance for error reporting */
15
+ logger: Logger;
16
+ /**
17
+ * Webhook signing secret for HMAC-SHA256 verification.
18
+ * Found on the webhook detail page in Linear settings.
19
+ */
20
+ webhookSecret: string;
21
+ /**
22
+ * Bot display name used for @-mention detection.
23
+ * For API key auth, this is typically the user's display name.
24
+ * For OAuth app auth with actor=app, this is the app name.
25
+ */
26
+ userName: string;
27
+ }
28
+ /**
29
+ * Configuration using a personal API key.
30
+ * Simplest setup, suitable for personal bots or testing.
31
+ *
32
+ * @see https://linear.app/docs/api-and-webhooks
33
+ */
34
+ interface LinearAdapterAPIKeyConfig extends LinearAdapterBaseConfig {
35
+ /** Personal API key from Linear Settings > Security & Access */
36
+ apiKey: string;
37
+ accessToken?: never;
38
+ }
39
+ /**
40
+ * Configuration using an OAuth access token (pre-obtained).
41
+ * Use this if you've already obtained an access token through the OAuth flow.
42
+ *
43
+ * @see https://linear.app/developers/oauth-2-0-authentication
44
+ */
45
+ interface LinearAdapterOAuthConfig extends LinearAdapterBaseConfig {
46
+ /** OAuth access token obtained through the OAuth flow */
47
+ accessToken: string;
48
+ apiKey?: never;
49
+ clientId?: never;
50
+ clientSecret?: never;
51
+ }
52
+ /**
53
+ * Configuration using OAuth client credentials (recommended for apps).
54
+ * The adapter handles token management internally - no need to store tokens.
55
+ *
56
+ * Uses the client_credentials grant type to obtain an app-level token.
57
+ * The token is valid for 30 days and auto-refreshes on 401.
58
+ *
59
+ * @see https://linear.app/developers/oauth-2-0-authentication#client-credentials-tokens
60
+ */
61
+ interface LinearAdapterAppConfig extends LinearAdapterBaseConfig {
62
+ /** OAuth application client ID */
63
+ clientId: string;
64
+ /** OAuth application client secret */
65
+ clientSecret: string;
66
+ apiKey?: never;
67
+ accessToken?: never;
68
+ }
69
+ /**
70
+ * Linear adapter configuration - API Key, OAuth token, or OAuth App (client credentials).
71
+ */
72
+ type LinearAdapterConfig = LinearAdapterAPIKeyConfig | LinearAdapterOAuthConfig | LinearAdapterAppConfig;
73
+ /**
74
+ * Decoded thread ID for Linear.
75
+ *
76
+ * Thread types:
77
+ * - Issue-level: Top-level comments on the issue (no commentId)
78
+ * - Comment thread: Replies nested under a specific root comment (has commentId)
79
+ */
80
+ interface LinearThreadId {
81
+ /** Linear issue UUID */
82
+ issueId: string;
83
+ /**
84
+ * Root comment ID for comment-level threads.
85
+ * If present, this is a comment thread (replies nest under this comment).
86
+ * If absent, this is an issue-level thread (top-level comment).
87
+ */
88
+ commentId?: string;
89
+ }
90
+ /**
91
+ * Comment data from a webhook payload.
92
+ *
93
+ * Verified against Linear's Webhooks Schema Explorer and
94
+ * example payloads from the official documentation.
95
+ *
96
+ * @see https://linear.app/developers/webhooks#webhook-payload
97
+ */
98
+ interface LinearCommentData {
99
+ /** Comment UUID */
100
+ id: string;
101
+ /** Comment body in markdown format */
102
+ body: string;
103
+ /** Issue UUID the comment is associated with */
104
+ issueId: string;
105
+ /** User UUID who wrote the comment */
106
+ userId: string;
107
+ /** Parent comment UUID (for nested/threaded replies) */
108
+ parentId?: string;
109
+ /** ISO 8601 creation date */
110
+ createdAt: string;
111
+ /** ISO 8601 last update date */
112
+ updatedAt: string;
113
+ /** Direct URL to the comment */
114
+ url?: string;
115
+ }
116
+ /**
117
+ * Platform-specific raw message type for Linear.
118
+ */
119
+ interface LinearRawMessage {
120
+ /** The raw comment data from webhook or API */
121
+ comment: LinearCommentData;
122
+ /** Organization ID from the webhook */
123
+ organizationId?: string;
124
+ }
125
+
126
+ /**
127
+ * Linear adapter for chat SDK.
128
+ *
129
+ * Supports comment threads on Linear issues.
130
+ * Authentication via personal API key or OAuth access token.
131
+ *
132
+ * @example API Key auth
133
+ * ```typescript
134
+ * import { Chat } from "chat";
135
+ * import { createLinearAdapter } from "@chat-adapter/linear";
136
+ * import { MemoryState } from "@chat-adapter/state-memory";
137
+ *
138
+ * const chat = new Chat({
139
+ * userName: "my-bot",
140
+ * adapters: {
141
+ * linear: createLinearAdapter({
142
+ * apiKey: process.env.LINEAR_API_KEY!,
143
+ * webhookSecret: process.env.LINEAR_WEBHOOK_SECRET!,
144
+ * userName: "my-bot",
145
+ * logger: console,
146
+ * }),
147
+ * },
148
+ * state: new MemoryState(),
149
+ * logger: "info",
150
+ * });
151
+ * ```
152
+ *
153
+ * @example OAuth auth
154
+ * ```typescript
155
+ * const chat = new Chat({
156
+ * userName: "my-bot",
157
+ * adapters: {
158
+ * linear: createLinearAdapter({
159
+ * accessToken: process.env.LINEAR_ACCESS_TOKEN!,
160
+ * webhookSecret: process.env.LINEAR_WEBHOOK_SECRET!,
161
+ * userName: "my-bot",
162
+ * logger: console,
163
+ * }),
164
+ * },
165
+ * state: new MemoryState(),
166
+ * logger: "info",
167
+ * });
168
+ * ```
169
+ */
170
+ declare class LinearAdapter implements Adapter<LinearThreadId, LinearRawMessage> {
171
+ readonly name = "linear";
172
+ readonly userName: string;
173
+ private linearClient;
174
+ private webhookSecret;
175
+ private chat;
176
+ private logger;
177
+ private _botUserId;
178
+ private formatConverter;
179
+ private clientCredentials;
180
+ private accessTokenExpiry;
181
+ /** Bot user ID used for self-message detection */
182
+ get botUserId(): string | undefined;
183
+ constructor(config: LinearAdapterConfig);
184
+ initialize(chat: ChatInstance): Promise<void>;
185
+ /**
186
+ * Fetch a new access token using client credentials grant.
187
+ * The token is valid for 30 days. The adapter auto-refreshes on 401.
188
+ *
189
+ * @see https://linear.app/developers/oauth-2-0-authentication#client-credentials-tokens
190
+ */
191
+ private refreshClientCredentialsToken;
192
+ /**
193
+ * Ensure the client credentials token is still valid. Refresh if expired.
194
+ */
195
+ private ensureValidToken;
196
+ /**
197
+ * Handle incoming webhook from Linear.
198
+ *
199
+ * @see https://linear.app/developers/webhooks
200
+ */
201
+ handleWebhook(request: Request, options?: WebhookOptions): Promise<Response>;
202
+ /**
203
+ * Verify Linear webhook signature using HMAC-SHA256.
204
+ *
205
+ * @see https://linear.app/developers/webhooks#securing-webhooks
206
+ */
207
+ private verifySignature;
208
+ /**
209
+ * Handle a new comment created on an issue.
210
+ *
211
+ * Threading logic:
212
+ * - If the comment has a parentId, it's a reply -> thread under the parent (root comment)
213
+ * - If no parentId, this is a root comment -> thread under this comment's own ID
214
+ */
215
+ private handleCommentCreated;
216
+ /**
217
+ * Handle reaction events (logging only - reactions don't include issueId).
218
+ */
219
+ private handleReaction;
220
+ /**
221
+ * Build a Message from a Linear comment and actor.
222
+ */
223
+ private buildMessage;
224
+ /**
225
+ * Post a message to a thread (create a comment on an issue).
226
+ *
227
+ * For comment-level threads, uses parentId to reply under the root comment.
228
+ * For issue-level threads, creates a top-level comment.
229
+ *
230
+ * Uses LinearClient.createComment({ issueId, body, parentId? }).
231
+ * @see https://linear.app/developers/sdk-fetching-and-modifying-data#mutations
232
+ */
233
+ postMessage(threadId: string, message: AdapterPostableMessage): Promise<RawMessage<LinearRawMessage>>;
234
+ /**
235
+ * Edit an existing message (update a comment).
236
+ *
237
+ * Uses LinearClient.updateComment(id, { body }).
238
+ * @see https://linear.app/developers/sdk-fetching-and-modifying-data#mutations
239
+ */
240
+ editMessage(threadId: string, messageId: string, message: AdapterPostableMessage): Promise<RawMessage<LinearRawMessage>>;
241
+ /**
242
+ * Delete a message (delete a comment).
243
+ *
244
+ * Uses LinearClient.deleteComment(id).
245
+ */
246
+ deleteMessage(_threadId: string, messageId: string): Promise<void>;
247
+ /**
248
+ * Add a reaction to a comment.
249
+ *
250
+ * Uses LinearClient.createReaction({ commentId, emoji }).
251
+ * Linear reactions use emoji strings (unicode).
252
+ */
253
+ addReaction(_threadId: string, messageId: string, emoji: EmojiValue | string): Promise<void>;
254
+ /**
255
+ * Remove a reaction from a comment.
256
+ *
257
+ * Linear doesn't have a direct "remove reaction by emoji + user" API.
258
+ * Removing requires knowing the reaction ID, which would require fetching
259
+ * the comment's reactions first. This is a known limitation.
260
+ */
261
+ removeReaction(_threadId: string, _messageId: string, _emoji: EmojiValue | string): Promise<void>;
262
+ /**
263
+ * Start typing indicator. Not supported by Linear.
264
+ */
265
+ startTyping(_threadId: string): Promise<void>;
266
+ /**
267
+ * Fetch messages from a thread.
268
+ *
269
+ * For issue-level threads: fetches all top-level issue comments.
270
+ * For comment-level threads: fetches the root comment and its children (replies).
271
+ */
272
+ fetchMessages(threadId: string, options?: FetchOptions): Promise<FetchResult<LinearRawMessage>>;
273
+ /**
274
+ * Fetch top-level comments on an issue.
275
+ */
276
+ private fetchIssueComments;
277
+ /**
278
+ * Fetch a comment thread (root comment + its children/replies).
279
+ */
280
+ private fetchCommentThread;
281
+ /**
282
+ * Convert an array of Linear SDK Comment objects to Message instances.
283
+ */
284
+ private commentsToMessages;
285
+ /**
286
+ * Fetch thread info for a Linear issue.
287
+ */
288
+ fetchThread(threadId: string): Promise<ThreadInfo>;
289
+ /**
290
+ * Encode a Linear thread ID.
291
+ *
292
+ * Formats:
293
+ * - Issue-level: linear:{issueId}
294
+ * - Comment thread: linear:{issueId}:c:{commentId}
295
+ */
296
+ encodeThreadId(platformData: LinearThreadId): string;
297
+ /**
298
+ * Decode a Linear thread ID.
299
+ *
300
+ * Formats:
301
+ * - Issue-level: linear:{issueId}
302
+ * - Comment thread: linear:{issueId}:c:{commentId}
303
+ */
304
+ decodeThreadId(threadId: string): LinearThreadId;
305
+ /**
306
+ * Parse platform message format to normalized format.
307
+ */
308
+ parseMessage(raw: LinearRawMessage): Message<LinearRawMessage>;
309
+ /**
310
+ * Render formatted content to Linear markdown.
311
+ */
312
+ renderFormatted(content: FormattedContent): string;
313
+ /**
314
+ * Resolve an emoji value to a unicode string.
315
+ * Linear uses standard unicode emoji for reactions.
316
+ */
317
+ private resolveEmoji;
318
+ }
319
+ /**
320
+ * Factory function to create a Linear adapter.
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * const adapter = createLinearAdapter({
325
+ * apiKey: process.env.LINEAR_API_KEY!,
326
+ * webhookSecret: process.env.LINEAR_WEBHOOK_SECRET!,
327
+ * userName: "my-bot",
328
+ * logger: console,
329
+ * });
330
+ * ```
331
+ */
332
+ declare function createLinearAdapter(config: LinearAdapterConfig): LinearAdapter;
333
+
334
+ export { LinearAdapter, type LinearAdapterAPIKeyConfig, type LinearAdapterAppConfig, type LinearAdapterConfig, type LinearAdapterOAuthConfig, type LinearRawMessage, type LinearThreadId, createLinearAdapter };