sylas-edge-worker 0.2.21
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/README.md +293 -0
- package/dist/ActivityPoster.d.ts +15 -0
- package/dist/ActivityPoster.d.ts.map +1 -0
- package/dist/ActivityPoster.js +194 -0
- package/dist/ActivityPoster.js.map +1 -0
- package/dist/AgentSessionManager.d.ts +280 -0
- package/dist/AgentSessionManager.d.ts.map +1 -0
- package/dist/AgentSessionManager.js +1412 -0
- package/dist/AgentSessionManager.js.map +1 -0
- package/dist/AskUserQuestionHandler.d.ts +97 -0
- package/dist/AskUserQuestionHandler.d.ts.map +1 -0
- package/dist/AskUserQuestionHandler.js +206 -0
- package/dist/AskUserQuestionHandler.js.map +1 -0
- package/dist/AttachmentService.d.ts +69 -0
- package/dist/AttachmentService.d.ts.map +1 -0
- package/dist/AttachmentService.js +369 -0
- package/dist/AttachmentService.js.map +1 -0
- package/dist/ChatSessionHandler.d.ts +87 -0
- package/dist/ChatSessionHandler.d.ts.map +1 -0
- package/dist/ChatSessionHandler.js +231 -0
- package/dist/ChatSessionHandler.js.map +1 -0
- package/dist/ConfigManager.d.ts +91 -0
- package/dist/ConfigManager.d.ts.map +1 -0
- package/dist/ConfigManager.js +227 -0
- package/dist/ConfigManager.js.map +1 -0
- package/dist/EdgeWorker.d.ts +670 -0
- package/dist/EdgeWorker.d.ts.map +1 -0
- package/dist/EdgeWorker.js +3801 -0
- package/dist/EdgeWorker.js.map +1 -0
- package/dist/GitService.d.ts +39 -0
- package/dist/GitService.d.ts.map +1 -0
- package/dist/GitService.js +432 -0
- package/dist/GitService.js.map +1 -0
- package/dist/GlobalSessionRegistry.d.ts +142 -0
- package/dist/GlobalSessionRegistry.d.ts.map +1 -0
- package/dist/GlobalSessionRegistry.js +254 -0
- package/dist/GlobalSessionRegistry.js.map +1 -0
- package/dist/PromptBuilder.d.ts +175 -0
- package/dist/PromptBuilder.d.ts.map +1 -0
- package/dist/PromptBuilder.js +884 -0
- package/dist/PromptBuilder.js.map +1 -0
- package/dist/RepositoryRouter.d.ts +152 -0
- package/dist/RepositoryRouter.d.ts.map +1 -0
- package/dist/RepositoryRouter.js +480 -0
- package/dist/RepositoryRouter.js.map +1 -0
- package/dist/RunnerSelectionService.d.ts +62 -0
- package/dist/RunnerSelectionService.d.ts.map +1 -0
- package/dist/RunnerSelectionService.js +379 -0
- package/dist/RunnerSelectionService.js.map +1 -0
- package/dist/SharedApplicationServer.d.ts +107 -0
- package/dist/SharedApplicationServer.d.ts.map +1 -0
- package/dist/SharedApplicationServer.js +247 -0
- package/dist/SharedApplicationServer.js.map +1 -0
- package/dist/SharedWebhookServer.d.ts +39 -0
- package/dist/SharedWebhookServer.d.ts.map +1 -0
- package/dist/SharedWebhookServer.js +150 -0
- package/dist/SharedWebhookServer.js.map +1 -0
- package/dist/SlackChatAdapter.d.ts +25 -0
- package/dist/SlackChatAdapter.d.ts.map +1 -0
- package/dist/SlackChatAdapter.js +143 -0
- package/dist/SlackChatAdapter.js.map +1 -0
- package/dist/UserAccessControl.d.ts +69 -0
- package/dist/UserAccessControl.d.ts.map +1 -0
- package/dist/UserAccessControl.js +171 -0
- package/dist/UserAccessControl.js.map +1 -0
- package/dist/WorktreeIncludeService.d.ts +32 -0
- package/dist/WorktreeIncludeService.d.ts.map +1 -0
- package/dist/WorktreeIncludeService.js +123 -0
- package/dist/WorktreeIncludeService.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/label-prompt-template.md +27 -0
- package/dist/procedures/ProcedureAnalyzer.d.ts +69 -0
- package/dist/procedures/ProcedureAnalyzer.d.ts.map +1 -0
- package/dist/procedures/ProcedureAnalyzer.js +271 -0
- package/dist/procedures/ProcedureAnalyzer.js.map +1 -0
- package/dist/procedures/index.d.ts +7 -0
- package/dist/procedures/index.d.ts.map +1 -0
- package/dist/procedures/index.js +7 -0
- package/dist/procedures/index.js.map +1 -0
- package/dist/procedures/registry.d.ts +156 -0
- package/dist/procedures/registry.d.ts.map +1 -0
- package/dist/procedures/registry.js +240 -0
- package/dist/procedures/registry.js.map +1 -0
- package/dist/procedures/types.d.ts +103 -0
- package/dist/procedures/types.d.ts.map +1 -0
- package/dist/procedures/types.js +5 -0
- package/dist/procedures/types.js.map +1 -0
- package/dist/prompt-assembly/types.d.ts +80 -0
- package/dist/prompt-assembly/types.d.ts.map +1 -0
- package/dist/prompt-assembly/types.js +8 -0
- package/dist/prompt-assembly/types.js.map +1 -0
- package/dist/prompts/builder.md +191 -0
- package/dist/prompts/debugger.md +128 -0
- package/dist/prompts/graphite-orchestrator.md +362 -0
- package/dist/prompts/orchestrator.md +290 -0
- package/dist/prompts/scoper.md +95 -0
- package/dist/prompts/standard-issue-assigned-user-prompt.md +33 -0
- package/dist/prompts/subroutines/changelog-update.md +79 -0
- package/dist/prompts/subroutines/coding-activity.md +12 -0
- package/dist/prompts/subroutines/concise-summary.md +67 -0
- package/dist/prompts/subroutines/debugger-fix.md +92 -0
- package/dist/prompts/subroutines/debugger-reproduction.md +74 -0
- package/dist/prompts/subroutines/full-delegation.md +68 -0
- package/dist/prompts/subroutines/get-approval.md +175 -0
- package/dist/prompts/subroutines/gh-pr.md +80 -0
- package/dist/prompts/subroutines/git-commit.md +37 -0
- package/dist/prompts/subroutines/plan-summary.md +21 -0
- package/dist/prompts/subroutines/preparation.md +16 -0
- package/dist/prompts/subroutines/question-answer.md +8 -0
- package/dist/prompts/subroutines/question-investigation.md +8 -0
- package/dist/prompts/subroutines/release-execution.md +81 -0
- package/dist/prompts/subroutines/release-summary.md +60 -0
- package/dist/prompts/subroutines/user-testing-summary.md +87 -0
- package/dist/prompts/subroutines/user-testing.md +48 -0
- package/dist/prompts/subroutines/validation-fixer.md +56 -0
- package/dist/prompts/subroutines/verbose-summary.md +46 -0
- package/dist/prompts/subroutines/verifications.md +77 -0
- package/dist/prompts/todolist-system-prompt-extension.md +15 -0
- package/dist/sinks/IActivitySink.d.ts +60 -0
- package/dist/sinks/IActivitySink.d.ts.map +1 -0
- package/dist/sinks/IActivitySink.js +2 -0
- package/dist/sinks/IActivitySink.js.map +1 -0
- package/dist/sinks/LinearActivitySink.d.ts +69 -0
- package/dist/sinks/LinearActivitySink.d.ts.map +1 -0
- package/dist/sinks/LinearActivitySink.js +111 -0
- package/dist/sinks/LinearActivitySink.js.map +1 -0
- package/dist/sinks/NoopActivitySink.d.ts +13 -0
- package/dist/sinks/NoopActivitySink.d.ts.map +1 -0
- package/dist/sinks/NoopActivitySink.js +17 -0
- package/dist/sinks/NoopActivitySink.js.map +1 -0
- package/dist/sinks/index.d.ts +9 -0
- package/dist/sinks/index.d.ts.map +1 -0
- package/dist/sinks/index.js +8 -0
- package/dist/sinks/index.js.map +1 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation/ValidationLoopController.d.ts +54 -0
- package/dist/validation/ValidationLoopController.d.ts.map +1 -0
- package/dist/validation/ValidationLoopController.js +242 -0
- package/dist/validation/ValidationLoopController.js.map +1 -0
- package/dist/validation/index.d.ts +7 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +7 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/types.d.ts +82 -0
- package/dist/validation/types.d.ts.map +1 -0
- package/dist/validation/types.js +29 -0
- package/dist/validation/types.js.map +1 -0
- package/label-prompt-template.md +27 -0
- package/package.json +56 -0
- package/prompt-template.md +116 -0
- package/prompts/builder.md +191 -0
- package/prompts/debugger.md +128 -0
- package/prompts/graphite-orchestrator.md +362 -0
- package/prompts/orchestrator.md +290 -0
- package/prompts/scoper.md +95 -0
- package/prompts/standard-issue-assigned-user-prompt.md +33 -0
- package/prompts/todolist-system-prompt-extension.md +15 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { mkdir, readdir, rename, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, extname, join } from "node:path";
|
|
3
|
+
import { fileTypeFromBuffer } from "file-type";
|
|
4
|
+
export class AttachmentService {
|
|
5
|
+
logger;
|
|
6
|
+
sylasHome;
|
|
7
|
+
constructor(logger, sylasHome) {
|
|
8
|
+
this.logger = logger;
|
|
9
|
+
this.sylasHome = sylasHome;
|
|
10
|
+
}
|
|
11
|
+
extractAttachmentUrls(text) {
|
|
12
|
+
if (!text)
|
|
13
|
+
return [];
|
|
14
|
+
// Match URLs that start with https://uploads.linear.app
|
|
15
|
+
// Exclude brackets and parentheses to avoid capturing malformed markdown link syntax
|
|
16
|
+
const regex = /https:\/\/uploads\.linear\.app\/[a-zA-Z0-9/_.-]+/gi;
|
|
17
|
+
const matches = text.match(regex) || [];
|
|
18
|
+
// Remove duplicates
|
|
19
|
+
return [...new Set(matches)];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Download attachments from Linear issue
|
|
23
|
+
* @param issue Linear issue object from webhook data
|
|
24
|
+
* @param repository Repository configuration
|
|
25
|
+
* @param workspacePath Path to workspace directory
|
|
26
|
+
* @param issueTracker Optional issue tracker service for fetching comments and native attachments
|
|
27
|
+
*/
|
|
28
|
+
async downloadIssueAttachments(issue, repository, workspacePath, issueTracker) {
|
|
29
|
+
// Create attachments directory in home directory
|
|
30
|
+
const workspaceFolderName = basename(workspacePath);
|
|
31
|
+
const attachmentsDir = join(this.sylasHome, workspaceFolderName, "attachments");
|
|
32
|
+
try {
|
|
33
|
+
const attachmentMap = {};
|
|
34
|
+
const imageMap = {};
|
|
35
|
+
let attachmentCount = 0;
|
|
36
|
+
let imageCount = 0;
|
|
37
|
+
let skippedCount = 0;
|
|
38
|
+
let failedCount = 0;
|
|
39
|
+
const maxAttachments = 20;
|
|
40
|
+
// Ensure directory exists
|
|
41
|
+
await mkdir(attachmentsDir, { recursive: true });
|
|
42
|
+
// Extract URLs from issue description
|
|
43
|
+
const descriptionUrls = this.extractAttachmentUrls(issue.description || "");
|
|
44
|
+
// Extract URLs from comments if available
|
|
45
|
+
const commentUrls = [];
|
|
46
|
+
// Fetch native Linear attachments (e.g., Sentry links)
|
|
47
|
+
const nativeAttachments = [];
|
|
48
|
+
if (issueTracker && issue.id) {
|
|
49
|
+
try {
|
|
50
|
+
// Fetch native attachments using Linear SDK
|
|
51
|
+
this.logger.debug(`Fetching native attachments for issue ${issue.identifier}`);
|
|
52
|
+
const attachments = await issue.attachments();
|
|
53
|
+
if (attachments?.nodes) {
|
|
54
|
+
for (const attachment of attachments.nodes) {
|
|
55
|
+
nativeAttachments.push({
|
|
56
|
+
title: attachment.title || "Untitled attachment",
|
|
57
|
+
url: attachment.url,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
this.logger.debug(`Found ${nativeAttachments.length} native attachments`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
this.logger.error("Failed to fetch native attachments:", error);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const comments = await issueTracker.fetchComments(issue.id);
|
|
68
|
+
const commentNodes = comments.nodes;
|
|
69
|
+
for (const comment of commentNodes) {
|
|
70
|
+
const urls = this.extractAttachmentUrls(comment.body);
|
|
71
|
+
commentUrls.push(...urls);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
this.logger.error("Failed to fetch comments for attachments:", error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Combine and deduplicate all URLs
|
|
79
|
+
const allUrls = [...new Set([...descriptionUrls, ...commentUrls])];
|
|
80
|
+
this.logger.debug(`Found ${allUrls.length} unique attachment URLs in issue ${issue.identifier}`);
|
|
81
|
+
if (allUrls.length > maxAttachments) {
|
|
82
|
+
this.logger.warn(`Warning: Found ${allUrls.length} attachments but limiting to ${maxAttachments}. Skipping ${allUrls.length - maxAttachments} attachments.`);
|
|
83
|
+
}
|
|
84
|
+
// Download attachments up to the limit
|
|
85
|
+
for (const url of allUrls) {
|
|
86
|
+
if (attachmentCount >= maxAttachments) {
|
|
87
|
+
skippedCount++;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// Generate a temporary filename
|
|
91
|
+
const tempFilename = `attachment_${attachmentCount + 1}.tmp`;
|
|
92
|
+
const tempPath = join(attachmentsDir, tempFilename);
|
|
93
|
+
const result = await this.downloadAttachment(url, tempPath, repository.linearToken);
|
|
94
|
+
if (result.success) {
|
|
95
|
+
// Determine the final filename based on type
|
|
96
|
+
let finalFilename;
|
|
97
|
+
if (result.isImage) {
|
|
98
|
+
imageCount++;
|
|
99
|
+
finalFilename = `image_${imageCount}${result.fileType || ".png"}`;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
finalFilename = `attachment_${attachmentCount + 1}${result.fileType || ""}`;
|
|
103
|
+
}
|
|
104
|
+
const finalPath = join(attachmentsDir, finalFilename);
|
|
105
|
+
// Rename the file to include the correct extension
|
|
106
|
+
await rename(tempPath, finalPath);
|
|
107
|
+
// Store in appropriate map
|
|
108
|
+
if (result.isImage) {
|
|
109
|
+
imageMap[url] = finalPath;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
attachmentMap[url] = finalPath;
|
|
113
|
+
}
|
|
114
|
+
attachmentCount++;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
failedCount++;
|
|
118
|
+
this.logger.warn(`Failed to download attachment: ${url}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Generate attachment manifest
|
|
122
|
+
const manifest = this.generateAttachmentManifest({
|
|
123
|
+
attachmentMap,
|
|
124
|
+
imageMap,
|
|
125
|
+
totalFound: allUrls.length,
|
|
126
|
+
downloaded: attachmentCount,
|
|
127
|
+
imagesDownloaded: imageCount,
|
|
128
|
+
skipped: skippedCount,
|
|
129
|
+
failed: failedCount,
|
|
130
|
+
nativeAttachments,
|
|
131
|
+
});
|
|
132
|
+
// Always return the attachments directory path (it's pre-created)
|
|
133
|
+
return {
|
|
134
|
+
manifest,
|
|
135
|
+
attachmentsDir: attachmentsDir,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.logger.error("Error downloading attachments:", error);
|
|
140
|
+
// Still return the attachments directory even on error
|
|
141
|
+
return { manifest: "", attachmentsDir: attachmentsDir };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Download a single attachment from Linear
|
|
146
|
+
*/
|
|
147
|
+
async downloadAttachment(attachmentUrl, destinationPath, linearToken) {
|
|
148
|
+
try {
|
|
149
|
+
this.logger.debug(`Downloading attachment from: ${attachmentUrl}`);
|
|
150
|
+
const response = await fetch(attachmentUrl, {
|
|
151
|
+
headers: {
|
|
152
|
+
Authorization: `Bearer ${linearToken}`,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
this.logger.error(`Attachment download failed: ${response.status} ${response.statusText}`);
|
|
157
|
+
return { success: false };
|
|
158
|
+
}
|
|
159
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
160
|
+
// Detect the file type from the buffer
|
|
161
|
+
const fileType = await fileTypeFromBuffer(buffer);
|
|
162
|
+
let detectedExtension;
|
|
163
|
+
let isImage = false;
|
|
164
|
+
if (fileType) {
|
|
165
|
+
detectedExtension = `.${fileType.ext}`;
|
|
166
|
+
isImage = fileType.mime.startsWith("image/");
|
|
167
|
+
this.logger.debug(`Detected file type: ${fileType.mime} (${fileType.ext}), is image: ${isImage}`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Try to get extension from URL
|
|
171
|
+
const urlPath = new URL(attachmentUrl).pathname;
|
|
172
|
+
const urlExt = extname(urlPath);
|
|
173
|
+
if (urlExt) {
|
|
174
|
+
detectedExtension = urlExt;
|
|
175
|
+
this.logger.debug(`Using extension from URL: ${detectedExtension}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Write the attachment to disk
|
|
179
|
+
await writeFile(destinationPath, buffer);
|
|
180
|
+
this.logger.debug(`Successfully downloaded attachment to: ${destinationPath}`);
|
|
181
|
+
return { success: true, fileType: detectedExtension, isImage };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
this.logger.error(`Error downloading attachment:`, error);
|
|
185
|
+
return { success: false };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Download attachments from a specific comment
|
|
190
|
+
* @param commentBody The body text of the comment
|
|
191
|
+
* @param attachmentsDir Directory where attachments should be saved
|
|
192
|
+
* @param linearToken Linear API token
|
|
193
|
+
* @param existingAttachmentCount Current number of attachments already downloaded
|
|
194
|
+
*/
|
|
195
|
+
async downloadCommentAttachments(commentBody, attachmentsDir, linearToken, existingAttachmentCount) {
|
|
196
|
+
const newAttachmentMap = {};
|
|
197
|
+
const newImageMap = {};
|
|
198
|
+
let newAttachmentCount = 0;
|
|
199
|
+
let newImageCount = 0;
|
|
200
|
+
let failedCount = 0;
|
|
201
|
+
const maxAttachments = 20;
|
|
202
|
+
// Extract URLs from the comment
|
|
203
|
+
const urls = this.extractAttachmentUrls(commentBody);
|
|
204
|
+
if (urls.length === 0) {
|
|
205
|
+
return {
|
|
206
|
+
newAttachmentMap,
|
|
207
|
+
newImageMap,
|
|
208
|
+
totalNewAttachments: 0,
|
|
209
|
+
failedCount: 0,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
this.logger.debug(`Found ${urls.length} attachment URLs in new comment`);
|
|
213
|
+
// Download new attachments
|
|
214
|
+
for (const url of urls) {
|
|
215
|
+
// Skip if we've already reached the total attachment limit
|
|
216
|
+
if (existingAttachmentCount + newAttachmentCount >= maxAttachments) {
|
|
217
|
+
this.logger.warn(`Skipping attachment due to ${maxAttachments} total attachment limit`);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
// Generate filename based on total attachment count
|
|
221
|
+
const attachmentNumber = existingAttachmentCount + newAttachmentCount + 1;
|
|
222
|
+
const tempFilename = `attachment_${attachmentNumber}.tmp`;
|
|
223
|
+
const tempPath = join(attachmentsDir, tempFilename);
|
|
224
|
+
const result = await this.downloadAttachment(url, tempPath, linearToken);
|
|
225
|
+
if (result.success) {
|
|
226
|
+
// Determine the final filename based on type
|
|
227
|
+
let finalFilename;
|
|
228
|
+
if (result.isImage) {
|
|
229
|
+
newImageCount++;
|
|
230
|
+
// Count existing images to get correct numbering
|
|
231
|
+
const existingImageCount = await this.countExistingImages(attachmentsDir);
|
|
232
|
+
finalFilename = `image_${existingImageCount + newImageCount}${result.fileType || ".png"}`;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
finalFilename = `attachment_${attachmentNumber}${result.fileType || ""}`;
|
|
236
|
+
}
|
|
237
|
+
const finalPath = join(attachmentsDir, finalFilename);
|
|
238
|
+
// Rename the file to include the correct extension
|
|
239
|
+
await rename(tempPath, finalPath);
|
|
240
|
+
// Store in appropriate map
|
|
241
|
+
if (result.isImage) {
|
|
242
|
+
newImageMap[url] = finalPath;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
newAttachmentMap[url] = finalPath;
|
|
246
|
+
}
|
|
247
|
+
newAttachmentCount++;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
failedCount++;
|
|
251
|
+
this.logger.warn(`Failed to download attachment: ${url}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
newAttachmentMap,
|
|
256
|
+
newImageMap,
|
|
257
|
+
totalNewAttachments: newAttachmentCount,
|
|
258
|
+
failedCount,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Count existing images in the attachments directory
|
|
263
|
+
*/
|
|
264
|
+
async countExistingImages(attachmentsDir) {
|
|
265
|
+
try {
|
|
266
|
+
const files = await readdir(attachmentsDir);
|
|
267
|
+
return files.filter((file) => file.startsWith("image_")).length;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Generate attachment manifest for new comment attachments
|
|
275
|
+
*/
|
|
276
|
+
generateNewAttachmentManifest(result) {
|
|
277
|
+
const { newAttachmentMap, newImageMap, totalNewAttachments, failedCount } = result;
|
|
278
|
+
if (totalNewAttachments === 0) {
|
|
279
|
+
return "";
|
|
280
|
+
}
|
|
281
|
+
let manifest = "\n## New Attachments from Comment\n\n";
|
|
282
|
+
manifest += `Downloaded ${totalNewAttachments} new attachment${totalNewAttachments > 1 ? "s" : ""}`;
|
|
283
|
+
if (failedCount > 0) {
|
|
284
|
+
manifest += ` (${failedCount} failed)`;
|
|
285
|
+
}
|
|
286
|
+
manifest += ".\n\n";
|
|
287
|
+
// List new images
|
|
288
|
+
if (Object.keys(newImageMap).length > 0) {
|
|
289
|
+
manifest += "### New Images\n";
|
|
290
|
+
Object.entries(newImageMap).forEach(([url, localPath], index) => {
|
|
291
|
+
const filename = basename(localPath);
|
|
292
|
+
manifest += `${index + 1}. ${filename} - Original URL: ${url}\n`;
|
|
293
|
+
manifest += ` Local path: ${localPath}\n\n`;
|
|
294
|
+
});
|
|
295
|
+
manifest += "You can use the Read tool to view these images.\n\n";
|
|
296
|
+
}
|
|
297
|
+
// List new other attachments
|
|
298
|
+
if (Object.keys(newAttachmentMap).length > 0) {
|
|
299
|
+
manifest += "### New Attachments\n";
|
|
300
|
+
Object.entries(newAttachmentMap).forEach(([url, localPath], index) => {
|
|
301
|
+
const filename = basename(localPath);
|
|
302
|
+
manifest += `${index + 1}. ${filename} - Original URL: ${url}\n`;
|
|
303
|
+
manifest += ` Local path: ${localPath}\n\n`;
|
|
304
|
+
});
|
|
305
|
+
manifest += "You can use the Read tool to view these files.\n\n";
|
|
306
|
+
}
|
|
307
|
+
return manifest;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Generate a markdown section describing downloaded attachments
|
|
311
|
+
*/
|
|
312
|
+
generateAttachmentManifest(downloadResult) {
|
|
313
|
+
const { attachmentMap, imageMap, totalFound, downloaded, imagesDownloaded, skipped, failed, nativeAttachments = [], } = downloadResult;
|
|
314
|
+
let manifest = "\n## Downloaded Attachments\n\n";
|
|
315
|
+
// Add native Linear attachments section if available
|
|
316
|
+
if (nativeAttachments.length > 0) {
|
|
317
|
+
manifest += "### Linear Issue Links\n";
|
|
318
|
+
nativeAttachments.forEach((attachment, index) => {
|
|
319
|
+
manifest += `${index + 1}. ${attachment.title}\n`;
|
|
320
|
+
manifest += ` URL: ${attachment.url}\n\n`;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
if (totalFound === 0 && nativeAttachments.length === 0) {
|
|
324
|
+
manifest += "No attachments were found in this issue.\n\n";
|
|
325
|
+
manifest +=
|
|
326
|
+
"The attachments directory `~/.sylas/<workspace>/attachments` has been created and is available for any future attachments that may be added to this issue.\n";
|
|
327
|
+
return manifest;
|
|
328
|
+
}
|
|
329
|
+
manifest += `Found ${totalFound} attachments. Downloaded ${downloaded}`;
|
|
330
|
+
if (imagesDownloaded > 0) {
|
|
331
|
+
manifest += ` (including ${imagesDownloaded} images)`;
|
|
332
|
+
}
|
|
333
|
+
if (skipped > 0) {
|
|
334
|
+
manifest += `, skipped ${skipped} due to ${downloaded} attachment limit`;
|
|
335
|
+
}
|
|
336
|
+
if (failed > 0) {
|
|
337
|
+
manifest += `, failed to download ${failed}`;
|
|
338
|
+
}
|
|
339
|
+
manifest += ".\n\n";
|
|
340
|
+
if (failed > 0) {
|
|
341
|
+
manifest +=
|
|
342
|
+
"**Note**: Some attachments failed to download. This may be due to authentication issues or the files being unavailable. The agent will continue processing the issue with the available information.\n\n";
|
|
343
|
+
}
|
|
344
|
+
manifest +=
|
|
345
|
+
"Attachments have been downloaded to the `~/.sylas/<workspace>/attachments` directory:\n\n";
|
|
346
|
+
// List images first
|
|
347
|
+
if (Object.keys(imageMap).length > 0) {
|
|
348
|
+
manifest += "### Images\n";
|
|
349
|
+
Object.entries(imageMap).forEach(([url, localPath], index) => {
|
|
350
|
+
const filename = basename(localPath);
|
|
351
|
+
manifest += `${index + 1}. ${filename} - Original URL: ${url}\n`;
|
|
352
|
+
manifest += ` Local path: ${localPath}\n\n`;
|
|
353
|
+
});
|
|
354
|
+
manifest += "You can use the Read tool to view these images.\n\n";
|
|
355
|
+
}
|
|
356
|
+
// List other attachments
|
|
357
|
+
if (Object.keys(attachmentMap).length > 0) {
|
|
358
|
+
manifest += "### Other Attachments\n";
|
|
359
|
+
Object.entries(attachmentMap).forEach(([url, localPath], index) => {
|
|
360
|
+
const filename = basename(localPath);
|
|
361
|
+
manifest += `${index + 1}. ${filename} - Original URL: ${url}\n`;
|
|
362
|
+
manifest += ` Local path: ${localPath}\n\n`;
|
|
363
|
+
});
|
|
364
|
+
manifest += "You can use the Read tool to view these files.\n\n";
|
|
365
|
+
}
|
|
366
|
+
return manifest;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=AttachmentService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttachmentService.js","sourceRoot":"","sources":["../src/AttachmentService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { McpServerConfig } from "sylas-claude-runner";
|
|
2
|
+
import type { IAgentRunner, ILogger } from "sylas-core";
|
|
3
|
+
/**
|
|
4
|
+
* Defines what each chat platform must provide for the generic session lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* Implementations are stateless data mappers — they translate platform-specific
|
|
7
|
+
* events into the common operations the ChatSessionHandler needs.
|
|
8
|
+
*/
|
|
9
|
+
/** Platform identifiers supported by the session manager */
|
|
10
|
+
export type ChatPlatformName = "slack" | "linear" | "github";
|
|
11
|
+
export interface ChatPlatformAdapter<TEvent> {
|
|
12
|
+
readonly platformName: ChatPlatformName;
|
|
13
|
+
/** Extract the user's task text from the raw event */
|
|
14
|
+
extractTaskInstructions(event: TEvent): string;
|
|
15
|
+
/** Derive a unique thread key for session tracking (e.g., "C123:1704110400.000100") */
|
|
16
|
+
getThreadKey(event: TEvent): string;
|
|
17
|
+
/** Get the unique event ID */
|
|
18
|
+
getEventId(event: TEvent): string;
|
|
19
|
+
/** Build a platform-specific system prompt */
|
|
20
|
+
buildSystemPrompt(event: TEvent): string;
|
|
21
|
+
/** Fetch thread context as formatted string. Returns "" if not applicable */
|
|
22
|
+
fetchThreadContext(event: TEvent): Promise<string>;
|
|
23
|
+
/** Post the agent's final response back to the platform */
|
|
24
|
+
postReply(event: TEvent, runner: IAgentRunner): Promise<void>;
|
|
25
|
+
/** Acknowledge receipt of the event (e.g., emoji reaction). Fire-and-forget */
|
|
26
|
+
acknowledgeReceipt(event: TEvent): Promise<void>;
|
|
27
|
+
/** Notify the user that a previous request is still processing */
|
|
28
|
+
notifyBusy(event: TEvent, threadKey: string): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Callbacks for EdgeWorker integration (same pattern as RepositoryRouterDeps).
|
|
32
|
+
*/
|
|
33
|
+
export interface ChatSessionHandlerDeps {
|
|
34
|
+
sylasHome: string;
|
|
35
|
+
defaultModel?: string;
|
|
36
|
+
defaultFallbackModel?: string;
|
|
37
|
+
mcpConfig?: Record<string, McpServerConfig>;
|
|
38
|
+
onWebhookStart: () => void;
|
|
39
|
+
onWebhookEnd: () => void;
|
|
40
|
+
onStateChange: () => Promise<void>;
|
|
41
|
+
onClaudeError: (error: Error) => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generic session lifecycle engine for chat platform integrations.
|
|
45
|
+
*
|
|
46
|
+
* Manages the create/resume/inject/reply session lifecycle independent of any
|
|
47
|
+
* specific chat platform. Platform-specific behavior is provided via a
|
|
48
|
+
* ChatPlatformAdapter.
|
|
49
|
+
*/
|
|
50
|
+
export declare class ChatSessionHandler<TEvent> {
|
|
51
|
+
private adapter;
|
|
52
|
+
private sessionManager;
|
|
53
|
+
private threadSessions;
|
|
54
|
+
private deps;
|
|
55
|
+
private logger;
|
|
56
|
+
constructor(adapter: ChatPlatformAdapter<TEvent>, deps: ChatSessionHandlerDeps, logger?: ILogger);
|
|
57
|
+
/**
|
|
58
|
+
* Main entry point — handles a single chat platform event.
|
|
59
|
+
*
|
|
60
|
+
* Replaces the per-platform handleXxxWebhook method in EdgeWorker.
|
|
61
|
+
*/
|
|
62
|
+
handleEvent(event: TEvent): Promise<void>;
|
|
63
|
+
/** Returns true if any runner managed by this handler is currently busy */
|
|
64
|
+
isAnyRunnerBusy(): boolean;
|
|
65
|
+
/** Returns all runners managed by this handler (for shutdown) */
|
|
66
|
+
getAllRunners(): IAgentRunner[];
|
|
67
|
+
/**
|
|
68
|
+
* Resume an existing session with a new prompt (--continue behavior).
|
|
69
|
+
*/
|
|
70
|
+
private resumeSession;
|
|
71
|
+
/**
|
|
72
|
+
* Handle Claude messages for chat sessions.
|
|
73
|
+
* Routes to the dedicated AgentSessionManager.
|
|
74
|
+
*/
|
|
75
|
+
private handleClaudeMessage;
|
|
76
|
+
/**
|
|
77
|
+
* Create an empty workspace directory for a chat thread.
|
|
78
|
+
* Unlike repository-associated sessions, chat sessions use plain directories (not git worktrees).
|
|
79
|
+
*/
|
|
80
|
+
private createWorkspace;
|
|
81
|
+
/**
|
|
82
|
+
* Build a ClaudeRunner config for a chat session.
|
|
83
|
+
* Used by both handleEvent (new session) and resumeSession to eliminate duplication.
|
|
84
|
+
*/
|
|
85
|
+
private buildRunnerConfig;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=ChatSessionHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatSessionHandler.d.ts","sourceRoot":"","sources":["../src/ChatSessionHandler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAqB,MAAM,YAAY,CAAC;AAK3E;;;;;GAKG;AACH,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7D,MAAM,WAAW,mBAAmB,CAAC,MAAM;IAC1C,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IAExC,sDAAsD;IACtD,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAE/C,uFAAuF;IACvF,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEpC,8BAA8B;IAC9B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAElC,8CAA8C;IAC9C,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEzC,6EAA6E;IAC7E,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnD,2DAA2D;IAC3D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D,+EAA+E;IAC/E,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD,kEAAkE;IAClE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACtC;AAED;;;;;;GAMG;AACH,qBAAa,kBAAkB,CAAC,MAAM;IACrC,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,MAAM,CAAU;gBAGvB,OAAO,EAAE,mBAAmB,CAAC,MAAM,CAAC,EACpC,IAAI,EAAE,sBAAsB,EAC5B,MAAM,CAAC,EAAE,OAAO;IAiBjB;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmL/C,2EAA2E;IAC3E,eAAe,IAAI,OAAO;IAS1B,iEAAiE;IACjE,aAAa,IAAI,YAAY,EAAE;IAI/B;;OAEG;YACW,aAAa;IAmC3B;;;OAGG;YACW,mBAAmB;IAOjC;;;OAGG;YACW,eAAe;IAuB7B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAmDzB"}
|