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,247 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
import { CloudflareTunnelClient } from "sylas-cloudflare-tunnel-client";
|
|
3
|
+
import { createLogger } from "sylas-core";
|
|
4
|
+
/**
|
|
5
|
+
* Shared application server that handles both webhooks and OAuth callbacks on a single port
|
|
6
|
+
* Consolidates functionality from SharedWebhookServer and CLI OAuth server
|
|
7
|
+
*/
|
|
8
|
+
export class SharedApplicationServer {
|
|
9
|
+
app = null;
|
|
10
|
+
webhookHandlers = new Map();
|
|
11
|
+
// Legacy handlers for direct Linear webhook registration (deprecated)
|
|
12
|
+
linearWebhookHandlers = new Map();
|
|
13
|
+
oauthCallbacks = new Map();
|
|
14
|
+
pendingApprovals = new Map();
|
|
15
|
+
port;
|
|
16
|
+
host;
|
|
17
|
+
isListening = false;
|
|
18
|
+
tunnelClient = null;
|
|
19
|
+
skipTunnel;
|
|
20
|
+
logger;
|
|
21
|
+
constructor(port = 3456, host = "localhost", skipTunnel = false, logger) {
|
|
22
|
+
this.port = port;
|
|
23
|
+
this.host = host;
|
|
24
|
+
this.skipTunnel = skipTunnel;
|
|
25
|
+
this.logger =
|
|
26
|
+
logger ?? createLogger({ component: "SharedApplicationServer" });
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initialize the Fastify app instance (must be called before registering routes)
|
|
30
|
+
*/
|
|
31
|
+
initializeFastify() {
|
|
32
|
+
if (this.app) {
|
|
33
|
+
return; // Already initialized
|
|
34
|
+
}
|
|
35
|
+
this.app = Fastify({
|
|
36
|
+
logger: false,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Start the shared application server
|
|
41
|
+
*/
|
|
42
|
+
async start() {
|
|
43
|
+
if (this.isListening) {
|
|
44
|
+
return; // Already listening
|
|
45
|
+
}
|
|
46
|
+
// Initialize Fastify if not already done
|
|
47
|
+
this.initializeFastify();
|
|
48
|
+
try {
|
|
49
|
+
await this.app.listen({
|
|
50
|
+
port: this.port,
|
|
51
|
+
host: this.host,
|
|
52
|
+
});
|
|
53
|
+
this.isListening = true;
|
|
54
|
+
this.logger.info(`Shared application server listening on http://${this.host}:${this.port}`);
|
|
55
|
+
// Start Cloudflare tunnel if CLOUDFLARE_TOKEN is set and tunnel is not skipped
|
|
56
|
+
if (!this.skipTunnel && process.env.CLOUDFLARE_TOKEN) {
|
|
57
|
+
await this.startCloudflareTunnel(process.env.CLOUDFLARE_TOKEN);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
this.isListening = false;
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start Cloudflare tunnel and wait for 4 'connected' events
|
|
67
|
+
*/
|
|
68
|
+
async startCloudflareTunnel(cloudflareToken) {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
let connectionCount = 0;
|
|
71
|
+
const requiredConnections = 4;
|
|
72
|
+
this.tunnelClient = new CloudflareTunnelClient(cloudflareToken, this.port);
|
|
73
|
+
// Listen for connection events (Cloudflare establishes 4 connections per tunnel)
|
|
74
|
+
this.tunnelClient.on("connected", () => {
|
|
75
|
+
connectionCount++;
|
|
76
|
+
this.logger.info(`Cloudflare tunnel connection ${connectionCount}/${requiredConnections} established`);
|
|
77
|
+
if (connectionCount === requiredConnections) {
|
|
78
|
+
this.logger.info("Cloudflare tunnel fully connected and ready");
|
|
79
|
+
resolve();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Listen for ready event to get tunnel URL
|
|
83
|
+
this.tunnelClient.on("ready", (tunnelUrl) => {
|
|
84
|
+
this.logger.info(`Cloudflare tunnel URL: ${tunnelUrl}`);
|
|
85
|
+
});
|
|
86
|
+
// Listen for error events
|
|
87
|
+
this.tunnelClient.on("error", (error) => {
|
|
88
|
+
this.logger.error("Cloudflare tunnel error:", error);
|
|
89
|
+
reject(error);
|
|
90
|
+
});
|
|
91
|
+
// Listen for disconnect events
|
|
92
|
+
this.tunnelClient.on("disconnect", (reason) => {
|
|
93
|
+
this.logger.info(`Cloudflare tunnel disconnected: ${reason}`);
|
|
94
|
+
});
|
|
95
|
+
// Start the tunnel
|
|
96
|
+
this.tunnelClient.startTunnel().catch(reject);
|
|
97
|
+
// Timeout after 30 seconds
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
if (connectionCount < requiredConnections) {
|
|
100
|
+
reject(new Error(`Timeout waiting for Cloudflare tunnel (${connectionCount}/${requiredConnections} connections). This is usually caused by firewall/VPN/proxy blocking cloudflared. See troubleshooting: https://github.com/smilebank7/sylas/blob/main/docs/CLOUDFLARE_TUNNEL.md#troubleshooting`));
|
|
101
|
+
}
|
|
102
|
+
}, 30000);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Stop the shared application server
|
|
107
|
+
*/
|
|
108
|
+
async stop() {
|
|
109
|
+
// Reject all pending approvals before shutdown
|
|
110
|
+
for (const [sessionId, approval] of this.pendingApprovals) {
|
|
111
|
+
approval.reject(new Error("Server shutting down"));
|
|
112
|
+
this.logger.debug(`Rejected pending approval for session ${sessionId} due to shutdown`);
|
|
113
|
+
}
|
|
114
|
+
this.pendingApprovals.clear();
|
|
115
|
+
// Stop Cloudflare tunnel if running
|
|
116
|
+
if (this.tunnelClient) {
|
|
117
|
+
this.tunnelClient.disconnect();
|
|
118
|
+
this.tunnelClient = null;
|
|
119
|
+
this.logger.info("Cloudflare tunnel stopped");
|
|
120
|
+
}
|
|
121
|
+
if (this.app && this.isListening) {
|
|
122
|
+
await this.app.close();
|
|
123
|
+
this.isListening = false;
|
|
124
|
+
this.logger.info("Shared application server stopped");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the port number the server is listening on
|
|
129
|
+
*/
|
|
130
|
+
getPort() {
|
|
131
|
+
return this.port;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get the Fastify instance for registering routes
|
|
135
|
+
* Initializes Fastify if not already done
|
|
136
|
+
*/
|
|
137
|
+
getFastifyInstance() {
|
|
138
|
+
this.initializeFastify();
|
|
139
|
+
return this.app;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Register a webhook handler for a specific token (LEGACY - deprecated)
|
|
143
|
+
* Supports two signatures:
|
|
144
|
+
* 1. For ndjson-client: (token, secret, handler)
|
|
145
|
+
* 2. For legacy direct registration: (token, handler) where handler takes (req, res)
|
|
146
|
+
*
|
|
147
|
+
* NOTE: New code should use LinearEventTransport which registers routes directly with Fastify
|
|
148
|
+
*/
|
|
149
|
+
registerWebhookHandler(token, secretOrHandler, handler) {
|
|
150
|
+
if (typeof secretOrHandler === "string" && handler) {
|
|
151
|
+
// ndjson-client style registration
|
|
152
|
+
this.webhookHandlers.set(token, { secret: secretOrHandler, handler });
|
|
153
|
+
this.logger.debug(`Registered webhook handler (proxy-style) for token ending in ...${token.slice(-4)}`);
|
|
154
|
+
}
|
|
155
|
+
else if (typeof secretOrHandler === "function") {
|
|
156
|
+
// Legacy direct registration
|
|
157
|
+
this.linearWebhookHandlers.set(token, secretOrHandler);
|
|
158
|
+
this.logger.debug(`Registered webhook handler (legacy direct-style) for token ending in ...${token.slice(-4)}`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
throw new Error("Invalid webhook handler registration parameters");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Unregister a webhook handler
|
|
166
|
+
*/
|
|
167
|
+
unregisterWebhookHandler(token) {
|
|
168
|
+
const hadProxyHandler = this.webhookHandlers.delete(token);
|
|
169
|
+
const hadDirectHandler = this.linearWebhookHandlers.delete(token);
|
|
170
|
+
if (hadProxyHandler || hadDirectHandler) {
|
|
171
|
+
this.logger.debug(`Unregistered webhook handler for token ending in ...${token.slice(-4)}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Start OAuth flow and return promise that resolves when callback is received
|
|
176
|
+
*/
|
|
177
|
+
async startOAuthFlow(proxyUrl) {
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
// Generate unique ID for this flow
|
|
180
|
+
const flowId = Date.now().toString();
|
|
181
|
+
// Store callback for this flow
|
|
182
|
+
this.oauthCallbacks.set(flowId, { resolve, reject, id: flowId });
|
|
183
|
+
// Check if we should use direct Linear OAuth (when self-hosting)
|
|
184
|
+
const isExternalHost = process.env.SYLAS_HOST_EXTERNAL?.toLowerCase().trim() === "true";
|
|
185
|
+
const useDirectOAuth = isExternalHost && process.env.LINEAR_CLIENT_ID;
|
|
186
|
+
const callbackBaseUrl = `http://${this.host}:${this.port}`;
|
|
187
|
+
let authUrl;
|
|
188
|
+
if (useDirectOAuth) {
|
|
189
|
+
// Use local OAuth authorize endpoint
|
|
190
|
+
authUrl = `${callbackBaseUrl}/oauth/authorize?callback=${encodeURIComponent(`${callbackBaseUrl}/callback`)}`;
|
|
191
|
+
this.logger.info(`Using direct OAuth mode (SYLAS_HOST_EXTERNAL=true)`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
// Use proxy OAuth endpoint
|
|
195
|
+
authUrl = `${proxyUrl}/oauth/authorize?callback=${encodeURIComponent(`${callbackBaseUrl}/callback`)}`;
|
|
196
|
+
}
|
|
197
|
+
this.logger.info(`Opening your browser to authorize with Linear...`);
|
|
198
|
+
this.logger.info(`If the browser doesn't open, visit: ${authUrl}`);
|
|
199
|
+
// Timeout after 5 minutes
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
if (this.oauthCallbacks.has(flowId)) {
|
|
202
|
+
this.oauthCallbacks.delete(flowId);
|
|
203
|
+
reject(new Error("OAuth timeout"));
|
|
204
|
+
}
|
|
205
|
+
}, 5 * 60 * 1000);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get the webhook URL
|
|
210
|
+
*/
|
|
211
|
+
getWebhookUrl() {
|
|
212
|
+
return `http://${this.host}:${this.port}/webhook`;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get the OAuth callback URL for registration with proxy
|
|
216
|
+
*/
|
|
217
|
+
getOAuthCallbackUrl() {
|
|
218
|
+
return `http://${this.host}:${this.port}/callback`;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Register an approval request and get approval URL
|
|
222
|
+
*/
|
|
223
|
+
registerApprovalRequest(sessionId) {
|
|
224
|
+
// Clean up expired approvals (older than 30 minutes)
|
|
225
|
+
const now = Date.now();
|
|
226
|
+
for (const [key, approval] of this.pendingApprovals) {
|
|
227
|
+
if (now - approval.createdAt > 30 * 60 * 1000) {
|
|
228
|
+
approval.reject(new Error("Approval request expired"));
|
|
229
|
+
this.pendingApprovals.delete(key);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Create promise for this approval request
|
|
233
|
+
const promise = new Promise((resolve, reject) => {
|
|
234
|
+
this.pendingApprovals.set(sessionId, {
|
|
235
|
+
resolve: (approved, feedback) => resolve({ approved, feedback }),
|
|
236
|
+
reject,
|
|
237
|
+
sessionId,
|
|
238
|
+
createdAt: now,
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
// Generate approval URL
|
|
242
|
+
const url = `http://${this.host}:${this.port}/approval?session=${encodeURIComponent(sessionId)}`;
|
|
243
|
+
this.logger.debug(`Registered approval request for session ${sessionId}: ${url}`);
|
|
244
|
+
return { promise, url };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=SharedApplicationServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedApplicationServer.js","sourceRoot":"","sources":["../src/SharedApplicationServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ILogger } from "sylas-core";
|
|
2
|
+
/**
|
|
3
|
+
* Shared webhook server that can handle multiple Linear tokens
|
|
4
|
+
* Each token has its own webhook secret for signature verification
|
|
5
|
+
*/
|
|
6
|
+
export declare class SharedWebhookServer {
|
|
7
|
+
private server;
|
|
8
|
+
private webhookHandlers;
|
|
9
|
+
private port;
|
|
10
|
+
private host;
|
|
11
|
+
private isListening;
|
|
12
|
+
private logger;
|
|
13
|
+
constructor(port?: number, host?: string, logger?: ILogger);
|
|
14
|
+
/**
|
|
15
|
+
* Start the shared webhook server
|
|
16
|
+
*/
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Stop the shared webhook server
|
|
20
|
+
*/
|
|
21
|
+
stop(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Register a webhook handler for a specific token
|
|
24
|
+
*/
|
|
25
|
+
registerWebhookHandler(token: string, secret: string, handler: (body: string, signature: string, timestamp?: string) => boolean): void;
|
|
26
|
+
/**
|
|
27
|
+
* Unregister a webhook handler
|
|
28
|
+
*/
|
|
29
|
+
unregisterWebhookHandler(token: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get the webhook URL for registration with proxy
|
|
32
|
+
*/
|
|
33
|
+
getWebhookUrl(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Handle incoming webhook requests
|
|
36
|
+
*/
|
|
37
|
+
private handleWebhookRequest;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=SharedWebhookServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedWebhookServer.d.ts","sourceRoot":"","sources":["../src/SharedWebhookServer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD;;;GAGG;AACH,qBAAa,mBAAmB;IAC/B,OAAO,CAAC,MAAM,CAAgD;IAC9D,OAAO,CAAC,eAAe,CAMnB;IACJ,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAU;gBAGvB,IAAI,GAAE,MAAa,EACnB,IAAI,GAAE,MAAoB,EAC1B,MAAM,CAAC,EAAE,OAAO;IAOjB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyB5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;OAEG;IACH,sBAAsB,CACrB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,GACvE,IAAI;IAOP;;OAEG;IACH,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAO7C;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;YACW,oBAAoB;CAyFlC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { createServer, } from "node:http";
|
|
2
|
+
import { createLogger } from "sylas-core";
|
|
3
|
+
/**
|
|
4
|
+
* Shared webhook server that can handle multiple Linear tokens
|
|
5
|
+
* Each token has its own webhook secret for signature verification
|
|
6
|
+
*/
|
|
7
|
+
export class SharedWebhookServer {
|
|
8
|
+
server = null;
|
|
9
|
+
webhookHandlers = new Map();
|
|
10
|
+
port;
|
|
11
|
+
host;
|
|
12
|
+
isListening = false;
|
|
13
|
+
logger;
|
|
14
|
+
constructor(port = 3456, host = "localhost", logger) {
|
|
15
|
+
this.port = port;
|
|
16
|
+
this.host = host;
|
|
17
|
+
this.logger = logger ?? createLogger({ component: "SharedWebhookServer" });
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Start the shared webhook server
|
|
21
|
+
*/
|
|
22
|
+
async start() {
|
|
23
|
+
if (this.isListening) {
|
|
24
|
+
return; // Already listening
|
|
25
|
+
}
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
this.server = createServer((req, res) => {
|
|
28
|
+
this.handleWebhookRequest(req, res);
|
|
29
|
+
});
|
|
30
|
+
this.server.listen(this.port, this.host, () => {
|
|
31
|
+
this.isListening = true;
|
|
32
|
+
this.logger.info(`Shared webhook server listening on http://${this.host}:${this.port}`);
|
|
33
|
+
resolve();
|
|
34
|
+
});
|
|
35
|
+
this.server.on("error", (error) => {
|
|
36
|
+
this.isListening = false;
|
|
37
|
+
reject(error);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Stop the shared webhook server
|
|
43
|
+
*/
|
|
44
|
+
async stop() {
|
|
45
|
+
if (this.server && this.isListening) {
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
this.server.close(() => {
|
|
48
|
+
this.isListening = false;
|
|
49
|
+
this.logger.info("Shared webhook server stopped");
|
|
50
|
+
resolve();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Register a webhook handler for a specific token
|
|
57
|
+
*/
|
|
58
|
+
registerWebhookHandler(token, secret, handler) {
|
|
59
|
+
this.webhookHandlers.set(token, { secret, handler });
|
|
60
|
+
this.logger.info(`Registered webhook handler for token ending in ...${token.slice(-4)}`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Unregister a webhook handler
|
|
64
|
+
*/
|
|
65
|
+
unregisterWebhookHandler(token) {
|
|
66
|
+
this.webhookHandlers.delete(token);
|
|
67
|
+
this.logger.info(`Unregistered webhook handler for token ending in ...${token.slice(-4)}`);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the webhook URL for registration with proxy
|
|
71
|
+
*/
|
|
72
|
+
getWebhookUrl() {
|
|
73
|
+
return `http://${this.host}:${this.port}/webhook`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Handle incoming webhook requests
|
|
77
|
+
*/
|
|
78
|
+
async handleWebhookRequest(req, res) {
|
|
79
|
+
try {
|
|
80
|
+
this.logger.debug(`Incoming webhook request: ${req.method} ${req.url}`);
|
|
81
|
+
if (req.method !== "POST") {
|
|
82
|
+
this.logger.debug(`Rejected non-POST request: ${req.method}`);
|
|
83
|
+
res.writeHead(405, { "Content-Type": "text/plain" });
|
|
84
|
+
res.end("Method Not Allowed");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (req.url !== "/webhook") {
|
|
88
|
+
this.logger.debug(`Rejected request to wrong URL: ${req.url}`);
|
|
89
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
90
|
+
res.end("Not Found");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Read request body
|
|
94
|
+
let body = "";
|
|
95
|
+
req.on("data", (chunk) => {
|
|
96
|
+
body += chunk.toString();
|
|
97
|
+
});
|
|
98
|
+
req.on("end", () => {
|
|
99
|
+
try {
|
|
100
|
+
const signature = req.headers["x-webhook-signature"];
|
|
101
|
+
const timestamp = req.headers["x-webhook-timestamp"];
|
|
102
|
+
this.logger.debug(`Webhook received with ${body.length} bytes, ${this.webhookHandlers.size} registered handlers`);
|
|
103
|
+
if (!signature) {
|
|
104
|
+
this.logger.debug("Webhook rejected: Missing signature header");
|
|
105
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
106
|
+
res.end("Missing signature");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Try each registered handler until one verifies the signature
|
|
110
|
+
let handlerAttempts = 0;
|
|
111
|
+
for (const [token, { handler }] of this.webhookHandlers) {
|
|
112
|
+
handlerAttempts++;
|
|
113
|
+
try {
|
|
114
|
+
if (handler(body, signature, timestamp)) {
|
|
115
|
+
// Handler verified signature and processed webhook
|
|
116
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
117
|
+
res.end("OK");
|
|
118
|
+
this.logger.debug(`Webhook delivered to token ending in ...${token.slice(-4)} (attempt ${handlerAttempts}/${this.webhookHandlers.size})`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
this.logger.error(`Error in webhook handler for token ...${token.slice(-4)}:`, error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// No handler could verify the signature
|
|
127
|
+
this.logger.error(`Webhook signature verification failed for all ${this.webhookHandlers.size} registered handlers`);
|
|
128
|
+
res.writeHead(401, { "Content-Type": "text/plain" });
|
|
129
|
+
res.end("Unauthorized");
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
this.logger.error("Error processing webhook:", error);
|
|
133
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
134
|
+
res.end("Bad Request");
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
req.on("error", (error) => {
|
|
138
|
+
this.logger.error("Request error:", error);
|
|
139
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
140
|
+
res.end("Internal Server Error");
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
this.logger.error("Webhook request error:", error);
|
|
145
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
146
|
+
res.end("Internal Server Error");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=SharedWebhookServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SharedWebhookServer.js","sourceRoot":"","sources":["../src/SharedWebhookServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IAgentRunner, ILogger } from "sylas-core";
|
|
2
|
+
import { type SlackWebhookEvent } from "sylas-slack-event-transport";
|
|
3
|
+
import type { ChatPlatformAdapter } from "./ChatSessionHandler.js";
|
|
4
|
+
/**
|
|
5
|
+
* Slack implementation of ChatPlatformAdapter.
|
|
6
|
+
*
|
|
7
|
+
* Contains all Slack-specific logic extracted from EdgeWorker:
|
|
8
|
+
* text extraction, thread keys, system prompts, thread context,
|
|
9
|
+
* reply posting, and acknowledgement reactions.
|
|
10
|
+
*/
|
|
11
|
+
export declare class SlackChatAdapter implements ChatPlatformAdapter<SlackWebhookEvent> {
|
|
12
|
+
readonly platformName: "slack";
|
|
13
|
+
private logger;
|
|
14
|
+
constructor(logger?: ILogger);
|
|
15
|
+
extractTaskInstructions(event: SlackWebhookEvent): string;
|
|
16
|
+
getThreadKey(event: SlackWebhookEvent): string;
|
|
17
|
+
getEventId(event: SlackWebhookEvent): string;
|
|
18
|
+
buildSystemPrompt(event: SlackWebhookEvent): string;
|
|
19
|
+
fetchThreadContext(event: SlackWebhookEvent): Promise<string>;
|
|
20
|
+
postReply(event: SlackWebhookEvent, runner: IAgentRunner): Promise<void>;
|
|
21
|
+
acknowledgeReceipt(event: SlackWebhookEvent): Promise<void>;
|
|
22
|
+
notifyBusy(event: SlackWebhookEvent): Promise<void>;
|
|
23
|
+
private formatThreadContext;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=SlackChatAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlackChatAdapter.d.ts","sourceRoot":"","sources":["../src/SlackChatAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAIN,KAAK,iBAAiB,EAEtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE;;;;;;GAMG;AACH,qBAAa,gBACZ,YAAW,mBAAmB,CAAC,iBAAiB,CAAC;IAEjD,QAAQ,CAAC,YAAY,EAAG,OAAO,CAAU;IACzC,OAAO,CAAC,MAAM,CAAU;gBAEZ,MAAM,CAAC,EAAE,OAAO;IAI5B,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM;IAMzD,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM;IAK9C,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM;IAI5C,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM;IAe7C,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IA2C7D,SAAS,CACd,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC;IAqDV,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3D,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAezD,OAAO,CAAC,mBAAmB;CAgB3B"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createLogger } from "sylas-core";
|
|
2
|
+
import { SlackMessageService, SlackReactionService, stripMention as stripSlackMention, } from "sylas-slack-event-transport";
|
|
3
|
+
/**
|
|
4
|
+
* Slack implementation of ChatPlatformAdapter.
|
|
5
|
+
*
|
|
6
|
+
* Contains all Slack-specific logic extracted from EdgeWorker:
|
|
7
|
+
* text extraction, thread keys, system prompts, thread context,
|
|
8
|
+
* reply posting, and acknowledgement reactions.
|
|
9
|
+
*/
|
|
10
|
+
export class SlackChatAdapter {
|
|
11
|
+
platformName = "slack";
|
|
12
|
+
logger;
|
|
13
|
+
constructor(logger) {
|
|
14
|
+
this.logger = logger ?? createLogger({ component: "SlackChatAdapter" });
|
|
15
|
+
}
|
|
16
|
+
extractTaskInstructions(event) {
|
|
17
|
+
return (stripSlackMention(event.payload.text) || "Ask the user for more context");
|
|
18
|
+
}
|
|
19
|
+
getThreadKey(event) {
|
|
20
|
+
const threadTs = event.payload.thread_ts || event.payload.ts;
|
|
21
|
+
return `${event.payload.channel}:${threadTs}`;
|
|
22
|
+
}
|
|
23
|
+
getEventId(event) {
|
|
24
|
+
return event.eventId;
|
|
25
|
+
}
|
|
26
|
+
buildSystemPrompt(event) {
|
|
27
|
+
return `You are responding to a Slack @mention.
|
|
28
|
+
|
|
29
|
+
## Context
|
|
30
|
+
- **Requested by**: ${event.payload.user}
|
|
31
|
+
- **Channel**: ${event.payload.channel}
|
|
32
|
+
|
|
33
|
+
## Instructions
|
|
34
|
+
- You are running in a transient workspace, not associated with any code repository
|
|
35
|
+
- Be concise in your responses as they will be posted back to Slack
|
|
36
|
+
- If the user's request involves code changes, help them plan the work and suggest creating an issue in their project tracker (Linear, Jira, or GitHub Issues)
|
|
37
|
+
- You can answer questions, provide analysis, help with planning, and assist with research
|
|
38
|
+
- If files need to be created or examined, they will be in your working directory`;
|
|
39
|
+
}
|
|
40
|
+
async fetchThreadContext(event) {
|
|
41
|
+
// Only fetch context for threaded messages
|
|
42
|
+
if (!event.payload.thread_ts) {
|
|
43
|
+
return "";
|
|
44
|
+
}
|
|
45
|
+
if (!event.slackBotToken) {
|
|
46
|
+
this.logger.warn("Cannot fetch Slack thread context: no slackBotToken available");
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const slackService = new SlackMessageService();
|
|
51
|
+
const messages = await slackService.fetchThreadMessages({
|
|
52
|
+
token: event.slackBotToken,
|
|
53
|
+
channel: event.payload.channel,
|
|
54
|
+
thread_ts: event.payload.thread_ts,
|
|
55
|
+
limit: 50,
|
|
56
|
+
});
|
|
57
|
+
// Filter out the @mention message itself and bot messages
|
|
58
|
+
const contextMessages = messages.filter((msg) => msg.ts !== event.payload.ts &&
|
|
59
|
+
!msg.bot_id &&
|
|
60
|
+
msg.subtype !== "bot_message");
|
|
61
|
+
if (contextMessages.length === 0) {
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
return this.formatThreadContext(contextMessages);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
this.logger.warn(`Failed to fetch Slack thread context: ${error instanceof Error ? error.message : String(error)}`);
|
|
68
|
+
return "";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async postReply(event, runner) {
|
|
72
|
+
try {
|
|
73
|
+
// Get the last assistant message from the runner as the summary
|
|
74
|
+
const messages = runner.getMessages();
|
|
75
|
+
const lastAssistantMessage = [...messages]
|
|
76
|
+
.reverse()
|
|
77
|
+
.find((m) => m.type === "assistant");
|
|
78
|
+
let summary = "Task completed.";
|
|
79
|
+
if (lastAssistantMessage &&
|
|
80
|
+
lastAssistantMessage.type === "assistant" &&
|
|
81
|
+
"message" in lastAssistantMessage) {
|
|
82
|
+
const msg = lastAssistantMessage;
|
|
83
|
+
const textBlock = msg.message.content?.find((block) => block.type === "text" && block.text);
|
|
84
|
+
if (textBlock?.text) {
|
|
85
|
+
summary = textBlock.text;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!event.slackBotToken) {
|
|
89
|
+
this.logger.warn("Cannot post Slack reply: no slackBotToken available");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Thread the reply under the original message
|
|
93
|
+
const threadTs = event.payload.thread_ts || event.payload.ts;
|
|
94
|
+
await new SlackMessageService().postMessage({
|
|
95
|
+
token: event.slackBotToken,
|
|
96
|
+
channel: event.payload.channel,
|
|
97
|
+
text: summary,
|
|
98
|
+
thread_ts: threadTs,
|
|
99
|
+
});
|
|
100
|
+
this.logger.info(`Posted Slack reply to channel ${event.payload.channel} (thread ${threadTs})`);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.logger.error("Failed to post Slack reply", error instanceof Error ? error : new Error(String(error)));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async acknowledgeReceipt(event) {
|
|
107
|
+
if (!event.slackBotToken) {
|
|
108
|
+
this.logger.warn("Cannot add Slack reaction: no slackBotToken available (SLACK_BOT_TOKEN env var not set)");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
await new SlackReactionService().addReaction({
|
|
112
|
+
token: event.slackBotToken,
|
|
113
|
+
channel: event.payload.channel,
|
|
114
|
+
timestamp: event.payload.ts,
|
|
115
|
+
name: "eyes",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async notifyBusy(event) {
|
|
119
|
+
if (!event.slackBotToken) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const threadTs = event.payload.thread_ts || event.payload.ts;
|
|
123
|
+
await new SlackMessageService().postMessage({
|
|
124
|
+
token: event.slackBotToken,
|
|
125
|
+
channel: event.payload.channel,
|
|
126
|
+
text: "I'm still working on the previous request in this thread. I'll pick up your new message once I'm done.",
|
|
127
|
+
thread_ts: threadTs,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
formatThreadContext(messages) {
|
|
131
|
+
const formattedMessages = messages
|
|
132
|
+
.map((msg) => ` <message>
|
|
133
|
+
<author>${msg.user ?? "unknown"}</author>
|
|
134
|
+
<timestamp>${msg.ts}</timestamp>
|
|
135
|
+
<content>
|
|
136
|
+
${msg.text}
|
|
137
|
+
</content>
|
|
138
|
+
</message>`)
|
|
139
|
+
.join("\n");
|
|
140
|
+
return `<slack_thread_context>\n${formattedMessages}\n</slack_thread_context>`;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=SlackChatAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SlackChatAdapter.js","sourceRoot":"","sources":["../src/SlackChatAdapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACN,mBAAmB,EACnB,oBAAoB,EAGpB,YAAY,IAAI,iBAAiB,GACjC,MAAM,6BAA6B,CAAC;AAGrC;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IAGnB,YAAY,GAAG,OAAgB,CAAC;IACjC,MAAM,CAAU;IAExB,YAAY,MAAgB;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,YAAY,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,uBAAuB,CAAC,KAAwB;QAC/C,OAAO,CACN,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,+BAA+B,CACxE,CAAC;IACH,CAAC;IAED,YAAY,CAAC,KAAwB;QACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC;IAC/C,CAAC;IAED,UAAU,CAAC,KAAwB;QAClC,OAAO,KAAK,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,iBAAiB,CAAC,KAAwB;QACzC,OAAO;;;sBAGa,KAAK,CAAC,OAAO,CAAC,IAAI;iBACvB,KAAK,CAAC,OAAO,CAAC,OAAO;;;;;;;kFAO4C,CAAC;IAClF,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAAwB;QAChD,2CAA2C;QAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YAC9B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CACf,+DAA+D,CAC/D,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,YAAY,GAAG,IAAI,mBAAmB,EAAE,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,mBAAmB,CAAC;gBACvD,KAAK,EAAE,KAAK,CAAC,aAAa;gBAC1B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;gBAC9B,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS;gBAClC,KAAK,EAAE,EAAE;aACT,CAAC,CAAC;YAEH,0DAA0D;YAC1D,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CACtC,CAAC,GAAG,EAAE,EAAE,CACP,GAAG,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,EAAE;gBAC3B,CAAC,GAAG,CAAC,MAAM;gBACX,GAAG,CAAC,OAAO,KAAK,aAAa,CAC9B,CAAC;YAEF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,OAAO,EAAE,CAAC;YACX,CAAC;YAED,OAAO,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CACf,yCAAyC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACjG,CAAC;YACF,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAED,KAAK,CAAC,SAAS,CACd,KAAwB,EACxB,MAAoB;QAEpB,IAAI,CAAC;YACJ,gEAAgE;YAChE,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;YACtC,MAAM,oBAAoB,GAAG,CAAC,GAAG,QAAQ,CAAC;iBACxC,OAAO,EAAE;iBACT,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;YAEtC,IAAI,OAAO,GAAG,iBAAiB,CAAC;YAChC,IACC,oBAAoB;gBACpB,oBAAoB,CAAC,IAAI,KAAK,WAAW;gBACzC,SAAS,IAAI,oBAAoB,EAChC,CAAC;gBACF,MAAM,GAAG,GAAG,oBAIX,CAAC;gBACF,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAC1C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,CAC9C,CAAC;gBACF,IAAI,SAAS,EAAE,IAAI,EAAE,CAAC;oBACrB,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC;gBAC1B,CAAC;YACF,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;gBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;gBACxE,OAAO;YACR,CAAC;YAED,8CAA8C;YAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAE7D,MAAM,IAAI,mBAAmB,EAAE,CAAC,WAAW,CAAC;gBAC3C,KAAK,EAAE,KAAK,CAAC,aAAa;gBAC1B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;gBAC9B,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,QAAQ;aACnB,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CACf,iCAAiC,KAAK,CAAC,OAAO,CAAC,OAAO,YAAY,QAAQ,GAAG,CAC7E,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB,4BAA4B,EAC5B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CACzD,CAAC;QACH,CAAC;IACF,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,KAAwB;QAChD,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CACf,yFAAyF,CACzF,CAAC;YACF,OAAO;QACR,CAAC;QAED,MAAM,IAAI,oBAAoB,EAAE,CAAC,WAAW,CAAC;YAC5C,KAAK,EAAE,KAAK,CAAC,aAAa;YAC1B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;YAC9B,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;YAC3B,IAAI,EAAE,MAAM;SACZ,CAAC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAwB;QACxC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YAC1B,OAAO;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAE7D,MAAM,IAAI,mBAAmB,EAAE,CAAC,WAAW,CAAC;YAC3C,KAAK,EAAE,KAAK,CAAC,aAAa;YAC1B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;YAC9B,IAAI,EAAE,wGAAwG;YAC9G,SAAS,EAAE,QAAQ;SACnB,CAAC,CAAC;IACJ,CAAC;IAEO,mBAAmB,CAAC,QAA8B;QACzD,MAAM,iBAAiB,GAAG,QAAQ;aAChC,GAAG,CACH,CAAC,GAAG,EAAE,EAAE,CACP;cACS,GAAG,CAAC,IAAI,IAAI,SAAS;iBAClB,GAAG,CAAC,EAAE;;EAErB,GAAG,CAAC,IAAI;;aAEG,CACT;aACA,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,OAAO,2BAA2B,iBAAiB,2BAA2B,CAAC;IAChF,CAAC;CACD"}
|