@renseiai/plugin-linear 0.8.6

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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -0
  3. package/dist/src/__tests__/subpath-exports.test.d.ts +2 -0
  4. package/dist/src/__tests__/subpath-exports.test.d.ts.map +1 -0
  5. package/dist/src/__tests__/subpath-exports.test.js +136 -0
  6. package/dist/src/agent-client-project-repo.test.d.ts +2 -0
  7. package/dist/src/agent-client-project-repo.test.d.ts.map +1 -0
  8. package/dist/src/agent-client-project-repo.test.js +153 -0
  9. package/dist/src/agent-client.d.ts +261 -0
  10. package/dist/src/agent-client.d.ts.map +1 -0
  11. package/dist/src/agent-client.js +902 -0
  12. package/dist/src/agent-session.d.ts +303 -0
  13. package/dist/src/agent-session.d.ts.map +1 -0
  14. package/dist/src/agent-session.js +969 -0
  15. package/dist/src/checkbox-utils.d.ts +88 -0
  16. package/dist/src/checkbox-utils.d.ts.map +1 -0
  17. package/dist/src/checkbox-utils.js +120 -0
  18. package/dist/src/circuit-breaker.d.ts +76 -0
  19. package/dist/src/circuit-breaker.d.ts.map +1 -0
  20. package/dist/src/circuit-breaker.js +229 -0
  21. package/dist/src/circuit-breaker.test.d.ts +2 -0
  22. package/dist/src/circuit-breaker.test.d.ts.map +1 -0
  23. package/dist/src/circuit-breaker.test.js +292 -0
  24. package/dist/src/constants.d.ts +87 -0
  25. package/dist/src/constants.d.ts.map +1 -0
  26. package/dist/src/constants.js +101 -0
  27. package/dist/src/defaults/auto-trigger.d.ts +35 -0
  28. package/dist/src/defaults/auto-trigger.d.ts.map +1 -0
  29. package/dist/src/defaults/auto-trigger.js +36 -0
  30. package/dist/src/defaults/index.d.ts +12 -0
  31. package/dist/src/defaults/index.d.ts.map +1 -0
  32. package/dist/src/defaults/index.js +11 -0
  33. package/dist/src/defaults/priority.d.ts +20 -0
  34. package/dist/src/defaults/priority.d.ts.map +1 -0
  35. package/dist/src/defaults/priority.js +38 -0
  36. package/dist/src/defaults/prompts.d.ts +42 -0
  37. package/dist/src/defaults/prompts.d.ts.map +1 -0
  38. package/dist/src/defaults/prompts.js +313 -0
  39. package/dist/src/defaults/prompts.test.d.ts +2 -0
  40. package/dist/src/defaults/prompts.test.d.ts.map +1 -0
  41. package/dist/src/defaults/prompts.test.js +263 -0
  42. package/dist/src/defaults/work-type-detection.d.ts +19 -0
  43. package/dist/src/defaults/work-type-detection.d.ts.map +1 -0
  44. package/dist/src/defaults/work-type-detection.js +98 -0
  45. package/dist/src/errors.d.ts +91 -0
  46. package/dist/src/errors.d.ts.map +1 -0
  47. package/dist/src/errors.js +173 -0
  48. package/dist/src/frontend-adapter.d.ts +168 -0
  49. package/dist/src/frontend-adapter.d.ts.map +1 -0
  50. package/dist/src/frontend-adapter.js +314 -0
  51. package/dist/src/frontend-adapter.test.d.ts +2 -0
  52. package/dist/src/frontend-adapter.test.d.ts.map +1 -0
  53. package/dist/src/frontend-adapter.test.js +545 -0
  54. package/dist/src/index.d.ts +32 -0
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +35 -0
  57. package/dist/src/issue-tracker-adapter.d.ts +113 -0
  58. package/dist/src/issue-tracker-adapter.d.ts.map +1 -0
  59. package/dist/src/issue-tracker-adapter.js +169 -0
  60. package/dist/src/issue-tracker-proxy.d.ts +140 -0
  61. package/dist/src/issue-tracker-proxy.d.ts.map +1 -0
  62. package/dist/src/issue-tracker-proxy.js +10 -0
  63. package/dist/src/platform-adapter.d.ts +132 -0
  64. package/dist/src/platform-adapter.d.ts.map +1 -0
  65. package/dist/src/platform-adapter.js +260 -0
  66. package/dist/src/platform-adapter.test.d.ts +2 -0
  67. package/dist/src/platform-adapter.test.d.ts.map +1 -0
  68. package/dist/src/platform-adapter.test.js +468 -0
  69. package/dist/src/proxy-client.d.ts +103 -0
  70. package/dist/src/proxy-client.d.ts.map +1 -0
  71. package/dist/src/proxy-client.js +191 -0
  72. package/dist/src/rate-limiter.d.ts +64 -0
  73. package/dist/src/rate-limiter.d.ts.map +1 -0
  74. package/dist/src/rate-limiter.js +163 -0
  75. package/dist/src/rate-limiter.test.d.ts +2 -0
  76. package/dist/src/rate-limiter.test.d.ts.map +1 -0
  77. package/dist/src/rate-limiter.test.js +217 -0
  78. package/dist/src/retry.d.ts +59 -0
  79. package/dist/src/retry.d.ts.map +1 -0
  80. package/dist/src/retry.js +82 -0
  81. package/dist/src/retry.test.d.ts +2 -0
  82. package/dist/src/retry.test.d.ts.map +1 -0
  83. package/dist/src/retry.test.js +266 -0
  84. package/dist/src/tools/deployment-bridge.d.ts +34 -0
  85. package/dist/src/tools/deployment-bridge.d.ts.map +1 -0
  86. package/dist/src/tools/deployment-bridge.js +122 -0
  87. package/dist/src/tools/linear-plugin.d.ts +23 -0
  88. package/dist/src/tools/linear-plugin.d.ts.map +1 -0
  89. package/dist/src/tools/linear-plugin.js +175 -0
  90. package/dist/src/tools/linear-runner.d.ts +37 -0
  91. package/dist/src/tools/linear-runner.d.ts.map +1 -0
  92. package/dist/src/tools/linear-runner.js +810 -0
  93. package/dist/src/types.d.ts +492 -0
  94. package/dist/src/types.d.ts.map +1 -0
  95. package/dist/src/types.js +148 -0
  96. package/dist/src/utils.d.ts +52 -0
  97. package/dist/src/utils.d.ts.map +1 -0
  98. package/dist/src/utils.js +277 -0
  99. package/dist/src/webhook-types.d.ts +308 -0
  100. package/dist/src/webhook-types.d.ts.map +1 -0
  101. package/dist/src/webhook-types.js +46 -0
  102. package/package.json +73 -0
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Linear API Utilities
3
+ *
4
+ * Helper functions for working with Linear API
5
+ */
6
+ /**
7
+ * Truncate a string to a maximum length, adding truncation marker if needed
8
+ */
9
+ export declare function truncateText(text: string, maxLength?: number): string;
10
+ /**
11
+ * Build a completion comment with smart truncation.
12
+ * Prioritizes: summary > plan status > session ID
13
+ *
14
+ * If the full comment exceeds maxLength:
15
+ * 1. First, truncate plan items to show only states
16
+ * 2. If still too long, truncate the summary
17
+ */
18
+ export declare function buildCompletionComment(summary: string, planItems: Array<{
19
+ state: string;
20
+ title: string;
21
+ }>, sessionId: string | null, maxLength?: number): string;
22
+ /**
23
+ * Represents a chunk of content split for multiple comments
24
+ */
25
+ export interface CommentChunk {
26
+ body: string;
27
+ partNumber: number;
28
+ totalParts: number;
29
+ }
30
+ /**
31
+ * Split content into multiple comment chunks
32
+ *
33
+ * Splitting strategy:
34
+ * 1. Reserve space for part markers
35
+ * 2. Split at paragraph boundaries first
36
+ * 3. If paragraph too long, split at sentence boundaries
37
+ * 4. If sentence too long, split at word boundaries
38
+ * 5. Never split inside code blocks
39
+ */
40
+ export declare function splitContentIntoComments(content: string, maxLength?: number, maxComments?: number): CommentChunk[];
41
+ /**
42
+ * Build completion comments with smart splitting.
43
+ * Returns multiple comment chunks if content exceeds max length.
44
+ *
45
+ * For backward compatibility, maintains the same header/footer structure
46
+ * as buildCompletionComment, but splits long content across multiple comments.
47
+ */
48
+ export declare function buildCompletionComments(summary: string, planItems: Array<{
49
+ state: string;
50
+ title: string;
51
+ }>, sessionId: string | null, maxLength?: number): CommentChunk[];
52
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAkC,GAC5C,MAAM,CAOR;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,GAAE,MAAkC,GAC5C,MAAM,CA6DR;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB;AAkED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,SAAS,GAAE,MAAkC,EAC7C,WAAW,GAAE,MAAgC,GAC5C,YAAY,EAAE,CAqDhB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,GAAE,MAAkC,GAC5C,YAAY,EAAE,CAiGhB"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Linear API Utilities
3
+ *
4
+ * Helper functions for working with Linear API
5
+ */
6
+ import { LINEAR_COMMENT_MAX_LENGTH, TRUNCATION_MARKER, MAX_COMPLETION_COMMENTS, COMMENT_OVERHEAD, CONTINUATION_MARKER, } from './constants.js';
7
+ /**
8
+ * Truncate a string to a maximum length, adding truncation marker if needed
9
+ */
10
+ export function truncateText(text, maxLength = LINEAR_COMMENT_MAX_LENGTH) {
11
+ if (text.length <= maxLength) {
12
+ return text;
13
+ }
14
+ const truncateAt = maxLength - TRUNCATION_MARKER.length;
15
+ return text.substring(0, truncateAt) + TRUNCATION_MARKER;
16
+ }
17
+ /**
18
+ * Build a completion comment with smart truncation.
19
+ * Prioritizes: summary > plan status > session ID
20
+ *
21
+ * If the full comment exceeds maxLength:
22
+ * 1. First, truncate plan items to show only states
23
+ * 2. If still too long, truncate the summary
24
+ */
25
+ export function buildCompletionComment(summary, planItems, sessionId, maxLength = LINEAR_COMMENT_MAX_LENGTH) {
26
+ const stateEmoji = {
27
+ pending: '\u{2B1C}',
28
+ inProgress: '\u{1F504}',
29
+ completed: '\u{2705}',
30
+ canceled: '\u{274C}',
31
+ };
32
+ // Build static parts
33
+ const header = '## Agent Work Complete\n\n';
34
+ const planHeader = '\n\n### Final Plan Status\n\n';
35
+ const footer = `\n\n---\n*Session ID: ${sessionId ?? 'unknown'}*`;
36
+ // Full plan status
37
+ const fullPlanStatus = planItems
38
+ .map((item) => `${stateEmoji[item.state] ?? '\u{2B1C}'} ${item.title}`)
39
+ .join('\n');
40
+ // Abbreviated plan status (just emoji counts)
41
+ const completedCount = planItems.filter((i) => i.state === 'completed').length;
42
+ const pendingCount = planItems.filter((i) => i.state === 'pending').length;
43
+ const canceledCount = planItems.filter((i) => i.state === 'canceled').length;
44
+ const abbreviatedPlanStatus = [
45
+ `\u{2705} ${completedCount} completed`,
46
+ pendingCount > 0 ? `\u{2B1C} ${pendingCount} pending` : null,
47
+ canceledCount > 0 ? `\u{274C} ${canceledCount} canceled` : null,
48
+ ]
49
+ .filter(Boolean)
50
+ .join(' | ');
51
+ // Try full comment first
52
+ const fullComment = header + summary + planHeader + fullPlanStatus + footer;
53
+ if (fullComment.length <= maxLength) {
54
+ return fullComment;
55
+ }
56
+ // Try with abbreviated plan
57
+ const abbreviatedComment = header + summary + planHeader + abbreviatedPlanStatus + footer;
58
+ if (abbreviatedComment.length <= maxLength) {
59
+ return abbreviatedComment;
60
+ }
61
+ // Need to truncate summary
62
+ const fixedLength = header.length +
63
+ planHeader.length +
64
+ abbreviatedPlanStatus.length +
65
+ footer.length +
66
+ TRUNCATION_MARKER.length;
67
+ const availableForSummary = maxLength - fixedLength;
68
+ if (availableForSummary > 100) {
69
+ // Only truncate if we have reasonable space
70
+ const truncatedSummary = summary.substring(0, availableForSummary) + TRUNCATION_MARKER;
71
+ return header + truncatedSummary + planHeader + abbreviatedPlanStatus + footer;
72
+ }
73
+ // Extreme case: even the fixed parts are too long, just truncate everything
74
+ return truncateText(fullComment, maxLength);
75
+ }
76
+ /**
77
+ * Check if a position is inside a code block
78
+ */
79
+ function isInsideCodeBlock(text, position) {
80
+ let insideCodeBlock = false;
81
+ let i = 0;
82
+ while (i < position && i < text.length) {
83
+ if (text.slice(i, i + 3) === '```') {
84
+ insideCodeBlock = !insideCodeBlock;
85
+ i += 3;
86
+ }
87
+ else {
88
+ i++;
89
+ }
90
+ }
91
+ return insideCodeBlock;
92
+ }
93
+ /**
94
+ * Find a safe split point in text that doesn't break code blocks
95
+ */
96
+ function findSafeSplitPoint(text, targetLength) {
97
+ if (text.length <= targetLength) {
98
+ return text.length;
99
+ }
100
+ // Try to split at paragraph boundary first
101
+ const paragraphBoundary = text.lastIndexOf('\n\n', targetLength);
102
+ if (paragraphBoundary > targetLength * 0.5 && !isInsideCodeBlock(text, paragraphBoundary)) {
103
+ return paragraphBoundary;
104
+ }
105
+ // Try to split at sentence boundary
106
+ const sentenceEnd = text.lastIndexOf('. ', targetLength);
107
+ if (sentenceEnd > targetLength * 0.5 && !isInsideCodeBlock(text, sentenceEnd)) {
108
+ return sentenceEnd + 1; // Include the period
109
+ }
110
+ // Try to split at newline
111
+ const newline = text.lastIndexOf('\n', targetLength);
112
+ if (newline > targetLength * 0.5 && !isInsideCodeBlock(text, newline)) {
113
+ return newline;
114
+ }
115
+ // Try to split at word boundary
116
+ const wordBoundary = text.lastIndexOf(' ', targetLength);
117
+ if (wordBoundary > targetLength * 0.3 && !isInsideCodeBlock(text, wordBoundary)) {
118
+ return wordBoundary;
119
+ }
120
+ // If we're inside a code block, find the end of it
121
+ if (isInsideCodeBlock(text, targetLength)) {
122
+ // Look for code block end after targetLength
123
+ const codeBlockEnd = text.indexOf('```', targetLength);
124
+ if (codeBlockEnd !== -1 && codeBlockEnd < targetLength * 1.5) {
125
+ // Include the closing fence and newline
126
+ const afterFence = text.indexOf('\n', codeBlockEnd + 3);
127
+ return afterFence !== -1 ? afterFence : codeBlockEnd + 3;
128
+ }
129
+ }
130
+ // Last resort: split at target length
131
+ return targetLength;
132
+ }
133
+ /**
134
+ * Split content into multiple comment chunks
135
+ *
136
+ * Splitting strategy:
137
+ * 1. Reserve space for part markers
138
+ * 2. Split at paragraph boundaries first
139
+ * 3. If paragraph too long, split at sentence boundaries
140
+ * 4. If sentence too long, split at word boundaries
141
+ * 5. Never split inside code blocks
142
+ */
143
+ export function splitContentIntoComments(content, maxLength = LINEAR_COMMENT_MAX_LENGTH, maxComments = MAX_COMPLETION_COMMENTS) {
144
+ // Account for overhead (part markers, continuation markers)
145
+ const effectiveMaxLength = maxLength - COMMENT_OVERHEAD;
146
+ if (content.length <= effectiveMaxLength) {
147
+ return [{ body: content, partNumber: 1, totalParts: 1 }];
148
+ }
149
+ const chunks = [];
150
+ let remaining = content;
151
+ while (remaining.length > 0 && chunks.length < maxComments) {
152
+ // Reserve space for continuation marker if not the last chunk
153
+ const reserveForContinuation = remaining.length > effectiveMaxLength
154
+ ? CONTINUATION_MARKER.length
155
+ : 0;
156
+ const chunkMaxLength = effectiveMaxLength - reserveForContinuation;
157
+ if (remaining.length <= chunkMaxLength) {
158
+ chunks.push(remaining);
159
+ remaining = '';
160
+ }
161
+ else {
162
+ const splitPoint = findSafeSplitPoint(remaining, chunkMaxLength);
163
+ const chunk = remaining.slice(0, splitPoint).trimEnd();
164
+ chunks.push(chunk);
165
+ remaining = remaining.slice(splitPoint).trimStart();
166
+ }
167
+ }
168
+ // If we hit max comments and still have content, append truncation to last chunk
169
+ if (remaining.length > 0 && chunks.length > 0) {
170
+ chunks[chunks.length - 1] += TRUNCATION_MARKER;
171
+ }
172
+ const totalParts = chunks.length;
173
+ return chunks.map((chunk, index) => {
174
+ const partNumber = index + 1;
175
+ const isLastPart = partNumber === totalParts;
176
+ // Add part marker for multi-part comments
177
+ let body = chunk;
178
+ if (totalParts > 1) {
179
+ const partMarker = `\n\n---\n*Part ${partNumber}/${totalParts}*`;
180
+ if (!isLastPart) {
181
+ body = chunk + CONTINUATION_MARKER + partMarker;
182
+ }
183
+ else {
184
+ body = chunk + partMarker;
185
+ }
186
+ }
187
+ return { body, partNumber, totalParts };
188
+ });
189
+ }
190
+ /**
191
+ * Build completion comments with smart splitting.
192
+ * Returns multiple comment chunks if content exceeds max length.
193
+ *
194
+ * For backward compatibility, maintains the same header/footer structure
195
+ * as buildCompletionComment, but splits long content across multiple comments.
196
+ */
197
+ export function buildCompletionComments(summary, planItems, sessionId, maxLength = LINEAR_COMMENT_MAX_LENGTH) {
198
+ const stateEmoji = {
199
+ pending: '\u{2B1C}',
200
+ inProgress: '\u{1F504}',
201
+ completed: '\u{2705}',
202
+ canceled: '\u{274C}',
203
+ };
204
+ // Build static parts
205
+ const header = '## Agent Work Complete\n\n';
206
+ const planHeader = '\n\n### Final Plan Status\n\n';
207
+ const footer = `\n\n---\n*Session ID: ${sessionId ?? 'unknown'}*`;
208
+ // Full plan status
209
+ const fullPlanStatus = planItems
210
+ .map((item) => `${stateEmoji[item.state] ?? '\u{2B1C}'} ${item.title}`)
211
+ .join('\n');
212
+ // Abbreviated plan status (just emoji counts)
213
+ const completedCount = planItems.filter((i) => i.state === 'completed').length;
214
+ const pendingCount = planItems.filter((i) => i.state === 'pending').length;
215
+ const canceledCount = planItems.filter((i) => i.state === 'canceled').length;
216
+ const abbreviatedPlanStatus = [
217
+ `\u{2705} ${completedCount} completed`,
218
+ pendingCount > 0 ? `\u{2B1C} ${pendingCount} pending` : null,
219
+ canceledCount > 0 ? `\u{274C} ${canceledCount} canceled` : null,
220
+ ]
221
+ .filter(Boolean)
222
+ .join(' | ');
223
+ // Try full comment first (single comment)
224
+ const fullComment = header + summary + planHeader + fullPlanStatus + footer;
225
+ if (fullComment.length <= maxLength) {
226
+ return [{ body: fullComment, partNumber: 1, totalParts: 1 }];
227
+ }
228
+ // Try with abbreviated plan (still single comment)
229
+ const abbreviatedComment = header + summary + planHeader + abbreviatedPlanStatus + footer;
230
+ if (abbreviatedComment.length <= maxLength) {
231
+ return [{ body: abbreviatedComment, partNumber: 1, totalParts: 1 }];
232
+ }
233
+ // Need to split into multiple comments
234
+ // First comment gets header + beginning of summary
235
+ // Middle comments get summary continuation
236
+ // Last comment gets end of summary + plan status + footer
237
+ const fixedSuffixLength = planHeader.length + abbreviatedPlanStatus.length + footer.length;
238
+ const headerLength = header.length;
239
+ // Split the summary into chunks
240
+ const summaryChunks = splitContentIntoComments(summary, maxLength - COMMENT_OVERHEAD - Math.max(headerLength, fixedSuffixLength), MAX_COMPLETION_COMMENTS);
241
+ // Build final comments
242
+ const result = [];
243
+ const totalParts = summaryChunks.length;
244
+ for (let i = 0; i < summaryChunks.length; i++) {
245
+ const isFirst = i === 0;
246
+ const isLast = i === summaryChunks.length - 1;
247
+ const partNumber = i + 1;
248
+ let body = '';
249
+ if (isFirst) {
250
+ body += header;
251
+ }
252
+ body += summaryChunks[i].body;
253
+ // Remove the part marker from the chunk (we'll add our own)
254
+ if (totalParts > 1) {
255
+ body = body.replace(/\n\n---\n\*Part \d+\/\d+\*$/, '');
256
+ body = body.replace(new RegExp(escapeRegExp(CONTINUATION_MARKER), 'g'), '');
257
+ }
258
+ if (isLast) {
259
+ body += planHeader + abbreviatedPlanStatus + footer;
260
+ }
261
+ // Add part marker for multi-part comments
262
+ if (totalParts > 1) {
263
+ if (!isLast) {
264
+ body += CONTINUATION_MARKER;
265
+ }
266
+ body += `\n\n---\n*Part ${partNumber}/${totalParts}*`;
267
+ }
268
+ result.push({ body, partNumber, totalParts });
269
+ }
270
+ return result;
271
+ }
272
+ /**
273
+ * Escape special regex characters in a string
274
+ */
275
+ function escapeRegExp(string) {
276
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
277
+ }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Linear Webhook Payload Types
3
+ *
4
+ * Types for processing Linear webhook events, including:
5
+ * - AgentSession events (created, prompted, updated, removed)
6
+ * - Issue update events
7
+ *
8
+ * @see https://linear.app/developers/webhooks
9
+ * @see https://linear.app/developers/agent-interaction
10
+ */
11
+ import type { AgentActivitySignal } from './types.js';
12
+ /**
13
+ * Standard webhook action types for most Linear resources
14
+ */
15
+ export type WebhookAction = 'create' | 'update' | 'remove';
16
+ /**
17
+ * AgentSession-specific webhook action types
18
+ * Note: Linear sends past-tense actions (created, updated, removed)
19
+ * - created: New session initiated by user mention or delegation
20
+ * - prompted: User sent a follow-up message to an existing session
21
+ * - updated: Session state changed
22
+ * - removed: Session was deleted
23
+ */
24
+ export type AgentSessionAction = 'created' | 'prompted' | 'updated' | 'removed';
25
+ /**
26
+ * User who initiated or is responsible for the session
27
+ */
28
+ export interface WebhookUser {
29
+ id: string;
30
+ name: string;
31
+ email?: string;
32
+ displayName?: string;
33
+ avatarUrl?: string;
34
+ }
35
+ /**
36
+ * Comment data included in webhook payloads
37
+ */
38
+ export interface WebhookComment {
39
+ id: string;
40
+ body: string;
41
+ createdAt: string;
42
+ user?: WebhookUser;
43
+ parentId?: string;
44
+ }
45
+ /**
46
+ * Issue data included in webhook payloads
47
+ */
48
+ export interface WebhookIssue {
49
+ id: string;
50
+ identifier: string;
51
+ title: string;
52
+ description?: string;
53
+ url: string;
54
+ state?: {
55
+ id: string;
56
+ name: string;
57
+ type: string;
58
+ };
59
+ team?: {
60
+ id: string;
61
+ name: string;
62
+ key: string;
63
+ };
64
+ labels?: Array<{
65
+ id: string;
66
+ name: string;
67
+ color?: string;
68
+ }>;
69
+ project?: {
70
+ id: string;
71
+ name: string;
72
+ };
73
+ parent?: {
74
+ id: string;
75
+ identifier: string;
76
+ title: string;
77
+ };
78
+ }
79
+ /**
80
+ * Base Linear webhook payload
81
+ * All webhook events contain these common fields
82
+ */
83
+ export interface LinearWebhookPayload {
84
+ /** The action that triggered this webhook */
85
+ action: WebhookAction | AgentSessionAction;
86
+ /** The type of resource this webhook is for */
87
+ type: string;
88
+ /** The resource data */
89
+ data: Record<string, unknown>;
90
+ /** URL to the resource in Linear */
91
+ url?: string;
92
+ /** ISO timestamp when the event occurred */
93
+ createdAt: string;
94
+ /** ID of the organization this webhook belongs to */
95
+ organizationId?: string;
96
+ /** Unix timestamp when the webhook was sent */
97
+ webhookTimestamp?: number;
98
+ /** Unique ID for this webhook delivery */
99
+ webhookId?: string;
100
+ }
101
+ /**
102
+ * AgentSession state values in webhook payloads.
103
+ *
104
+ * Named `LinearSessionState` to distinguish from:
105
+ * - `AgentSessionState` (Linear Agent SDK states: pending, active, error, awaitingInput, complete)
106
+ * - `AgentSessionStatus` (Redis session tracking states)
107
+ */
108
+ export type LinearSessionState = 'created' | 'running' | 'completed' | 'failed';
109
+ /**
110
+ * Base AgentSession data common to all session events
111
+ */
112
+ export interface AgentSessionData {
113
+ /** Unique session ID */
114
+ id: string;
115
+ /** ID of the issue this session is working on */
116
+ issueId: string;
117
+ /** ID of the agent assigned to this session */
118
+ agentId: string;
119
+ /** Current state of the session */
120
+ state: LinearSessionState;
121
+ /** External URL for the agent's work (e.g., PR link) */
122
+ externalUrl?: string;
123
+ /** Allow additional unknown fields from webhook payload */
124
+ [key: string]: unknown;
125
+ }
126
+ /**
127
+ * Extended AgentSession data for 'create' events
128
+ * Includes context needed to start working on an issue
129
+ */
130
+ export interface AgentSessionCreatedData extends AgentSessionData {
131
+ /**
132
+ * Formatted prompt string containing relevant context for the agent session.
133
+ * Includes issue details, comments, and guidance.
134
+ * Present only for 'create' events.
135
+ */
136
+ promptContext?: string;
137
+ /**
138
+ * Previous comments in the thread before this agent was mentioned.
139
+ * Present only for 'create' events where the session was initiated
140
+ * by mentioning the agent in a child comment of a thread.
141
+ */
142
+ previousComments?: WebhookComment[];
143
+ /**
144
+ * Guidance to inform the agent's behavior.
145
+ * Comes from configuration at workspace, parent teams, and/or current team.
146
+ * The nearest team-specific guidance takes highest precedence.
147
+ */
148
+ guidance?: string;
149
+ /**
150
+ * The human user responsible for initiating this session.
151
+ * Unset if the session was initiated via automation or by an agent user.
152
+ */
153
+ user?: WebhookUser;
154
+ /**
155
+ * Full issue data for the session
156
+ */
157
+ issue?: WebhookIssue;
158
+ /**
159
+ * The comment that triggered this session (if initiated via comment mention)
160
+ */
161
+ comment?: WebhookComment;
162
+ }
163
+ /**
164
+ * Agent activity included in prompted webhooks
165
+ * This can indicate special signals like 'stop' from the user
166
+ */
167
+ export interface WebhookAgentActivity {
168
+ /** The type of activity */
169
+ type?: string;
170
+ /** Signal modifier for the activity */
171
+ signal?: AgentActivitySignal;
172
+ /** Activity content/body */
173
+ body?: string;
174
+ }
175
+ /**
176
+ * Extended AgentSession data for 'prompted' events
177
+ * Includes the follow-up message from the user
178
+ */
179
+ export interface AgentSessionPromptedData extends AgentSessionData {
180
+ /**
181
+ * The follow-up prompt/message from the user.
182
+ * Present when user sends a message to an existing session.
183
+ */
184
+ promptContext?: string;
185
+ /**
186
+ * The user who sent the follow-up message
187
+ */
188
+ user?: WebhookUser;
189
+ /**
190
+ * The comment containing the follow-up message
191
+ */
192
+ comment?: WebhookComment;
193
+ /**
194
+ * Agent activity associated with this prompt.
195
+ * May contain a 'stop' signal if the user clicked Stop.
196
+ * @see https://linear.app/developers/agent-signals
197
+ */
198
+ agentActivity?: WebhookAgentActivity;
199
+ }
200
+ /**
201
+ * AgentSession data for 'update' events
202
+ */
203
+ export interface AgentSessionUpdatedData extends AgentSessionData {
204
+ /** Previous values before the update */
205
+ updatedFrom?: {
206
+ state?: LinearSessionState;
207
+ externalUrl?: string;
208
+ };
209
+ }
210
+ /**
211
+ * Webhook payload for AgentSession 'created' events
212
+ * Triggered when a new agent session is initiated by mention or delegation
213
+ */
214
+ export interface AgentSessionCreatedPayload extends LinearWebhookPayload {
215
+ type: 'AgentSessionEvent';
216
+ action: 'created';
217
+ data: AgentSessionCreatedData;
218
+ }
219
+ /**
220
+ * Webhook payload for AgentSession 'prompted' events
221
+ * Triggered when a user sends a follow-up message to an existing session
222
+ */
223
+ export interface AgentSessionPromptedPayload extends LinearWebhookPayload {
224
+ type: 'AgentSessionEvent';
225
+ action: 'prompted';
226
+ data: AgentSessionPromptedData;
227
+ }
228
+ /**
229
+ * Webhook payload for AgentSession 'updated' events
230
+ * Triggered when session state changes
231
+ */
232
+ export interface AgentSessionUpdatedPayload extends LinearWebhookPayload {
233
+ type: 'AgentSessionEvent';
234
+ action: 'updated';
235
+ data: AgentSessionUpdatedData;
236
+ }
237
+ /**
238
+ * Webhook payload for AgentSession 'removed' events
239
+ * Triggered when a session is deleted
240
+ */
241
+ export interface AgentSessionRemovedPayload extends LinearWebhookPayload {
242
+ type: 'AgentSessionEvent';
243
+ action: 'removed';
244
+ data: AgentSessionData;
245
+ }
246
+ /**
247
+ * Union type for all AgentSession webhook payloads
248
+ */
249
+ export type AgentSessionPayload = AgentSessionCreatedPayload | AgentSessionPromptedPayload | AgentSessionUpdatedPayload | AgentSessionRemovedPayload;
250
+ /**
251
+ * Type guard to check if a payload is an AgentSession event
252
+ */
253
+ export declare function isAgentSessionPayload(payload: LinearWebhookPayload): payload is AgentSessionPayload;
254
+ /**
255
+ * Type guard for AgentSession 'created' events
256
+ */
257
+ export declare function isAgentSessionCreated(payload: LinearWebhookPayload): payload is AgentSessionCreatedPayload;
258
+ /**
259
+ * Type guard for AgentSession 'prompted' events (follow-up messages)
260
+ */
261
+ export declare function isAgentSessionPrompted(payload: LinearWebhookPayload): payload is AgentSessionPromptedPayload;
262
+ /**
263
+ * Type guard for AgentSession 'updated' events
264
+ */
265
+ export declare function isAgentSessionUpdated(payload: LinearWebhookPayload): payload is AgentSessionUpdatedPayload;
266
+ /**
267
+ * Type guard for AgentSession 'removed' events
268
+ */
269
+ export declare function isAgentSessionRemoved(payload: LinearWebhookPayload): payload is AgentSessionRemovedPayload;
270
+ /**
271
+ * Issue state information in webhook payloads
272
+ */
273
+ export interface WebhookIssueState {
274
+ id: string;
275
+ name: string;
276
+ type: string;
277
+ }
278
+ /**
279
+ * Extended issue data for Issue update webhooks
280
+ */
281
+ export interface IssueUpdateData extends WebhookIssue {
282
+ state: WebhookIssueState;
283
+ assignee?: WebhookUser;
284
+ /** Allow additional unknown fields */
285
+ [key: string]: unknown;
286
+ }
287
+ /**
288
+ * Webhook payload for Issue update events
289
+ * @see https://linear.app/developers/webhooks
290
+ */
291
+ export interface IssueUpdatePayload extends LinearWebhookPayload {
292
+ type: 'Issue';
293
+ action: 'update';
294
+ data: IssueUpdateData;
295
+ /** Previous values before the update */
296
+ updatedFrom: {
297
+ stateId?: string;
298
+ assigneeId?: string;
299
+ [key: string]: unknown;
300
+ };
301
+ /** The actor who made the change */
302
+ actor?: WebhookUser;
303
+ }
304
+ /**
305
+ * Type guard for Issue update events
306
+ */
307
+ export declare function isIssueUpdate(payload: LinearWebhookPayload): payload is IssueUpdatePayload;
308
+ //# sourceMappingURL=webhook-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-types.d.ts","sourceRoot":"","sources":["../../src/webhook-types.ts"],"names":[],"mappings":"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"}