@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.
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/src/__tests__/subpath-exports.test.d.ts +2 -0
- package/dist/src/__tests__/subpath-exports.test.d.ts.map +1 -0
- package/dist/src/__tests__/subpath-exports.test.js +136 -0
- package/dist/src/agent-client-project-repo.test.d.ts +2 -0
- package/dist/src/agent-client-project-repo.test.d.ts.map +1 -0
- package/dist/src/agent-client-project-repo.test.js +153 -0
- package/dist/src/agent-client.d.ts +261 -0
- package/dist/src/agent-client.d.ts.map +1 -0
- package/dist/src/agent-client.js +902 -0
- package/dist/src/agent-session.d.ts +303 -0
- package/dist/src/agent-session.d.ts.map +1 -0
- package/dist/src/agent-session.js +969 -0
- package/dist/src/checkbox-utils.d.ts +88 -0
- package/dist/src/checkbox-utils.d.ts.map +1 -0
- package/dist/src/checkbox-utils.js +120 -0
- package/dist/src/circuit-breaker.d.ts +76 -0
- package/dist/src/circuit-breaker.d.ts.map +1 -0
- package/dist/src/circuit-breaker.js +229 -0
- package/dist/src/circuit-breaker.test.d.ts +2 -0
- package/dist/src/circuit-breaker.test.d.ts.map +1 -0
- package/dist/src/circuit-breaker.test.js +292 -0
- package/dist/src/constants.d.ts +87 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +101 -0
- package/dist/src/defaults/auto-trigger.d.ts +35 -0
- package/dist/src/defaults/auto-trigger.d.ts.map +1 -0
- package/dist/src/defaults/auto-trigger.js +36 -0
- package/dist/src/defaults/index.d.ts +12 -0
- package/dist/src/defaults/index.d.ts.map +1 -0
- package/dist/src/defaults/index.js +11 -0
- package/dist/src/defaults/priority.d.ts +20 -0
- package/dist/src/defaults/priority.d.ts.map +1 -0
- package/dist/src/defaults/priority.js +38 -0
- package/dist/src/defaults/prompts.d.ts +42 -0
- package/dist/src/defaults/prompts.d.ts.map +1 -0
- package/dist/src/defaults/prompts.js +313 -0
- package/dist/src/defaults/prompts.test.d.ts +2 -0
- package/dist/src/defaults/prompts.test.d.ts.map +1 -0
- package/dist/src/defaults/prompts.test.js +263 -0
- package/dist/src/defaults/work-type-detection.d.ts +19 -0
- package/dist/src/defaults/work-type-detection.d.ts.map +1 -0
- package/dist/src/defaults/work-type-detection.js +98 -0
- package/dist/src/errors.d.ts +91 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +173 -0
- package/dist/src/frontend-adapter.d.ts +168 -0
- package/dist/src/frontend-adapter.d.ts.map +1 -0
- package/dist/src/frontend-adapter.js +314 -0
- package/dist/src/frontend-adapter.test.d.ts +2 -0
- package/dist/src/frontend-adapter.test.d.ts.map +1 -0
- package/dist/src/frontend-adapter.test.js +545 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +35 -0
- package/dist/src/issue-tracker-adapter.d.ts +113 -0
- package/dist/src/issue-tracker-adapter.d.ts.map +1 -0
- package/dist/src/issue-tracker-adapter.js +169 -0
- package/dist/src/issue-tracker-proxy.d.ts +140 -0
- package/dist/src/issue-tracker-proxy.d.ts.map +1 -0
- package/dist/src/issue-tracker-proxy.js +10 -0
- package/dist/src/platform-adapter.d.ts +132 -0
- package/dist/src/platform-adapter.d.ts.map +1 -0
- package/dist/src/platform-adapter.js +260 -0
- package/dist/src/platform-adapter.test.d.ts +2 -0
- package/dist/src/platform-adapter.test.d.ts.map +1 -0
- package/dist/src/platform-adapter.test.js +468 -0
- package/dist/src/proxy-client.d.ts +103 -0
- package/dist/src/proxy-client.d.ts.map +1 -0
- package/dist/src/proxy-client.js +191 -0
- package/dist/src/rate-limiter.d.ts +64 -0
- package/dist/src/rate-limiter.d.ts.map +1 -0
- package/dist/src/rate-limiter.js +163 -0
- package/dist/src/rate-limiter.test.d.ts +2 -0
- package/dist/src/rate-limiter.test.d.ts.map +1 -0
- package/dist/src/rate-limiter.test.js +217 -0
- package/dist/src/retry.d.ts +59 -0
- package/dist/src/retry.d.ts.map +1 -0
- package/dist/src/retry.js +82 -0
- package/dist/src/retry.test.d.ts +2 -0
- package/dist/src/retry.test.d.ts.map +1 -0
- package/dist/src/retry.test.js +266 -0
- package/dist/src/tools/deployment-bridge.d.ts +34 -0
- package/dist/src/tools/deployment-bridge.d.ts.map +1 -0
- package/dist/src/tools/deployment-bridge.js +122 -0
- package/dist/src/tools/linear-plugin.d.ts +23 -0
- package/dist/src/tools/linear-plugin.d.ts.map +1 -0
- package/dist/src/tools/linear-plugin.js +175 -0
- package/dist/src/tools/linear-runner.d.ts +37 -0
- package/dist/src/tools/linear-runner.d.ts.map +1 -0
- package/dist/src/tools/linear-runner.js +810 -0
- package/dist/src/types.d.ts +492 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +148 -0
- package/dist/src/utils.d.ts +52 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +277 -0
- package/dist/src/webhook-types.d.ts +308 -0
- package/dist/src/webhook-types.d.ts.map +1 -0
- package/dist/src/webhook-types.js +46 -0
- 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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"}
|