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,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"}
|