@cursor/july 0.1.75 → 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/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/deployment-scm-event-stream.js +4 -4
- 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/playground/assets/index-Bfwz2yLN.css +1 -0
- package/dist/playground/index.html +2 -2
- package/package.json +1 -1
- package/src/internal/authored-alias-hooks.ts +75 -7
- package/src/internal/authored-loaders.ts +15 -4
- package/src/internal/deployment-scm-event-stream.ts +4 -4
- package/src/internal/review-comments.ts +286 -0
- package/dist/playground/assets/index-BrSd5vff.css +0 -1
- /package/dist/playground/assets/{index-BJy9UJrF.js → index-BWqjJcRo.js} +0 -0
|
@@ -14,10 +14,22 @@
|
|
|
14
14
|
* project's own node_modules; `fallbackAliases` only apply when that
|
|
15
15
|
* fails (npx/global installs, projects without a local dependency), so a
|
|
16
16
|
* real install in the user's project keeps precedence.
|
|
17
|
+
*
|
|
18
|
+
* A third case is first-party factory agents that relative-import this
|
|
19
|
+
* package's `src/` from a monorepo checkout. Hosted engines `npm install`
|
|
20
|
+
* only the agent directory, so files under `packages/agent-serve/src` have
|
|
21
|
+
* no `node_modules`. Bare specifiers from that tree (`zod`, octokit, …)
|
|
22
|
+
* retry against the running `@cursor/july` package.json, which does.
|
|
17
23
|
*/
|
|
18
24
|
export interface AuthoredAliasHookData {
|
|
19
25
|
directAliases: Record<string, string>;
|
|
20
26
|
fallbackAliases: Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* `file:` URL of the running `@cursor/july` package.json. Bare imports
|
|
29
|
+
* from monorepo `packages/agent-serve/` source retry against this parent
|
|
30
|
+
* when the source tree has no `node_modules` (hosted factory engines).
|
|
31
|
+
*/
|
|
32
|
+
sourceTreeFallbackParentURL?: string;
|
|
21
33
|
}
|
|
22
34
|
export declare function initialize(data: AuthoredAliasHookData): void;
|
|
23
35
|
interface ResolveResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authored-alias-hooks.d.ts","sourceRoot":"","sources":["../../src/internal/authored-alias-hooks.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authored-alias-hooks.d.ts","sourceRoot":"","sources":["../../src/internal/authored-alias-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAQH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAQD,wBAAgB,UAAU,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAM5D;AAED,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,KAAK,WAAW,GAAG,CACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,KACb,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5C,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,GACvB,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAwBxC"}
|
|
@@ -14,17 +14,27 @@
|
|
|
14
14
|
* project's own node_modules; `fallbackAliases` only apply when that
|
|
15
15
|
* fails (npx/global installs, projects without a local dependency), so a
|
|
16
16
|
* real install in the user's project keeps precedence.
|
|
17
|
+
*
|
|
18
|
+
* A third case is first-party factory agents that relative-import this
|
|
19
|
+
* package's `src/` from a monorepo checkout. Hosted engines `npm install`
|
|
20
|
+
* only the agent directory, so files under `packages/agent-serve/src` have
|
|
21
|
+
* no `node_modules`. Bare specifiers from that tree (`zod`, octokit, …)
|
|
22
|
+
* retry against the running `@cursor/july` package.json, which does.
|
|
17
23
|
*/
|
|
18
24
|
// Null-prototype copies so specifiers like "constructor" or "__proto__"
|
|
19
25
|
// can never resolve to inherited Object.prototype members.
|
|
20
26
|
let directAliases = toNullProtoMap({});
|
|
21
27
|
let fallbackAliases = toNullProtoMap({});
|
|
28
|
+
let sourceTreeFallbackParentURL;
|
|
22
29
|
function toNullProtoMap(source) {
|
|
23
30
|
return Object.assign(Object.create(null), source);
|
|
24
31
|
}
|
|
25
32
|
export function initialize(data) {
|
|
26
33
|
directAliases = toNullProtoMap(data.directAliases);
|
|
27
34
|
fallbackAliases = toNullProtoMap(data.fallbackAliases);
|
|
35
|
+
const parent = data.sourceTreeFallbackParentURL;
|
|
36
|
+
sourceTreeFallbackParentURL =
|
|
37
|
+
typeof parent === "string" && parent !== "" ? parent : undefined;
|
|
28
38
|
}
|
|
29
39
|
export function resolve(specifier, context, nextResolve) {
|
|
30
40
|
const direct = directAliases[specifier];
|
|
@@ -32,12 +42,54 @@ export function resolve(specifier, context, nextResolve) {
|
|
|
32
42
|
return { url: direct, shortCircuit: true };
|
|
33
43
|
}
|
|
34
44
|
const fallback = fallbackAliases[specifier];
|
|
35
|
-
if (fallback
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
if (fallback !== undefined) {
|
|
46
|
+
return Promise.resolve()
|
|
47
|
+
.then(() => nextResolve(specifier, context))
|
|
48
|
+
.catch(() => ({ url: fallback, shortCircuit: true }));
|
|
49
|
+
}
|
|
50
|
+
if (sourceTreeFallbackParentURL !== undefined &&
|
|
51
|
+
isBarePackageSpecifier(specifier) &&
|
|
52
|
+
isMonorepoAgentServeSource(parentURLOf(context))) {
|
|
53
|
+
const retryParent = sourceTreeFallbackParentURL;
|
|
54
|
+
return Promise.resolve()
|
|
55
|
+
.then(() => nextResolve(specifier, context))
|
|
56
|
+
.catch(() => nextResolve(specifier, withParentURL(context, retryParent)));
|
|
57
|
+
}
|
|
58
|
+
// Not ours: pass through with no promise/try-catch overhead. This hook
|
|
59
|
+
// runs on every module resolution in the process.
|
|
60
|
+
return nextResolve(specifier, context);
|
|
61
|
+
}
|
|
62
|
+
function parentURLOf(context) {
|
|
63
|
+
if (context === null || typeof context !== "object") {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const parentURL = context.parentURL;
|
|
67
|
+
return typeof parentURL === "string" ? parentURL : undefined;
|
|
68
|
+
}
|
|
69
|
+
function withParentURL(context, parentURL) {
|
|
70
|
+
if (context !== null && typeof context === "object") {
|
|
71
|
+
return Object.assign(Object.assign({}, context), { parentURL });
|
|
72
|
+
}
|
|
73
|
+
return { parentURL };
|
|
74
|
+
}
|
|
75
|
+
function isBarePackageSpecifier(specifier) {
|
|
76
|
+
if (specifier.length === 0) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const first = specifier[0];
|
|
80
|
+
if (first === "." || first === "/" || first === "\\") {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return !(specifier.startsWith("node:") ||
|
|
84
|
+
specifier.startsWith("file:") ||
|
|
85
|
+
specifier.startsWith("data:") ||
|
|
86
|
+
specifier.startsWith("http:") ||
|
|
87
|
+
specifier.startsWith("https:"));
|
|
88
|
+
}
|
|
89
|
+
function isMonorepoAgentServeSource(parentURL) {
|
|
90
|
+
if (parentURL === undefined) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return (parentURL.includes("/packages/agent-serve/") &&
|
|
94
|
+
!parentURL.includes("/node_modules/"));
|
|
43
95
|
}
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
* imports of the framework resolve against the running package: the
|
|
12
12
|
* historical `@anysphere/agent-serve[/x]` name always, and
|
|
13
13
|
* `@cursor/july[/x]` / `@cursor/agentkit[/x]` as fallbacks when the user's
|
|
14
|
-
* project has no local install (npx / global).
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* project has no local install (npx / global). The same hooks retry bare
|
|
15
|
+
* npm specifiers from monorepo `packages/agent-serve/` source against this
|
|
16
|
+
* package (hosted factory engines install only the agent directory).
|
|
17
|
+
* Source runs (tsx from the monorepo) skip both — the host loader and
|
|
18
|
+
* tsconfig paths already cover them.
|
|
17
19
|
*/
|
|
18
20
|
/**
|
|
19
21
|
* ESM specifier for an authored agent/eval file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authored-loaders.d.ts","sourceRoot":"","sources":["../../src/internal/authored-loaders.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"authored-loaders.d.ts","sourceRoot":"","sources":["../../src/internal/authored-loaders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAyBH;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,MAAM,CAIR;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAclC;AAID;;;;;GAKG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAAC,IAAI,CAAC,CAS7D"}
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
* imports of the framework resolve against the running package: the
|
|
12
12
|
* historical `@anysphere/agent-serve[/x]` name always, and
|
|
13
13
|
* `@cursor/july[/x]` / `@cursor/agentkit[/x]` as fallbacks when the user's
|
|
14
|
-
* project has no local install (npx / global).
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* project has no local install (npx / global). The same hooks retry bare
|
|
15
|
+
* npm specifiers from monorepo `packages/agent-serve/` source against this
|
|
16
|
+
* package (hosted factory engines install only the agent directory).
|
|
17
|
+
* Source runs (tsx from the monorepo) skip both — the host loader and
|
|
18
|
+
* tsconfig paths already cover them.
|
|
17
19
|
*/
|
|
18
20
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
19
21
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
@@ -160,7 +162,14 @@ function registerFrameworkAliases() {
|
|
|
160
162
|
fallbackAliases[`${AGENTKIT_PACKAGE_NAME}${suffix}`] = target;
|
|
161
163
|
}
|
|
162
164
|
const hooksUrl = new URL("./authored-alias-hooks.js", import.meta.url);
|
|
163
|
-
const data = {
|
|
165
|
+
const data = {
|
|
166
|
+
directAliases,
|
|
167
|
+
fallbackAliases,
|
|
168
|
+
// Hosted factory agents relative-import this package's src/ from a
|
|
169
|
+
// monorepo checkout while npm install ran only in the agent directory.
|
|
170
|
+
// Bare specifiers from that tree retry against this package.json.
|
|
171
|
+
sourceTreeFallbackParentURL: pathToFileURL(join(packageRootDir(), "package.json")).href,
|
|
172
|
+
};
|
|
164
173
|
// `node:module`'s register() is synchronous: it blocks until the hooks
|
|
165
174
|
// thread has initialized, so the aliases are active when it returns.
|
|
166
175
|
registerModuleHooks(hooksUrl, { data });
|
|
@@ -42,10 +42,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
42
42
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
45
|
+
// Hosted engines install the consuming agent's directory alone and load this
|
|
46
|
+
// file as raw TypeScript source. Relative and `node:` imports resolve here;
|
|
47
|
+
// this package's own npm dependencies retry against the running `@cursor/july`
|
|
48
|
+
// install (authored-alias-hooks). Do not add deps that package does not have.
|
|
49
49
|
import { createHmac } from "node:crypto";
|
|
50
50
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
51
51
|
import { join } from "node:path";
|
|
@@ -94,6 +94,38 @@ export type GetReviewCommentsArgs = {
|
|
|
94
94
|
export type ReviewCommentReaderImplementation = {
|
|
95
95
|
getReviewComments: (args: GetReviewCommentsArgs) => Promise<ExistingReviewComment[]>;
|
|
96
96
|
};
|
|
97
|
+
export type ResolveReviewThreadsArgs = {
|
|
98
|
+
target: ScmReviewTarget;
|
|
99
|
+
/** REST comment ids whose threads should be resolved. */
|
|
100
|
+
commentIds: readonly number[];
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Outcome of resolving review threads for a set of comment ids. Callers
|
|
105
|
+
* treat this as best-effort actuation: a failed resolve must not fail the
|
|
106
|
+
* review that already posted.
|
|
107
|
+
*/
|
|
108
|
+
export type ResolveReviewThreadsResult = {
|
|
109
|
+
requested: number;
|
|
110
|
+
resolved: number;
|
|
111
|
+
alreadyResolved: number;
|
|
112
|
+
notFound: number;
|
|
113
|
+
failed: number;
|
|
114
|
+
detail: string;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Write side of thread resolution, the counterpart of
|
|
118
|
+
* {@link ReviewCommentReaderImplementation}. Bugbot's equivalent is
|
|
119
|
+
* `IGitProvider.resolveReviewThreadForComment` / `resolveThreads`.
|
|
120
|
+
*
|
|
121
|
+
* GitHub only exposes resolve via GraphQL (`resolveReviewThread`). REST
|
|
122
|
+
* has no equivalent. The mutation runs as whatever identity minted the
|
|
123
|
+
* bound GitHub client — for `githubChannel({ cursorAccount })` that is
|
|
124
|
+
* the Cursor installation, the same identity that posted the comments.
|
|
125
|
+
*/
|
|
126
|
+
export type ReviewThreadResolverImplementation = {
|
|
127
|
+
resolveReviewThreadsForComments: (args: ResolveReviewThreadsArgs) => Promise<ResolveReviewThreadsResult>;
|
|
128
|
+
};
|
|
97
129
|
/** Parse a PR URL into the SCM target to read comments from. */
|
|
98
130
|
export declare function resolveScmReviewTarget(prUrl: string): ScmReviewTarget | undefined;
|
|
99
131
|
/**
|
|
@@ -105,11 +137,41 @@ export declare function createReviewCommentReader(args: {
|
|
|
105
137
|
target: ScmReviewTarget;
|
|
106
138
|
github?: HostGitHubClient;
|
|
107
139
|
}): ReviewCommentReaderImplementation | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* Resolver for a resolved target. Returns undefined when the host cannot
|
|
142
|
+
* serve that provider, so callers degrade instead of throwing.
|
|
143
|
+
*/
|
|
144
|
+
export declare function createReviewThreadResolver(args: {
|
|
145
|
+
target: ScmReviewTarget;
|
|
146
|
+
github?: HostGitHubClient;
|
|
147
|
+
}): ReviewThreadResolverImplementation | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* Resolve the review threads that own `commentIds` on `prUrl`.
|
|
150
|
+
*
|
|
151
|
+
* No-ops (never throws) when the PR is on an SCM this host cannot write,
|
|
152
|
+
* no client is bound, or `commentIds` is empty. Same degrade-don't-fail
|
|
153
|
+
* posture as {@link createReviewCommentReader}.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resolveReviewThreadsForComments(args: {
|
|
156
|
+
prUrl: string;
|
|
157
|
+
commentIds: readonly number[];
|
|
158
|
+
github?: HostGitHubClient;
|
|
159
|
+
resolver?: ReviewThreadResolverImplementation;
|
|
160
|
+
signal?: AbortSignal;
|
|
161
|
+
}): Promise<ResolveReviewThreadsResult>;
|
|
108
162
|
/**
|
|
109
163
|
* Reads inline review comments through the host GitHub client (Cursor
|
|
110
164
|
* account lease, App installation token, or PAT).
|
|
111
165
|
*/
|
|
112
166
|
export declare function createHostGithubReviewCommentReader(github: HostGitHubClient): ReviewCommentReaderImplementation;
|
|
167
|
+
/**
|
|
168
|
+
* Resolves inline review threads through the host GitHub client (Cursor
|
|
169
|
+
* account lease, App installation token, or PAT). GitHub GraphQL has no
|
|
170
|
+
* comment→thread field, so this pages the PR's review threads and matches
|
|
171
|
+
* each REST comment id by `databaseId` — the same approach as Bugbot's
|
|
172
|
+
* `resolveReviewThreadForComment`.
|
|
173
|
+
*/
|
|
174
|
+
export declare function createHostGithubReviewThreadResolver(github: HostGitHubClient): ReviewThreadResolverImplementation;
|
|
113
175
|
type GithubReviewCommentLike = {
|
|
114
176
|
id: number;
|
|
115
177
|
path: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-comments.d.ts","sourceRoot":"","sources":["../../src/internal/review-comments.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"review-comments.d.ts","sourceRoot":"","sources":["../../src/internal/review-comments.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 {
|