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.
Files changed (163) hide show
  1. package/README.md +293 -0
  2. package/dist/ActivityPoster.d.ts +15 -0
  3. package/dist/ActivityPoster.d.ts.map +1 -0
  4. package/dist/ActivityPoster.js +194 -0
  5. package/dist/ActivityPoster.js.map +1 -0
  6. package/dist/AgentSessionManager.d.ts +280 -0
  7. package/dist/AgentSessionManager.d.ts.map +1 -0
  8. package/dist/AgentSessionManager.js +1412 -0
  9. package/dist/AgentSessionManager.js.map +1 -0
  10. package/dist/AskUserQuestionHandler.d.ts +97 -0
  11. package/dist/AskUserQuestionHandler.d.ts.map +1 -0
  12. package/dist/AskUserQuestionHandler.js +206 -0
  13. package/dist/AskUserQuestionHandler.js.map +1 -0
  14. package/dist/AttachmentService.d.ts +69 -0
  15. package/dist/AttachmentService.d.ts.map +1 -0
  16. package/dist/AttachmentService.js +369 -0
  17. package/dist/AttachmentService.js.map +1 -0
  18. package/dist/ChatSessionHandler.d.ts +87 -0
  19. package/dist/ChatSessionHandler.d.ts.map +1 -0
  20. package/dist/ChatSessionHandler.js +231 -0
  21. package/dist/ChatSessionHandler.js.map +1 -0
  22. package/dist/ConfigManager.d.ts +91 -0
  23. package/dist/ConfigManager.d.ts.map +1 -0
  24. package/dist/ConfigManager.js +227 -0
  25. package/dist/ConfigManager.js.map +1 -0
  26. package/dist/EdgeWorker.d.ts +670 -0
  27. package/dist/EdgeWorker.d.ts.map +1 -0
  28. package/dist/EdgeWorker.js +3801 -0
  29. package/dist/EdgeWorker.js.map +1 -0
  30. package/dist/GitService.d.ts +39 -0
  31. package/dist/GitService.d.ts.map +1 -0
  32. package/dist/GitService.js +432 -0
  33. package/dist/GitService.js.map +1 -0
  34. package/dist/GlobalSessionRegistry.d.ts +142 -0
  35. package/dist/GlobalSessionRegistry.d.ts.map +1 -0
  36. package/dist/GlobalSessionRegistry.js +254 -0
  37. package/dist/GlobalSessionRegistry.js.map +1 -0
  38. package/dist/PromptBuilder.d.ts +175 -0
  39. package/dist/PromptBuilder.d.ts.map +1 -0
  40. package/dist/PromptBuilder.js +884 -0
  41. package/dist/PromptBuilder.js.map +1 -0
  42. package/dist/RepositoryRouter.d.ts +152 -0
  43. package/dist/RepositoryRouter.d.ts.map +1 -0
  44. package/dist/RepositoryRouter.js +480 -0
  45. package/dist/RepositoryRouter.js.map +1 -0
  46. package/dist/RunnerSelectionService.d.ts +62 -0
  47. package/dist/RunnerSelectionService.d.ts.map +1 -0
  48. package/dist/RunnerSelectionService.js +379 -0
  49. package/dist/RunnerSelectionService.js.map +1 -0
  50. package/dist/SharedApplicationServer.d.ts +107 -0
  51. package/dist/SharedApplicationServer.d.ts.map +1 -0
  52. package/dist/SharedApplicationServer.js +247 -0
  53. package/dist/SharedApplicationServer.js.map +1 -0
  54. package/dist/SharedWebhookServer.d.ts +39 -0
  55. package/dist/SharedWebhookServer.d.ts.map +1 -0
  56. package/dist/SharedWebhookServer.js +150 -0
  57. package/dist/SharedWebhookServer.js.map +1 -0
  58. package/dist/SlackChatAdapter.d.ts +25 -0
  59. package/dist/SlackChatAdapter.d.ts.map +1 -0
  60. package/dist/SlackChatAdapter.js +143 -0
  61. package/dist/SlackChatAdapter.js.map +1 -0
  62. package/dist/UserAccessControl.d.ts +69 -0
  63. package/dist/UserAccessControl.d.ts.map +1 -0
  64. package/dist/UserAccessControl.js +171 -0
  65. package/dist/UserAccessControl.js.map +1 -0
  66. package/dist/WorktreeIncludeService.d.ts +32 -0
  67. package/dist/WorktreeIncludeService.d.ts.map +1 -0
  68. package/dist/WorktreeIncludeService.js +123 -0
  69. package/dist/WorktreeIncludeService.js.map +1 -0
  70. package/dist/index.d.ts +22 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +17 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/label-prompt-template.md +27 -0
  75. package/dist/procedures/ProcedureAnalyzer.d.ts +69 -0
  76. package/dist/procedures/ProcedureAnalyzer.d.ts.map +1 -0
  77. package/dist/procedures/ProcedureAnalyzer.js +271 -0
  78. package/dist/procedures/ProcedureAnalyzer.js.map +1 -0
  79. package/dist/procedures/index.d.ts +7 -0
  80. package/dist/procedures/index.d.ts.map +1 -0
  81. package/dist/procedures/index.js +7 -0
  82. package/dist/procedures/index.js.map +1 -0
  83. package/dist/procedures/registry.d.ts +156 -0
  84. package/dist/procedures/registry.d.ts.map +1 -0
  85. package/dist/procedures/registry.js +240 -0
  86. package/dist/procedures/registry.js.map +1 -0
  87. package/dist/procedures/types.d.ts +103 -0
  88. package/dist/procedures/types.d.ts.map +1 -0
  89. package/dist/procedures/types.js +5 -0
  90. package/dist/procedures/types.js.map +1 -0
  91. package/dist/prompt-assembly/types.d.ts +80 -0
  92. package/dist/prompt-assembly/types.d.ts.map +1 -0
  93. package/dist/prompt-assembly/types.js +8 -0
  94. package/dist/prompt-assembly/types.js.map +1 -0
  95. package/dist/prompts/builder.md +191 -0
  96. package/dist/prompts/debugger.md +128 -0
  97. package/dist/prompts/graphite-orchestrator.md +362 -0
  98. package/dist/prompts/orchestrator.md +290 -0
  99. package/dist/prompts/scoper.md +95 -0
  100. package/dist/prompts/standard-issue-assigned-user-prompt.md +33 -0
  101. package/dist/prompts/subroutines/changelog-update.md +79 -0
  102. package/dist/prompts/subroutines/coding-activity.md +12 -0
  103. package/dist/prompts/subroutines/concise-summary.md +67 -0
  104. package/dist/prompts/subroutines/debugger-fix.md +92 -0
  105. package/dist/prompts/subroutines/debugger-reproduction.md +74 -0
  106. package/dist/prompts/subroutines/full-delegation.md +68 -0
  107. package/dist/prompts/subroutines/get-approval.md +175 -0
  108. package/dist/prompts/subroutines/gh-pr.md +80 -0
  109. package/dist/prompts/subroutines/git-commit.md +37 -0
  110. package/dist/prompts/subroutines/plan-summary.md +21 -0
  111. package/dist/prompts/subroutines/preparation.md +16 -0
  112. package/dist/prompts/subroutines/question-answer.md +8 -0
  113. package/dist/prompts/subroutines/question-investigation.md +8 -0
  114. package/dist/prompts/subroutines/release-execution.md +81 -0
  115. package/dist/prompts/subroutines/release-summary.md +60 -0
  116. package/dist/prompts/subroutines/user-testing-summary.md +87 -0
  117. package/dist/prompts/subroutines/user-testing.md +48 -0
  118. package/dist/prompts/subroutines/validation-fixer.md +56 -0
  119. package/dist/prompts/subroutines/verbose-summary.md +46 -0
  120. package/dist/prompts/subroutines/verifications.md +77 -0
  121. package/dist/prompts/todolist-system-prompt-extension.md +15 -0
  122. package/dist/sinks/IActivitySink.d.ts +60 -0
  123. package/dist/sinks/IActivitySink.d.ts.map +1 -0
  124. package/dist/sinks/IActivitySink.js +2 -0
  125. package/dist/sinks/IActivitySink.js.map +1 -0
  126. package/dist/sinks/LinearActivitySink.d.ts +69 -0
  127. package/dist/sinks/LinearActivitySink.d.ts.map +1 -0
  128. package/dist/sinks/LinearActivitySink.js +111 -0
  129. package/dist/sinks/LinearActivitySink.js.map +1 -0
  130. package/dist/sinks/NoopActivitySink.d.ts +13 -0
  131. package/dist/sinks/NoopActivitySink.d.ts.map +1 -0
  132. package/dist/sinks/NoopActivitySink.js +17 -0
  133. package/dist/sinks/NoopActivitySink.js.map +1 -0
  134. package/dist/sinks/index.d.ts +9 -0
  135. package/dist/sinks/index.d.ts.map +1 -0
  136. package/dist/sinks/index.js +8 -0
  137. package/dist/sinks/index.js.map +1 -0
  138. package/dist/types.d.ts +32 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/types.js +2 -0
  141. package/dist/types.js.map +1 -0
  142. package/dist/validation/ValidationLoopController.d.ts +54 -0
  143. package/dist/validation/ValidationLoopController.d.ts.map +1 -0
  144. package/dist/validation/ValidationLoopController.js +242 -0
  145. package/dist/validation/ValidationLoopController.js.map +1 -0
  146. package/dist/validation/index.d.ts +7 -0
  147. package/dist/validation/index.d.ts.map +1 -0
  148. package/dist/validation/index.js +7 -0
  149. package/dist/validation/index.js.map +1 -0
  150. package/dist/validation/types.d.ts +82 -0
  151. package/dist/validation/types.d.ts.map +1 -0
  152. package/dist/validation/types.js +29 -0
  153. package/dist/validation/types.js.map +1 -0
  154. package/label-prompt-template.md +27 -0
  155. package/package.json +56 -0
  156. package/prompt-template.md +116 -0
  157. package/prompts/builder.md +191 -0
  158. package/prompts/debugger.md +128 -0
  159. package/prompts/graphite-orchestrator.md +362 -0
  160. package/prompts/orchestrator.md +290 -0
  161. package/prompts/scoper.md +95 -0
  162. package/prompts/standard-issue-assigned-user-prompt.md +33 -0
  163. package/prompts/todolist-system-prompt-extension.md +15 -0
@@ -0,0 +1,480 @@
1
+ import { AgentActivitySignal, createLogger, } from "sylas-core";
2
+ /**
3
+ * RepositoryRouter handles all repository routing logic including:
4
+ * - Multi-priority routing (labels, projects, teams)
5
+ * - Issue-to-repository caching
6
+ * - Repository selection UI via Linear elicitation
7
+ * - Selection response handling
8
+ *
9
+ * This class was extracted from EdgeWorker to improve modularity and testability.
10
+ */
11
+ export class RepositoryRouter {
12
+ deps;
13
+ /** Cache mapping issue IDs to selected repository IDs */
14
+ issueRepositoryCache = new Map();
15
+ /** Pending repository selections awaiting user response */
16
+ pendingSelections = new Map();
17
+ logger;
18
+ constructor(deps, logger) {
19
+ this.deps = deps;
20
+ this.logger = logger ?? createLogger({ component: "RepositoryRouter" });
21
+ }
22
+ /**
23
+ * Get cached repository for an issue
24
+ *
25
+ * This is a simple cache lookup used by agentSessionPrompted webhooks (Branch 3).
26
+ * Per CLAUDE.md: "The repository will be retrieved from the issue-to-repository
27
+ * cache - no new routing logic is performed."
28
+ *
29
+ * @param issueId The Linear issue ID
30
+ * @param repositoriesMap Map of repository IDs to configurations
31
+ * @returns The cached repository or null if not found
32
+ */
33
+ getCachedRepository(issueId, repositoriesMap) {
34
+ const cachedRepositoryId = this.issueRepositoryCache.get(issueId);
35
+ if (!cachedRepositoryId) {
36
+ this.logger.debug(`No cached repository found for issue ${issueId}`);
37
+ return null;
38
+ }
39
+ const cachedRepository = repositoriesMap.get(cachedRepositoryId);
40
+ if (!cachedRepository) {
41
+ // Repository no longer exists, remove from cache
42
+ this.logger.warn(`Cached repository ${cachedRepositoryId} no longer exists, removing from cache`);
43
+ this.issueRepositoryCache.delete(issueId);
44
+ return null;
45
+ }
46
+ this.logger.debug(`Using cached repository ${cachedRepository.name} for issue ${issueId}`);
47
+ return cachedRepository;
48
+ }
49
+ /**
50
+ * Determine repository for webhook using multi-priority routing:
51
+ * Priority 0: Existing active sessions
52
+ * Priority 1: Description tag (explicit [repo=...] in issue description)
53
+ * Priority 2: Routing labels
54
+ * Priority 3: Project-based routing
55
+ * Priority 4: Team-based routing
56
+ * Priority 5: Catch-all repositories
57
+ */
58
+ async determineRepositoryForWebhook(webhook, repos) {
59
+ const workspaceId = webhook.organizationId;
60
+ if (!workspaceId) {
61
+ return repos[0]
62
+ ? {
63
+ type: "selected",
64
+ repository: repos[0],
65
+ routingMethod: "workspace-fallback",
66
+ }
67
+ : { type: "none" };
68
+ }
69
+ // Extract issue information
70
+ const { issueId, teamKey, issueIdentifier } = this.extractIssueInfo(webhook);
71
+ // Priority 0: Check for existing active sessions
72
+ // TODO: Remove this priority check - existing session detection should not be a routing method
73
+ if (issueId) {
74
+ for (const repo of repos) {
75
+ if (this.deps.hasActiveSession(issueId, repo.id)) {
76
+ this.logger.info(`Repository selected: ${repo.name} (existing active session)`);
77
+ return {
78
+ type: "selected",
79
+ repository: repo,
80
+ routingMethod: "workspace-fallback",
81
+ };
82
+ }
83
+ }
84
+ }
85
+ // Filter repos by workspace
86
+ const workspaceRepos = repos.filter((repo) => repo.linearWorkspaceId === workspaceId);
87
+ if (workspaceRepos.length === 0)
88
+ return { type: "none" };
89
+ // Priority 1: Check description tag [repo=...]
90
+ const descriptionTagRepo = await this.findRepositoryByDescriptionTag(issueId, workspaceRepos, workspaceId);
91
+ if (descriptionTagRepo) {
92
+ this.logger.info(`Repository selected: ${descriptionTagRepo.name} (description-tag routing)`);
93
+ return {
94
+ type: "selected",
95
+ repository: descriptionTagRepo,
96
+ routingMethod: "description-tag",
97
+ };
98
+ }
99
+ // Priority 2: Check routing labels
100
+ const labelMatchedRepo = await this.findRepositoryByLabels(issueId, workspaceRepos, workspaceId);
101
+ if (labelMatchedRepo) {
102
+ this.logger.info(`Repository selected: ${labelMatchedRepo.name} (label-based routing)`);
103
+ return {
104
+ type: "selected",
105
+ repository: labelMatchedRepo,
106
+ routingMethod: "label-based",
107
+ };
108
+ }
109
+ // Priority 3: Check project-based routing
110
+ if (issueId) {
111
+ const projectMatchedRepo = await this.findRepositoryByProject(issueId, workspaceRepos, workspaceId);
112
+ if (projectMatchedRepo) {
113
+ this.logger.info(`Repository selected: ${projectMatchedRepo.name} (project-based routing)`);
114
+ return {
115
+ type: "selected",
116
+ repository: projectMatchedRepo,
117
+ routingMethod: "project-based",
118
+ };
119
+ }
120
+ }
121
+ // Priority 4: Check team-based routing
122
+ if (teamKey) {
123
+ const teamMatchedRepo = this.findRepositoryByTeamKey(teamKey, workspaceRepos);
124
+ if (teamMatchedRepo) {
125
+ this.logger.info(`Repository selected: ${teamMatchedRepo.name} (team-based routing)`);
126
+ return {
127
+ type: "selected",
128
+ repository: teamMatchedRepo,
129
+ routingMethod: "team-based",
130
+ };
131
+ }
132
+ }
133
+ // Try parsing issue identifier as fallback for team routing
134
+ // TODO: Remove team prefix routing - should rely on explicit team-based routing only
135
+ if (issueIdentifier?.includes("-")) {
136
+ const prefix = issueIdentifier.split("-")[0];
137
+ if (prefix) {
138
+ const repo = this.findRepositoryByTeamKey(prefix, workspaceRepos);
139
+ if (repo) {
140
+ this.logger.info(`Repository selected: ${repo.name} (team prefix routing)`);
141
+ return {
142
+ type: "selected",
143
+ repository: repo,
144
+ routingMethod: "team-prefix",
145
+ };
146
+ }
147
+ }
148
+ }
149
+ // Priority 5: Find catch-all repository (no routing configuration)
150
+ // TODO: Remove catch-all routing - require explicit routing configuration for all repositories
151
+ const catchAllRepo = workspaceRepos.find((repo) => (!repo.teamKeys || repo.teamKeys.length === 0) &&
152
+ (!repo.routingLabels || repo.routingLabels.length === 0) &&
153
+ (!repo.projectKeys || repo.projectKeys.length === 0));
154
+ if (catchAllRepo) {
155
+ this.logger.info(`Repository selected: ${catchAllRepo.name} (workspace catch-all)`);
156
+ return {
157
+ type: "selected",
158
+ repository: catchAllRepo,
159
+ routingMethod: "catch-all",
160
+ };
161
+ }
162
+ // Multiple repositories with no routing match - request user selection
163
+ if (workspaceRepos.length > 1) {
164
+ this.logger.info(`Multiple repositories (${workspaceRepos.length}) found with no routing match - requesting user selection`);
165
+ return { type: "needs_selection", workspaceRepos };
166
+ }
167
+ // Final fallback to first workspace repo
168
+ const fallbackRepo = workspaceRepos[0];
169
+ if (fallbackRepo) {
170
+ this.logger.info(`Repository selected: ${fallbackRepo.name} (workspace fallback)`);
171
+ return {
172
+ type: "selected",
173
+ repository: fallbackRepo,
174
+ routingMethod: "workspace-fallback",
175
+ };
176
+ }
177
+ return { type: "none" };
178
+ }
179
+ /**
180
+ * Find repository by routing labels
181
+ */
182
+ async findRepositoryByLabels(issueId, repos, workspaceId) {
183
+ if (!issueId)
184
+ return null;
185
+ const reposWithRoutingLabels = repos.filter((repo) => repo.routingLabels && repo.routingLabels.length > 0);
186
+ if (reposWithRoutingLabels.length === 0)
187
+ return null;
188
+ try {
189
+ const labels = await this.deps.fetchIssueLabels(issueId, workspaceId);
190
+ for (const repo of reposWithRoutingLabels) {
191
+ if (repo.routingLabels?.some((routingLabel) => labels.includes(routingLabel))) {
192
+ return repo;
193
+ }
194
+ }
195
+ }
196
+ catch (error) {
197
+ this.logger.error(`Failed to fetch labels for routing:`, error);
198
+ }
199
+ return null;
200
+ }
201
+ /**
202
+ * Find repository by description tag
203
+ *
204
+ * Parses the issue description for a [repo=...] tag and matches against:
205
+ * - Repository GitHub URL (contains org/repo-name)
206
+ * - Repository name
207
+ * - Repository ID
208
+ *
209
+ * Example tags:
210
+ * - [repo=Trelent/lighthouse-financial-disclosure]
211
+ * - [repo=my-repo-name]
212
+ */
213
+ async findRepositoryByDescriptionTag(issueId, repos, workspaceId) {
214
+ if (!issueId)
215
+ return null;
216
+ try {
217
+ const description = await this.deps.fetchIssueDescription(issueId, workspaceId);
218
+ if (!description)
219
+ return null;
220
+ const repoTag = this.parseRepoTagFromDescription(description);
221
+ if (!repoTag)
222
+ return null;
223
+ this.logger.debug(`Found [repo=${repoTag}] tag in issue description`);
224
+ // Try to match against repositories
225
+ for (const repo of repos) {
226
+ // Match by GitHub URL containing the tag value (e.g., "org/repo-name")
227
+ if (repo.githubUrl?.includes(repoTag)) {
228
+ this.logger.debug(`Matched repo tag "${repoTag}" to repository ${repo.name} via GitHub URL`);
229
+ return repo;
230
+ }
231
+ // Match by repository name (exact match, case-insensitive)
232
+ if (repo.name.toLowerCase() === repoTag.toLowerCase()) {
233
+ this.logger.debug(`Matched repo tag "${repoTag}" to repository ${repo.name} via name`);
234
+ return repo;
235
+ }
236
+ // Match by repository ID
237
+ if (repo.id === repoTag) {
238
+ this.logger.debug(`Matched repo tag "${repoTag}" to repository ${repo.name} via ID`);
239
+ return repo;
240
+ }
241
+ }
242
+ this.logger.debug(`No repository matched [repo=${repoTag}] tag`);
243
+ }
244
+ catch (error) {
245
+ this.logger.error(`Failed to fetch description for routing:`, error);
246
+ }
247
+ return null;
248
+ }
249
+ /**
250
+ * Parse [repo=...] tag from issue description
251
+ *
252
+ * Supports various formats:
253
+ * - [repo=org/repo-name]
254
+ * - [repo=repo-name]
255
+ * - [repo=repo-id]
256
+ *
257
+ * Also handles escaped brackets (\\[repo=...\\]) which Linear may produce
258
+ * when the description contains markdown-escaped square brackets.
259
+ *
260
+ * Returns the tag value or null if not found.
261
+ */
262
+ parseRepoTagFromDescription(description) {
263
+ // Match [repo=...] pattern - captures everything between = and ]
264
+ // The pattern allows: alphanumeric, hyphens, underscores, forward slashes, dots
265
+ // Also handles escaped brackets (\\[ and \\]) that Linear may produce
266
+ const match = description.match(/\\?\[repo=([a-zA-Z0-9_\-/.]+)\\?\]/);
267
+ return match?.[1] ?? null;
268
+ }
269
+ /**
270
+ * Find repository by team key
271
+ */
272
+ findRepositoryByTeamKey(teamKey, repos) {
273
+ return repos.find((r) => r.teamKeys?.includes(teamKey));
274
+ }
275
+ /**
276
+ * Find repository by project name
277
+ */
278
+ async findRepositoryByProject(issueId, repos, workspaceId) {
279
+ // Try each repository that has projectKeys configured
280
+ for (const repo of repos) {
281
+ if (!repo.projectKeys || repo.projectKeys.length === 0)
282
+ continue;
283
+ try {
284
+ const issueTracker = this.deps.getIssueTracker(workspaceId);
285
+ if (!issueTracker) {
286
+ this.logger.warn(`No issue tracker found for workspace ${workspaceId}`);
287
+ continue;
288
+ }
289
+ const fullIssue = await issueTracker.fetchIssue(issueId);
290
+ const project = await fullIssue?.project;
291
+ if (!project || !project.name) {
292
+ this.logger.debug(`No project name found for issue ${issueId} in repository ${repo.name}`);
293
+ continue;
294
+ }
295
+ const projectName = project.name;
296
+ if (repo.projectKeys.includes(projectName)) {
297
+ this.logger.debug(`Matched issue ${issueId} to repository ${repo.name} via project: ${projectName}`);
298
+ return repo;
299
+ }
300
+ }
301
+ catch (error) {
302
+ // Continue to next repository if this one fails
303
+ this.logger.debug(`Failed to fetch project for issue ${issueId} from repository ${repo.name}:`, error);
304
+ }
305
+ }
306
+ return null;
307
+ }
308
+ /**
309
+ * Elicit user repository selection - post elicitation to Linear
310
+ */
311
+ async elicitUserRepositorySelection(webhook, workspaceRepos) {
312
+ const { agentSession } = webhook;
313
+ const agentSessionId = agentSession.id;
314
+ const { issue } = agentSession;
315
+ if (!issue) {
316
+ this.logger.error("Cannot elicit repository selection without issue");
317
+ return;
318
+ }
319
+ this.logger.info(`Posting repository selection elicitation for issue ${issue.identifier}`);
320
+ // Store pending selection
321
+ this.pendingSelections.set(agentSessionId, {
322
+ issueId: issue.id,
323
+ workspaceRepos,
324
+ });
325
+ // Validate we have repositories to offer
326
+ const firstRepo = workspaceRepos[0];
327
+ if (!firstRepo) {
328
+ this.logger.error("No repositories available for selection elicitation");
329
+ return;
330
+ }
331
+ // Get issue tracker for the workspace
332
+ const issueTracker = this.deps.getIssueTracker(webhook.organizationId);
333
+ if (!issueTracker) {
334
+ this.logger.error(`No issue tracker found for workspace ${webhook.organizationId}`);
335
+ return;
336
+ }
337
+ // Create repository options
338
+ const options = workspaceRepos.map((repo) => ({
339
+ value: repo.githubUrl || repo.name,
340
+ }));
341
+ // Post elicitation activity
342
+ try {
343
+ await issueTracker.createAgentActivity({
344
+ agentSessionId,
345
+ content: {
346
+ type: "elicitation",
347
+ body: "Which repository should I work in for this issue?",
348
+ },
349
+ signal: AgentActivitySignal.Select,
350
+ signalMetadata: { options },
351
+ });
352
+ this.logger.info(`Posted repository selection elicitation with ${options.length} options`);
353
+ }
354
+ catch (error) {
355
+ this.logger.error(`Failed to post repository selection elicitation:`, error);
356
+ await this.postRepositorySelectionError(agentSessionId, issueTracker, error);
357
+ this.pendingSelections.delete(agentSessionId);
358
+ }
359
+ }
360
+ /**
361
+ * Post error activity when repository selection fails
362
+ */
363
+ async postRepositorySelectionError(agentSessionId, issueTracker, error) {
364
+ const errorObj = error;
365
+ const errorMessage = errorObj?.message || String(error);
366
+ try {
367
+ await issueTracker.createAgentActivity({
368
+ agentSessionId,
369
+ content: {
370
+ type: "error",
371
+ body: `Failed to display repository selection: ${errorMessage}`,
372
+ },
373
+ });
374
+ this.logger.info(`Posted error activity for repository selection failure`);
375
+ }
376
+ catch (postError) {
377
+ this.logger.error(`Failed to post error activity (may be due to same underlying issue):`, postError);
378
+ }
379
+ }
380
+ /**
381
+ * Select repository from user response
382
+ * Returns the selected repository or null if webhook should not be processed further
383
+ */
384
+ async selectRepositoryFromResponse(agentSessionId, selectedRepositoryName) {
385
+ const pendingData = this.pendingSelections.get(agentSessionId);
386
+ if (!pendingData) {
387
+ this.logger.debug(`No pending repository selection found for agent session ${agentSessionId}`);
388
+ return null;
389
+ }
390
+ // Remove from pending map
391
+ this.pendingSelections.delete(agentSessionId);
392
+ // Find selected repository by GitHub URL or name
393
+ const selectedRepo = pendingData.workspaceRepos.find((repo) => repo.githubUrl === selectedRepositoryName ||
394
+ repo.name === selectedRepositoryName);
395
+ // Fallback to first repository if not found
396
+ const repository = selectedRepo || pendingData.workspaceRepos[0];
397
+ if (!repository) {
398
+ this.logger.error(`No repository found for selection: ${selectedRepositoryName}`);
399
+ return null;
400
+ }
401
+ if (!selectedRepo) {
402
+ this.logger.info(`Repository "${selectedRepositoryName}" not found, falling back to ${repository.name}`);
403
+ }
404
+ else {
405
+ this.logger.info(`User selected repository: ${repository.name}`);
406
+ }
407
+ return repository;
408
+ }
409
+ /**
410
+ * Check if there's a pending repository selection for this agent session
411
+ */
412
+ hasPendingSelection(agentSessionId) {
413
+ return this.pendingSelections.has(agentSessionId);
414
+ }
415
+ /**
416
+ * Extract issue information from webhook
417
+ */
418
+ extractIssueInfo(webhook) {
419
+ // Handle agent session webhooks
420
+ if (this.isAgentSessionCreatedWebhook(webhook) ||
421
+ this.isAgentSessionPromptedWebhook(webhook)) {
422
+ return {
423
+ issueId: webhook.agentSession?.issue?.id,
424
+ teamKey: webhook.agentSession?.issue?.team?.key,
425
+ issueIdentifier: webhook.agentSession?.issue?.identifier,
426
+ };
427
+ }
428
+ // Handle entity webhooks (e.g., Issue updates)
429
+ if (this.isEntityWebhook(webhook)) {
430
+ // For Issue entity webhooks, data contains the issue payload
431
+ if (webhook.type === "Issue") {
432
+ const issueData = webhook.data;
433
+ return {
434
+ issueId: issueData?.id,
435
+ teamKey: issueData?.team?.key,
436
+ issueIdentifier: issueData?.identifier,
437
+ };
438
+ }
439
+ // Other entity types don't have issue info
440
+ return {};
441
+ }
442
+ // Handle notification webhooks (AppUserNotification)
443
+ if ("notification" in webhook && webhook.notification) {
444
+ return {
445
+ issueId: webhook.notification?.issue?.id,
446
+ teamKey: webhook.notification?.issue?.team?.key,
447
+ issueIdentifier: webhook.notification?.issue?.identifier,
448
+ };
449
+ }
450
+ return {};
451
+ }
452
+ /**
453
+ * Type guard for entity webhooks (Issue, Comment, etc.)
454
+ */
455
+ isEntityWebhook(webhook) {
456
+ return "data" in webhook && webhook.data !== undefined;
457
+ }
458
+ /**
459
+ * Type guards
460
+ */
461
+ isAgentSessionCreatedWebhook(webhook) {
462
+ return webhook.action === "created";
463
+ }
464
+ isAgentSessionPromptedWebhook(webhook) {
465
+ return webhook.action === "prompted";
466
+ }
467
+ /**
468
+ * Get issue repository cache for serialization
469
+ */
470
+ getIssueRepositoryCache() {
471
+ return this.issueRepositoryCache;
472
+ }
473
+ /**
474
+ * Restore issue repository cache from serialization
475
+ */
476
+ restoreIssueRepositoryCache(cache) {
477
+ this.issueRepositoryCache = cache;
478
+ }
479
+ }
480
+ //# sourceMappingURL=RepositoryRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RepositoryRouter.js","sourceRoot":"","sources":["../src/RepositoryRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { EdgeWorkerConfig, ILogger, RepositoryConfig, SylasAgentSession } from "sylas-core";
2
+ import type { ProcedureAnalyzer } from "./procedures/index.js";
3
+ export declare class RunnerSelectionService {
4
+ private config;
5
+ private logger;
6
+ constructor(config: EdgeWorkerConfig, logger: ILogger);
7
+ /**
8
+ * Resolve default model for a given runner from config with sensible built-in defaults.
9
+ */
10
+ getDefaultModelForRunner(runnerType: "claude" | "gemini" | "codex" | "cursor" | "opencode"): string;
11
+ /**
12
+ * Resolve default fallback model for a given runner from config with sensible built-in defaults.
13
+ * Supports legacy Claude fallback key for backwards compatibility.
14
+ */
15
+ getDefaultFallbackModelForRunner(runnerType: "claude" | "gemini" | "codex" | "cursor" | "opencode"): string;
16
+ /**
17
+ * Parse a bracketed tag from issue description.
18
+ *
19
+ * Supports escaped brackets (`\\[tag=value\\]`) which Linear can emit.
20
+ */
21
+ parseDescriptionTag(description: string, tagName: string): string | undefined;
22
+ /**
23
+ * Determine runner type and model using labels + issue description tags.
24
+ *
25
+ * Supported description tags:
26
+ * - [agent=claude|gemini|codex|cursor|opencode]
27
+ * - [model=<model-name>]
28
+ *
29
+ * Precedence:
30
+ * 1. Description tags override labels
31
+ * 2. Agent labels override model labels
32
+ * 3. Model labels can infer agent type
33
+ * 4. Defaults to opencode runner
34
+ */
35
+ determineRunnerSelection(labels: string[], issueDescription?: string): {
36
+ runnerType: "claude" | "gemini" | "codex" | "cursor" | "opencode";
37
+ modelOverride?: string;
38
+ fallbackModelOverride?: string;
39
+ };
40
+ /**
41
+ * Resolve a tool preset string to an array of tool names.
42
+ */
43
+ resolveToolPreset(preset: string | string[]): string[];
44
+ /**
45
+ * Build allowed tools list with Linear MCP tools automatically included
46
+ */
47
+ buildAllowedTools(repository: RepositoryConfig, promptType?: "debugger" | "builder" | "scoper" | "orchestrator" | "graphite-orchestrator"): string[];
48
+ /**
49
+ * Build disallowed tools list from repository and global config
50
+ */
51
+ buildDisallowedTools(repository: RepositoryConfig, promptType?: "debugger" | "builder" | "scoper" | "orchestrator" | "graphite-orchestrator"): string[];
52
+ /**
53
+ * Merge subroutine-level disallowedTools with base disallowedTools
54
+ * @param session Current agent session
55
+ * @param baseDisallowedTools Base disallowed tools from repository/global config
56
+ * @param logContext Context string for logging (e.g., "EdgeWorker", "resumeClaudeSession")
57
+ * @param procedureAnalyzer ProcedureAnalyzer instance to resolve current subroutine
58
+ * @returns Merged disallowed tools list
59
+ */
60
+ mergeSubroutineDisallowedTools(session: SylasAgentSession, baseDisallowedTools: string[], logContext: string, procedureAnalyzer: ProcedureAnalyzer): string[];
61
+ }
62
+ //# sourceMappingURL=RunnerSelectionService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RunnerSelectionService.d.ts","sourceRoot":"","sources":["../src/RunnerSelectionService.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,gBAAgB,EAChB,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,qBAAa,sBAAsB;IAClC,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAU;gBAEZ,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO;IAKrD;;OAEG;IACI,wBAAwB,CAC9B,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAC/D,MAAM;IAsBT;;;OAGG;IACI,gCAAgC,CACtC,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAC/D,MAAM;IAwBT;;;;OAIG;IACI,mBAAmB,CACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACb,MAAM,GAAG,SAAS;IAUrB;;;;;;;;;;;;OAYG;IACI,wBAAwB,CAC9B,MAAM,EAAE,MAAM,EAAE,EAChB,gBAAgB,CAAC,EAAE,MAAM,GACvB;QACF,UAAU,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;QAClE,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAC/B;IA+MD;;OAEG;IACI,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE;IAoB7D;;OAEG;IACI,iBAAiB,CACvB,UAAU,EAAE,gBAAgB,EAC5B,UAAU,CAAC,EACR,UAAU,GACV,SAAS,GACT,QAAQ,GACR,cAAc,GACd,uBAAuB,GACxB,MAAM,EAAE;IA6DX;;OAEG;IACI,oBAAoB,CAC1B,UAAU,EAAE,gBAAgB,EAC5B,UAAU,CAAC,EACR,UAAU,GACV,SAAS,GACT,QAAQ,GACR,cAAc,GACd,uBAAuB,GACxB,MAAM,EAAE;IAuDX;;;;;;;OAOG;IACI,8BAA8B,CACpC,OAAO,EAAE,iBAAiB,EAC1B,mBAAmB,EAAE,MAAM,EAAE,EAC7B,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,iBAAiB,GAClC,MAAM,EAAE;CAiBX"}