@cursor/july 0.1.74 → 0.1.76
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/dist/channels/checks.d.ts +111 -0
- package/dist/channels/checks.d.ts.map +1 -0
- package/dist/channels/checks.js +86 -0
- package/dist/channels/deployments/deployments-channel.d.ts +44 -0
- package/dist/channels/deployments/deployments-channel.d.ts.map +1 -0
- package/dist/channels/deployments/deployments-channel.js +92 -0
- package/dist/channels/deployments/index.d.ts +26 -0
- package/dist/channels/deployments/index.d.ts.map +1 -0
- package/dist/channels/deployments/index.js +25 -0
- package/dist/channels/deployments/types.d.ts +69 -0
- package/dist/channels/deployments/types.d.ts.map +1 -0
- package/dist/channels/deployments/types.js +6 -0
- package/dist/channels/github/checks.d.ts +13 -48
- package/dist/channels/github/checks.d.ts.map +1 -1
- package/dist/channels/github/checks.js +56 -64
- package/dist/channels/origin/api.d.ts +100 -0
- package/dist/channels/origin/api.d.ts.map +1 -0
- package/dist/channels/origin/api.js +225 -0
- package/dist/channels/origin/binding.d.ts +44 -0
- package/dist/channels/origin/binding.d.ts.map +1 -0
- package/dist/channels/origin/binding.js +45 -0
- package/dist/channels/origin/checks.d.ts +107 -0
- package/dist/channels/origin/checks.d.ts.map +1 -0
- package/dist/channels/origin/checks.js +145 -0
- package/dist/channels/origin/index.d.ts +3 -0
- package/dist/channels/origin/index.d.ts.map +1 -1
- package/dist/channels/origin/index.js +3 -0
- package/dist/channels/origin/origin-channel.d.ts +4 -4
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +12 -2
- package/dist/channels/origin/types.d.ts +36 -0
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels.d.ts +1 -0
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +1 -0
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.BETd-WqU.js → app.b8bhB2SV.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DGZeXVqn.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.wEaGEmV9.js → VPLocalSearchBox.lLSeIyWw.js} +1 -1
- package/dist/docs/assets/chunks/{theme.DNDicFOP.js → theme.C_owesa-.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.MN8iDy8V.js → reference_channels.md.G5GysZ7e.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.MN8iDy8V.lean.js → reference_channels.md.G5GysZ7e.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +3 -3
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +3 -3
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/convert-automation.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +3 -3
- package/dist/docs/guides/opentelemetry.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +3 -3
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/artifacts.html +3 -3
- package/dist/docs/reference/channels.html +5 -5
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/templates/agentic-owners.html +3 -3
- package/dist/docs/templates/demo.html +3 -3
- package/dist/docs/templates/pr-autofixer.html +3 -3
- package/dist/docs/templates/security-reviewer.html +3 -3
- package/dist/docs/templates/triage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/internal/authored-alias-hooks.d.ts +12 -0
- package/dist/internal/authored-alias-hooks.d.ts.map +1 -1
- package/dist/internal/authored-alias-hooks.js +60 -8
- package/dist/internal/authored-loaders.d.ts +5 -3
- package/dist/internal/authored-loaders.d.ts.map +1 -1
- package/dist/internal/authored-loaders.js +13 -4
- package/dist/internal/cursor-deployment-relay.d.ts +77 -0
- package/dist/internal/cursor-deployment-relay.d.ts.map +1 -0
- package/dist/internal/cursor-deployment-relay.js +201 -0
- package/dist/internal/deployment-scm-event-stream.js +4 -4
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +1 -0
- package/dist/internal/review-comments.d.ts +62 -0
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +199 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +114 -5
- package/dist/playground/assets/{index-D_8I9TM0.js → index-BWqjJcRo.js} +1 -1
- package/dist/playground/assets/index-Bfwz2yLN.css +1 -0
- package/dist/playground/index.html +2 -2
- package/docs/reference/channels.md +15 -0
- package/package.json +7 -1
- package/src/channels/checks.ts +185 -0
- package/src/channels/deployments/deployments-channel.ts +109 -0
- package/src/channels/deployments/index.ts +26 -0
- package/src/channels/deployments/types.ts +80 -0
- package/src/channels/github/checks.ts +90 -115
- package/src/channels/origin/api.ts +318 -0
- package/src/channels/origin/binding.ts +96 -0
- package/src/channels/origin/checks.ts +250 -0
- package/src/channels/origin/index.ts +3 -0
- package/src/channels/origin/origin-channel.ts +18 -6
- package/src/channels/origin/types.ts +37 -0
- package/src/channels.ts +16 -0
- package/src/internal/authored-alias-hooks.ts +75 -7
- package/src/internal/authored-loaders.ts +15 -4
- package/src/internal/cursor-deployment-relay.ts +274 -0
- package/src/internal/deployment-scm-event-stream.ts +4 -4
- package/src/internal/distribution.ts +1 -0
- package/src/internal/review-comments.ts +286 -0
- package/src/internal/server.ts +149 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DM5INS71.js +0 -1
- package/dist/playground/assets/index-M3nSMc6_.css +0 -1
|
@@ -32,9 +32,55 @@ export function createReviewCommentReader(args) {
|
|
|
32
32
|
: createHostGithubReviewCommentReader(args.github);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolver for a resolved target. Returns undefined when the host cannot
|
|
37
|
+
* serve that provider, so callers degrade instead of throwing.
|
|
38
|
+
*/
|
|
39
|
+
export function createReviewThreadResolver(args) {
|
|
40
|
+
switch (args.target.provider) {
|
|
41
|
+
case "github":
|
|
42
|
+
return args.github === undefined
|
|
43
|
+
? undefined
|
|
44
|
+
: createHostGithubReviewThreadResolver(args.github);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the review threads that own `commentIds` on `prUrl`.
|
|
49
|
+
*
|
|
50
|
+
* No-ops (never throws) when the PR is on an SCM this host cannot write,
|
|
51
|
+
* no client is bound, or `commentIds` is empty. Same degrade-don't-fail
|
|
52
|
+
* posture as {@link createReviewCommentReader}.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveReviewThreadsForComments(args) {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
var _a;
|
|
57
|
+
if (args.commentIds.length === 0) {
|
|
58
|
+
return skippedResolve("no comments to resolve");
|
|
59
|
+
}
|
|
60
|
+
const target = resolveScmReviewTarget(args.prUrl);
|
|
61
|
+
if (target === undefined) {
|
|
62
|
+
return skippedResolve("no SCM resolver for this PR URL");
|
|
63
|
+
}
|
|
64
|
+
const resolver = (_a = args.resolver) !== null && _a !== void 0 ? _a : createReviewThreadResolver({
|
|
65
|
+
target,
|
|
66
|
+
github: args.github,
|
|
67
|
+
});
|
|
68
|
+
if (resolver === undefined) {
|
|
69
|
+
return skippedResolve("no GitHub client bound to resolve threads");
|
|
70
|
+
}
|
|
71
|
+
return resolver.resolveReviewThreadsForComments({
|
|
72
|
+
target,
|
|
73
|
+
commentIds: args.commentIds,
|
|
74
|
+
signal: args.signal,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
35
78
|
/** Cap on pages pulled per PR; GitHub serves 100 comments per page. */
|
|
36
79
|
const REVIEW_COMMENTS_MAX_PAGES = 5;
|
|
37
80
|
const REVIEW_COMMENTS_PAGE_SIZE = 100;
|
|
81
|
+
/** Cap on review-thread pages when mapping comment ids to GraphQL thread ids. */
|
|
82
|
+
const REVIEW_THREADS_MAX_PAGES = 20;
|
|
83
|
+
const REVIEW_THREADS_PAGE_SIZE = 100;
|
|
38
84
|
/**
|
|
39
85
|
* Reads inline review comments through the host GitHub client (Cursor
|
|
40
86
|
* account lease, App installation token, or PAT).
|
|
@@ -72,6 +118,149 @@ export function createHostGithubReviewCommentReader(github) {
|
|
|
72
118
|
},
|
|
73
119
|
};
|
|
74
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Resolves inline review threads through the host GitHub client (Cursor
|
|
123
|
+
* account lease, App installation token, or PAT). GitHub GraphQL has no
|
|
124
|
+
* comment→thread field, so this pages the PR's review threads and matches
|
|
125
|
+
* each REST comment id by `databaseId` — the same approach as Bugbot's
|
|
126
|
+
* `resolveReviewThreadForComment`.
|
|
127
|
+
*/
|
|
128
|
+
export function createHostGithubReviewThreadResolver(github) {
|
|
129
|
+
return {
|
|
130
|
+
resolveReviewThreadsForComments(_a) {
|
|
131
|
+
return __awaiter(this, arguments, void 0, function* ({ target, commentIds, signal }) {
|
|
132
|
+
var _b, _c, _d, _e, _f;
|
|
133
|
+
var _g, _h;
|
|
134
|
+
const uniqueIds = [...new Set(commentIds.filter((id) => id > 0))];
|
|
135
|
+
if (uniqueIds.length === 0) {
|
|
136
|
+
return skippedResolve("no comments to resolve");
|
|
137
|
+
}
|
|
138
|
+
const [owner, repo] = target.repo.split("/", 2);
|
|
139
|
+
if (owner === undefined || repo === undefined || repo === "") {
|
|
140
|
+
return skippedResolve("unparseable owner/repo from PR URL");
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const octokit = yield github.getOctokit();
|
|
144
|
+
const wanted = new Set(uniqueIds);
|
|
145
|
+
const matched = new Map();
|
|
146
|
+
let cursor = null;
|
|
147
|
+
for (let page = 0; page < REVIEW_THREADS_MAX_PAGES; page++) {
|
|
148
|
+
signal === null || signal === void 0 ? void 0 : signal.throwIfAborted();
|
|
149
|
+
const response = (yield octokit.graphql(REVIEW_THREADS_FOR_PR_QUERY, {
|
|
150
|
+
owner,
|
|
151
|
+
repo,
|
|
152
|
+
number: target.prNumber,
|
|
153
|
+
cursor,
|
|
154
|
+
}));
|
|
155
|
+
const reviewThreads = (_c = (_b = response.repository) === null || _b === void 0 ? void 0 : _b.pullRequest) === null || _c === void 0 ? void 0 : _c.reviewThreads;
|
|
156
|
+
for (const thread of (_g = reviewThreads === null || reviewThreads === void 0 ? void 0 : reviewThreads.nodes) !== null && _g !== void 0 ? _g : []) {
|
|
157
|
+
if ((thread === null || thread === void 0 ? void 0 : thread.id) === undefined || thread.id === "") {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
for (const comment of (_h = (_d = thread.comments) === null || _d === void 0 ? void 0 : _d.nodes) !== null && _h !== void 0 ? _h : []) {
|
|
161
|
+
const databaseId = comment === null || comment === void 0 ? void 0 : comment.databaseId;
|
|
162
|
+
if (databaseId !== undefined &&
|
|
163
|
+
databaseId !== null &&
|
|
164
|
+
wanted.has(databaseId) &&
|
|
165
|
+
!matched.has(databaseId)) {
|
|
166
|
+
matched.set(databaseId, {
|
|
167
|
+
threadId: thread.id,
|
|
168
|
+
isResolved: thread.isResolved === true,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (matched.size === wanted.size) {
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
const pageInfo = reviewThreads === null || reviewThreads === void 0 ? void 0 : reviewThreads.pageInfo;
|
|
177
|
+
if ((pageInfo === null || pageInfo === void 0 ? void 0 : pageInfo.hasNextPage) !== true || !pageInfo.endCursor) {
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
cursor = pageInfo.endCursor;
|
|
181
|
+
}
|
|
182
|
+
const toResolve = [
|
|
183
|
+
...new Map([...matched.values()]
|
|
184
|
+
.filter((thread) => !thread.isResolved)
|
|
185
|
+
.map((thread) => [thread.threadId, thread.threadId])).values(),
|
|
186
|
+
];
|
|
187
|
+
let resolved = 0;
|
|
188
|
+
let failed = 0;
|
|
189
|
+
for (const threadId of toResolve) {
|
|
190
|
+
signal === null || signal === void 0 ? void 0 : signal.throwIfAborted();
|
|
191
|
+
try {
|
|
192
|
+
const mutation = (yield octokit.graphql(RESOLVE_REVIEW_THREAD_MUTATION, { threadId }));
|
|
193
|
+
if (((_f = (_e = mutation.resolveReviewThread) === null || _e === void 0 ? void 0 : _e.thread) === null || _f === void 0 ? void 0 : _f.isResolved) === true) {
|
|
194
|
+
resolved += 1;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
failed += 1;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (_j) {
|
|
201
|
+
failed += 1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const alreadyResolved = new Set([...matched.values()]
|
|
205
|
+
.filter((thread) => thread.isResolved)
|
|
206
|
+
.map((thread) => thread.threadId)).size;
|
|
207
|
+
const notFound = wanted.size - matched.size;
|
|
208
|
+
return {
|
|
209
|
+
requested: uniqueIds.length,
|
|
210
|
+
resolved,
|
|
211
|
+
alreadyResolved,
|
|
212
|
+
notFound,
|
|
213
|
+
failed,
|
|
214
|
+
detail: `resolved ${resolved} of ${toResolve.length} open thread(s) for ${uniqueIds.length} comment(s) via host GitHub (${alreadyResolved} already resolved, ${notFound} not found, ${failed} failed)`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
requested: uniqueIds.length,
|
|
223
|
+
resolved: 0,
|
|
224
|
+
alreadyResolved: 0,
|
|
225
|
+
notFound: 0,
|
|
226
|
+
failed: uniqueIds.length,
|
|
227
|
+
detail: `host GitHub thread resolve failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const REVIEW_THREADS_FOR_PR_QUERY = `
|
|
235
|
+
query ReviewThreadsForPr(
|
|
236
|
+
$owner: String!
|
|
237
|
+
$repo: String!
|
|
238
|
+
$number: Int!
|
|
239
|
+
$cursor: String
|
|
240
|
+
) {
|
|
241
|
+
repository(owner: $owner, name: $repo) {
|
|
242
|
+
pullRequest(number: $number) {
|
|
243
|
+
reviewThreads(first: ${REVIEW_THREADS_PAGE_SIZE}, after: $cursor) {
|
|
244
|
+
nodes {
|
|
245
|
+
id
|
|
246
|
+
isResolved
|
|
247
|
+
comments(first: ${REVIEW_THREADS_PAGE_SIZE}) {
|
|
248
|
+
nodes { databaseId }
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
pageInfo { hasNextPage endCursor }
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
`;
|
|
257
|
+
const RESOLVE_REVIEW_THREAD_MUTATION = `
|
|
258
|
+
mutation ResolveReviewThread($threadId: ID!) {
|
|
259
|
+
resolveReviewThread(input: { threadId: $threadId }) {
|
|
260
|
+
thread { isResolved }
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
`;
|
|
75
264
|
/**
|
|
76
265
|
* GitHub review comment → {@link ExistingReviewComment}.
|
|
77
266
|
*
|
|
@@ -334,6 +523,16 @@ function skippedHost(detail) {
|
|
|
334
523
|
detail,
|
|
335
524
|
};
|
|
336
525
|
}
|
|
526
|
+
function skippedResolve(detail) {
|
|
527
|
+
return {
|
|
528
|
+
requested: 0,
|
|
529
|
+
resolved: 0,
|
|
530
|
+
alreadyResolved: 0,
|
|
531
|
+
notFound: 0,
|
|
532
|
+
failed: 0,
|
|
533
|
+
detail,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
337
536
|
function parseGithubPrUrl(prUrl) {
|
|
338
537
|
let url;
|
|
339
538
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/internal/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/internal/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuCH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAOhB,YAAY,EACb,MAAM,aAAa,CAAC;AAwHrB,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,iBAAiB,CAAC;AAwBpE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;CACvB;AAaD,6EAA6E;AAC7E,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,YAAY,GAAG,0BAA+B,GACtD,OAAO,CAAC,gBAAgB,CAAC,CAoxB3B"}
|
package/dist/internal/server.js
CHANGED
|
@@ -35,6 +35,7 @@ import { Buffer } from "node:buffer";
|
|
|
35
35
|
import { once } from "node:events";
|
|
36
36
|
import { createServer, } from "node:http";
|
|
37
37
|
import { join } from "node:path";
|
|
38
|
+
import { dispatchDeploymentEvent, getDeploymentsChannelOptions, } from "../channels/deployments/deployments-channel.js";
|
|
38
39
|
import { createCursorAccountGithubTokenResolver, getGithubCursorAccountRuntime, parseCursorGithubRepoScope, resolveCursorGithubPermissions, resolveCursorGithubProxyUrl, } from "../channels/github/cursor-account.js";
|
|
39
40
|
import { findGitHubChannelTargets } from "../channels/github/forward.js";
|
|
40
41
|
import { getOriginCursorAccountRuntime, parseCursorOriginRepoScope, } from "../channels/origin/cursor-account.js";
|
|
@@ -46,6 +47,7 @@ import { CursorAccountMcpBridge, collectCursorAccountConnections, cursorAccountM
|
|
|
46
47
|
import { CursorBackendClient } from "./cursor/backend-client.js";
|
|
47
48
|
import { cursorExternalApiUrl, resolveApiKey, SIGN_IN_HINT, } from "./cursor/credentials.js";
|
|
48
49
|
import { CursorGithubCredentialProvider } from "./cursor/github-credentials.js";
|
|
50
|
+
import { DeploymentEventRelay, fanOutDeploymentEvent, resolveDeploymentSubscriptions, } from "./cursor-deployment-relay.js";
|
|
49
51
|
import { CursorEventRelay, formatCursorScmDispatchOutcome, formatCursorScmEventLog, scmEventToGitHubPayload, scmMetadataToOriginPayload, } from "./cursor-event-relay.js";
|
|
50
52
|
import { AGENT_SERVE_GENERATION_ENV_VAR } from "./cursor-relay-core.js";
|
|
51
53
|
import { CursorSlackRelay, createCursorSlackApiCaller, formatCursorSlackEventLog, } from "./cursor-slack-relay.js";
|
|
@@ -536,6 +538,14 @@ export function startServer(mounts_1) {
|
|
|
536
538
|
cursorAccountOnly: options.cursorEvents === undefined &&
|
|
537
539
|
(cursorGithubTargets.length > 0 || cursorOriginTargets.length > 0),
|
|
538
540
|
});
|
|
541
|
+
// Cursor deployment-events relay: automatic when a mounted agent authored
|
|
542
|
+
// `deploymentsChannel({ ... })`.
|
|
543
|
+
const cursorDeploymentRelay = startCursorDeploymentRelay({
|
|
544
|
+
options,
|
|
545
|
+
runtimes,
|
|
546
|
+
accountKey,
|
|
547
|
+
logger,
|
|
548
|
+
});
|
|
539
549
|
const server = createServer((req, res) => {
|
|
540
550
|
void instrumentHttp(otelRuntime, req, res, () => handleRequest(router, req, res, logger));
|
|
541
551
|
});
|
|
@@ -553,6 +563,7 @@ export function startServer(mounts_1) {
|
|
|
553
563
|
});
|
|
554
564
|
}
|
|
555
565
|
catch (error) {
|
|
566
|
+
yield cursorDeploymentRelay === null || cursorDeploymentRelay === void 0 ? void 0 : cursorDeploymentRelay.stop();
|
|
556
567
|
yield cursorEventRelay === null || cursorEventRelay === void 0 ? void 0 : cursorEventRelay.stop();
|
|
557
568
|
yield cursorSlackRelay === null || cursorSlackRelay === void 0 ? void 0 : cursorSlackRelay.stop();
|
|
558
569
|
cursorGithubCredentials === null || cursorGithubCredentials === void 0 ? void 0 : cursorGithubCredentials.stop();
|
|
@@ -703,6 +714,7 @@ export function startServer(mounts_1) {
|
|
|
703
714
|
var _a;
|
|
704
715
|
var _b;
|
|
705
716
|
playgroundDev === null || playgroundDev === void 0 ? void 0 : playgroundDev.stop();
|
|
717
|
+
yield cursorDeploymentRelay === null || cursorDeploymentRelay === void 0 ? void 0 : cursorDeploymentRelay.stop();
|
|
706
718
|
yield cursorEventRelay === null || cursorEventRelay === void 0 ? void 0 : cursorEventRelay.stop();
|
|
707
719
|
yield cursorSlackRelay === null || cursorSlackRelay === void 0 ? void 0 : cursorSlackRelay.stop();
|
|
708
720
|
for (const runtime of runtimes) {
|
|
@@ -1660,13 +1672,110 @@ function collectCursorSlackTargets(runtimes) {
|
|
|
1660
1672
|
}
|
|
1661
1673
|
return targets;
|
|
1662
1674
|
}
|
|
1675
|
+
/** Every mounted `deploymentsChannel`, with its resolved subscriptions. */
|
|
1676
|
+
function collectCursorDeploymentTargets(runtimes, skipped) {
|
|
1677
|
+
const targets = [];
|
|
1678
|
+
for (const runtime of runtimes) {
|
|
1679
|
+
for (const channel of runtime.project.channels) {
|
|
1680
|
+
const options = getDeploymentsChannelOptions(channel.definition);
|
|
1681
|
+
if (options === undefined) {
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1684
|
+
const subscriptions = resolveDeploymentSubscriptions(options);
|
|
1685
|
+
if (subscriptions.length === 0) {
|
|
1686
|
+
// Declared the channel but named no repositories — usually an unset
|
|
1687
|
+
// env var. Say so rather than starting a relay that receives nothing.
|
|
1688
|
+
skipped.push(`${runtime.slug || runtime.project.name}/${channel.id}`);
|
|
1689
|
+
continue;
|
|
1690
|
+
}
|
|
1691
|
+
targets.push({ runtime, channelId: channel.id, options, subscriptions });
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
return targets;
|
|
1695
|
+
}
|
|
1663
1696
|
/**
|
|
1664
|
-
*
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
*
|
|
1668
|
-
*
|
|
1697
|
+
* Cursor deployment-events relay: automatic when a mounted agent authored
|
|
1698
|
+
* `deploymentsChannel({ ... })`. One relay per process reads
|
|
1699
|
+
* `/v0/deployment-events` for the union of every channel's repositories, and
|
|
1700
|
+
* each event is routed to the channels that asked for it — the same ownership
|
|
1701
|
+
* `startCursorSlackRelay` and `startCursorEventRelay` have.
|
|
1669
1702
|
*/
|
|
1703
|
+
function startCursorDeploymentRelay(input) {
|
|
1704
|
+
var _a;
|
|
1705
|
+
const { options, runtimes, accountKey, logger } = input;
|
|
1706
|
+
const skipped = [];
|
|
1707
|
+
const targets = collectCursorDeploymentTargets(runtimes, skipped);
|
|
1708
|
+
if (skipped.length > 0) {
|
|
1709
|
+
logger(`[agent-sdk] deployment-events: no repositories declared on ${skipped.join(", ")}; those channels receive nothing`);
|
|
1710
|
+
}
|
|
1711
|
+
if (targets.length === 0) {
|
|
1712
|
+
return undefined;
|
|
1713
|
+
}
|
|
1714
|
+
if (accountKey === undefined) {
|
|
1715
|
+
throw new Error(`This project has channels subscribed to deployment events (deploymentsChannel({ repos })) but the host is not signed in to Cursor. ${SIGN_IN_HINT}`);
|
|
1716
|
+
}
|
|
1717
|
+
// Union across channels: one registration per repo for the whole process,
|
|
1718
|
+
// however many channels named it. Per-channel environment and event-type
|
|
1719
|
+
// filtering happens at dispatch.
|
|
1720
|
+
const byRepo = new Map();
|
|
1721
|
+
for (const target of targets) {
|
|
1722
|
+
for (const subscription of target.subscriptions) {
|
|
1723
|
+
const existing = byRepo.get(subscription.repo);
|
|
1724
|
+
if (existing === undefined) {
|
|
1725
|
+
byRepo.set(subscription.repo, {
|
|
1726
|
+
repo: subscription.repo,
|
|
1727
|
+
environments: [...subscription.environments],
|
|
1728
|
+
events: new Set(subscription.events),
|
|
1729
|
+
});
|
|
1730
|
+
continue;
|
|
1731
|
+
}
|
|
1732
|
+
for (const event of subscription.events)
|
|
1733
|
+
existing.events.add(event);
|
|
1734
|
+
// An empty environment list means "every environment", so it absorbs.
|
|
1735
|
+
existing.environments =
|
|
1736
|
+
existing.environments.length === 0 ||
|
|
1737
|
+
subscription.environments.length === 0
|
|
1738
|
+
? []
|
|
1739
|
+
: [
|
|
1740
|
+
...new Set([
|
|
1741
|
+
...existing.environments,
|
|
1742
|
+
...subscription.environments,
|
|
1743
|
+
]),
|
|
1744
|
+
];
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
// Same host split as scm-events and slack-events: `/v0/deployment-events/*`
|
|
1748
|
+
// is on api.cursor.com, not api2.
|
|
1749
|
+
const baseStateRoot = (_a = options.stateRoot) !== null && _a !== void 0 ? _a : join(targets[0].runtime.project.rootDir, ".agent-serve");
|
|
1750
|
+
const relay = new DeploymentEventRelay({
|
|
1751
|
+
baseUrl: cursorExternalApiUrl(),
|
|
1752
|
+
apiKey: accountKey.apiKey,
|
|
1753
|
+
stateDir: join(baseStateRoot, "deployment-events"),
|
|
1754
|
+
subscriptions: [...byRepo.values()],
|
|
1755
|
+
logger,
|
|
1756
|
+
dispatch: (event) => __awaiter(this, void 0, void 0, function* () {
|
|
1757
|
+
return fanOutDeploymentEvent({
|
|
1758
|
+
event,
|
|
1759
|
+
logger,
|
|
1760
|
+
targets: targets.map((target) => ({
|
|
1761
|
+
name: `${target.runtime.slug || target.runtime.project.name}/${target.channelId}`,
|
|
1762
|
+
subscriptions: target.subscriptions,
|
|
1763
|
+
deliver: (delivered) => dispatchDeploymentEvent({
|
|
1764
|
+
options: target.options,
|
|
1765
|
+
event: delivered,
|
|
1766
|
+
args: buildChannelHandlerArgs({
|
|
1767
|
+
runtime: target.runtime,
|
|
1768
|
+
channelId: target.channelId,
|
|
1769
|
+
}),
|
|
1770
|
+
}),
|
|
1771
|
+
})),
|
|
1772
|
+
});
|
|
1773
|
+
}),
|
|
1774
|
+
});
|
|
1775
|
+
relay.start();
|
|
1776
|
+
logger(`[agent-sdk] deployment-events: relaying ${byRepo.size} repository subscription(s) to ${targets.length} channel(s)`);
|
|
1777
|
+
return relay;
|
|
1778
|
+
}
|
|
1670
1779
|
function startCursorSlackRelay(input) {
|
|
1671
1780
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1672
1781
|
var _a;
|