@inkeep/agents-work-apps 0.46.0 → 0.47.0
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/env.d.ts +2 -2
- package/dist/github/mcp/index.js +47 -3
- package/dist/github/mcp/schemas.d.ts +9 -1
- package/dist/github/mcp/schemas.js +14 -3
- package/dist/github/mcp/utils.d.ts +7 -3
- package/dist/github/mcp/utils.js +181 -70
- package/dist/github/routes/tokenExchange.d.ts +2 -2
- package/dist/github/routes/webhooks.d.ts +2 -2
- package/package.json +2 -2
package/dist/env.d.ts
CHANGED
|
@@ -14,11 +14,11 @@ declare const envSchema: z.ZodObject<{
|
|
|
14
14
|
pentest: "pentest";
|
|
15
15
|
}>>;
|
|
16
16
|
LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
|
|
17
|
+
error: "error";
|
|
17
18
|
trace: "trace";
|
|
18
19
|
debug: "debug";
|
|
19
20
|
info: "info";
|
|
20
21
|
warn: "warn";
|
|
21
|
-
error: "error";
|
|
22
22
|
}>>;
|
|
23
23
|
INKEEP_AGENTS_RUN_DATABASE_URL: z.ZodString;
|
|
24
24
|
INKEEP_AGENTS_MANAGE_UI_URL: z.ZodOptional<z.ZodString>;
|
|
@@ -32,7 +32,7 @@ declare const envSchema: z.ZodObject<{
|
|
|
32
32
|
declare const env: {
|
|
33
33
|
NODE_ENV: "development" | "production" | "test";
|
|
34
34
|
ENVIRONMENT: "development" | "production" | "test" | "pentest";
|
|
35
|
-
LOG_LEVEL: "
|
|
35
|
+
LOG_LEVEL: "error" | "trace" | "debug" | "info" | "warn";
|
|
36
36
|
INKEEP_AGENTS_RUN_DATABASE_URL: string;
|
|
37
37
|
INKEEP_AGENTS_MANAGE_UI_URL?: string | undefined;
|
|
38
38
|
GITHUB_APP_ID?: string | undefined;
|
package/dist/github/mcp/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import runDbClient_default from "../../db/runDbClient.js";
|
|
2
2
|
import { githubMcpAuth } from "./auth.js";
|
|
3
|
-
import { commitFileChanges, commitNewFile, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getGitHubClientFromRepo, visualizeUpdateOperations } from "./utils.js";
|
|
3
|
+
import { commitFileChanges, commitNewFile, fetchComments, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getGitHubClientFromRepo, visualizeUpdateOperations } from "./utils.js";
|
|
4
4
|
import { getMcpToolRepositoryAccessWithDetails } from "@inkeep/agents-core";
|
|
5
5
|
import { Hono } from "hono";
|
|
6
6
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -78,6 +78,23 @@ const getServer = async (toolId) => {
|
|
|
78
78
|
text: `Found ${files.length} files matching "${query}" in ${repoFullName}:\n\n${files.map((file) => `• ${file.name} (${file.path})\n URL: ${file.url}\n Score: ${file.score}`).join("\n\n")}`
|
|
79
79
|
}] };
|
|
80
80
|
} catch (error) {
|
|
81
|
+
if (error instanceof Error && "status" in error) {
|
|
82
|
+
const apiError = error;
|
|
83
|
+
if (apiError.status === 403 || apiError.status === 429) {
|
|
84
|
+
const retryAfter = apiError.response?.headers?.["retry-after"];
|
|
85
|
+
const resetHeader = apiError.response?.headers?.["x-ratelimit-reset"];
|
|
86
|
+
let waitMessage = "";
|
|
87
|
+
if (retryAfter) waitMessage = ` Try again in ${retryAfter} seconds.`;
|
|
88
|
+
else if (resetHeader) waitMessage = ` Rate limit resets at ${(/* @__PURE__ */ new Date(Number(resetHeader) * 1e3)).toISOString()}.`;
|
|
89
|
+
return {
|
|
90
|
+
content: [{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `GitHub Search API rate limit exceeded.${waitMessage} The search API is limited to 30 requests per minute. Please wait before retrying.`
|
|
93
|
+
}],
|
|
94
|
+
isError: true
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
81
98
|
return {
|
|
82
99
|
content: [{
|
|
83
100
|
type: "text",
|
|
@@ -158,9 +175,14 @@ const getServer = async (toolId) => {
|
|
|
158
175
|
isError: true
|
|
159
176
|
};
|
|
160
177
|
}
|
|
178
|
+
const [pr, fileDiffs, comments] = await Promise.all([
|
|
179
|
+
fetchPrInfo(githubClient, owner, repo, pull_request_number),
|
|
180
|
+
fetchPrFileDiffs(githubClient, owner, repo, pull_request_number),
|
|
181
|
+
fetchComments(githubClient, owner, repo, pull_request_number)
|
|
182
|
+
]);
|
|
161
183
|
return { content: [{
|
|
162
184
|
type: "text",
|
|
163
|
-
text: generatePrMarkdown(
|
|
185
|
+
text: generatePrMarkdown(pr, fileDiffs, comments, owner, repo)
|
|
164
186
|
}] };
|
|
165
187
|
} catch (error) {
|
|
166
188
|
if (error instanceof Error && "status" in error) {
|
|
@@ -643,13 +665,35 @@ const getServer = async (toolId) => {
|
|
|
643
665
|
});
|
|
644
666
|
return server;
|
|
645
667
|
};
|
|
668
|
+
const SERVER_CACHE_TTL_MS = 300 * 1e3;
|
|
669
|
+
const SERVER_CACHE_MAX_SIZE = 100;
|
|
670
|
+
const serverCache = /* @__PURE__ */ new Map();
|
|
671
|
+
const getCachedServer = async (toolId) => {
|
|
672
|
+
const cached = serverCache.get(toolId);
|
|
673
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
674
|
+
serverCache.delete(toolId);
|
|
675
|
+
serverCache.set(toolId, cached);
|
|
676
|
+
return cached.server;
|
|
677
|
+
}
|
|
678
|
+
serverCache.delete(toolId);
|
|
679
|
+
const server = await getServer(toolId);
|
|
680
|
+
serverCache.set(toolId, {
|
|
681
|
+
server,
|
|
682
|
+
expiresAt: Date.now() + SERVER_CACHE_TTL_MS
|
|
683
|
+
});
|
|
684
|
+
if (serverCache.size > SERVER_CACHE_MAX_SIZE) {
|
|
685
|
+
const firstKey = serverCache.keys().next().value;
|
|
686
|
+
if (firstKey !== void 0) serverCache.delete(firstKey);
|
|
687
|
+
}
|
|
688
|
+
return server;
|
|
689
|
+
};
|
|
646
690
|
const app = new Hono();
|
|
647
691
|
app.use("/", githubMcpAuth());
|
|
648
692
|
app.post("/", async (c) => {
|
|
649
693
|
if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_APP_PRIVATE_KEY) return c.json({ error: "GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY must be set" }, 500);
|
|
650
694
|
const toolId = c.get("toolId");
|
|
651
695
|
const body = await c.req.json();
|
|
652
|
-
const server = await
|
|
696
|
+
const server = await getCachedServer(toolId);
|
|
653
697
|
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
654
698
|
server.connect(transport);
|
|
655
699
|
const { req, res } = toReqRes(c.req.raw);
|
|
@@ -65,13 +65,21 @@ declare const CommentSchema: z.ZodObject<{
|
|
|
65
65
|
url: z.ZodURL;
|
|
66
66
|
}, z.core.$strip>;
|
|
67
67
|
createdAt: z.ZodString;
|
|
68
|
-
updatedAt: z.ZodString
|
|
68
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
69
69
|
type: z.ZodEnum<{
|
|
70
70
|
issue: "issue";
|
|
71
71
|
review: "review";
|
|
72
|
+
review_summary: "review_summary";
|
|
72
73
|
}>;
|
|
73
74
|
path: z.ZodOptional<z.ZodString>;
|
|
74
75
|
line: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
state: z.ZodOptional<z.ZodEnum<{
|
|
77
|
+
APPROVED: "APPROVED";
|
|
78
|
+
CHANGES_REQUESTED: "CHANGES_REQUESTED";
|
|
79
|
+
COMMENTED: "COMMENTED";
|
|
80
|
+
DISMISSED: "DISMISSED";
|
|
81
|
+
PENDING: "PENDING";
|
|
82
|
+
}>>;
|
|
75
83
|
}, z.core.$strip>;
|
|
76
84
|
declare const GitHubEventSchema: z.ZodObject<{
|
|
77
85
|
type: z.ZodString;
|
|
@@ -55,10 +55,21 @@ const CommentSchema = z.object({
|
|
|
55
55
|
body: z.string(),
|
|
56
56
|
author: GitHubUserSchema,
|
|
57
57
|
createdAt: z.string(),
|
|
58
|
-
updatedAt: z.string(),
|
|
59
|
-
type: z.enum([
|
|
58
|
+
updatedAt: z.string().optional(),
|
|
59
|
+
type: z.enum([
|
|
60
|
+
"issue",
|
|
61
|
+
"review",
|
|
62
|
+
"review_summary"
|
|
63
|
+
]),
|
|
60
64
|
path: z.string().optional(),
|
|
61
|
-
line: z.number().optional()
|
|
65
|
+
line: z.number().optional(),
|
|
66
|
+
state: z.enum([
|
|
67
|
+
"APPROVED",
|
|
68
|
+
"CHANGES_REQUESTED",
|
|
69
|
+
"COMMENTED",
|
|
70
|
+
"DISMISSED",
|
|
71
|
+
"PENDING"
|
|
72
|
+
]).optional()
|
|
62
73
|
});
|
|
63
74
|
const GitHubEventSchema = z.object({
|
|
64
75
|
type: z.string(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChangedFile, PullRequest } from "./schemas.js";
|
|
1
|
+
import { ChangedFile, Comment, PullRequest } from "./schemas.js";
|
|
2
2
|
import { Octokit } from "@octokit/rest";
|
|
3
3
|
|
|
4
4
|
//#region src/github/mcp/utils.d.ts
|
|
@@ -152,10 +152,14 @@ declare function fetchPrFiles(octokit: Octokit, owner: string, repo: string, prN
|
|
|
152
152
|
* Get file-based diffs with all commit messages that impacted each file.
|
|
153
153
|
*/
|
|
154
154
|
declare function fetchPrFileDiffs(octokit: Octokit, owner: string, repo: string, prNumber: number): Promise<ChangedFile[]>;
|
|
155
|
+
/**
|
|
156
|
+
* Fetch all PR comments (both issue comments and review comments)
|
|
157
|
+
*/
|
|
158
|
+
declare function fetchComments(octokit: Octokit, owner: string, repo: string, prNumber: number): Promise<Comment[]>;
|
|
155
159
|
/**
|
|
156
160
|
* Generate a markdown representation of a pull request with file diffs
|
|
157
161
|
*/
|
|
158
|
-
declare function generatePrMarkdown(pr: PullRequest, fileDiffs: ChangedFile[], owner: string, repo: string): string;
|
|
162
|
+
declare function generatePrMarkdown(pr: PullRequest, fileDiffs: ChangedFile[], comments: Comment[], owner: string, repo: string): string;
|
|
159
163
|
interface LLMUpdateOperation {
|
|
160
164
|
operation: 'replace_lines' | 'insert_after' | 'insert_before' | 'delete_lines';
|
|
161
165
|
lineStart: number;
|
|
@@ -225,4 +229,4 @@ declare function commitNewFile({
|
|
|
225
229
|
}): Promise<string>;
|
|
226
230
|
declare function formatFileDiff(pullRequestNumber: number, files: ChangedFile[], includeContents?: boolean): Promise<string>;
|
|
227
231
|
//#endregion
|
|
228
|
-
export { CommitData, LLMUpdateOperation, PullCommit, applyOperation, applyOperations, commitFileChanges, commitNewFile, fetchCommitDetails, fetchPrCommits, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getFilePathsInRepo, getGitHubClientFromInstallationId, getGitHubClientFromRepo, validateLineNumbers, visualizeUpdateOperations };
|
|
232
|
+
export { CommitData, LLMUpdateOperation, PullCommit, applyOperation, applyOperations, commitFileChanges, commitNewFile, fetchComments, fetchCommitDetails, fetchPrCommits, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getFilePathsInRepo, getGitHubClientFromInstallationId, getGitHubClientFromRepo, validateLineNumbers, visualizeUpdateOperations };
|
package/dist/github/mcp/utils.js
CHANGED
|
@@ -127,8 +127,8 @@ async function fetchPrFiles(octokit, owner, repo, prNumber, pathFilters = [], in
|
|
|
127
127
|
includeContents,
|
|
128
128
|
includePatch
|
|
129
129
|
}, `Fetching PR #${prNumber} changed files`);
|
|
130
|
-
const files = [];
|
|
131
130
|
const headSha = (await fetchPrInfo(octokit, owner, repo, prNumber)).head.sha;
|
|
131
|
+
const collectedFiles = [];
|
|
132
132
|
for await (const response of octokit.paginate.iterator(octokit.rest.pulls.listFiles, {
|
|
133
133
|
owner,
|
|
134
134
|
repo,
|
|
@@ -136,7 +136,7 @@ async function fetchPrFiles(octokit, owner, repo, prNumber, pathFilters = [], in
|
|
|
136
136
|
per_page: 100
|
|
137
137
|
})) for (const file of response.data) {
|
|
138
138
|
if (pathFilters.length > 0 && !pathFilters.some((filter) => minimatch(file.filename, filter))) continue;
|
|
139
|
-
|
|
139
|
+
collectedFiles.push({
|
|
140
140
|
commit_messages: [],
|
|
141
141
|
path: file.filename,
|
|
142
142
|
status: file.status,
|
|
@@ -144,25 +144,33 @@ async function fetchPrFiles(octokit, owner, repo, prNumber, pathFilters = [], in
|
|
|
144
144
|
deletions: file.deletions,
|
|
145
145
|
patch: includePatch ? file.patch : void 0,
|
|
146
146
|
previousPath: file.previous_filename
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (includeContents) {
|
|
150
|
+
const BATCH_SIZE = 10;
|
|
151
|
+
const filesToFetch = collectedFiles.filter((f) => f.status !== "removed");
|
|
152
|
+
for (let i = 0; i < filesToFetch.length; i += BATCH_SIZE) {
|
|
153
|
+
const batch = filesToFetch.slice(i, i + BATCH_SIZE);
|
|
154
|
+
await Promise.all(batch.map(async (changedFile) => {
|
|
155
|
+
try {
|
|
156
|
+
const { data: content } = await octokit.rest.repos.getContent({
|
|
157
|
+
owner,
|
|
158
|
+
repo,
|
|
159
|
+
path: changedFile.path,
|
|
160
|
+
ref: headSha
|
|
161
|
+
});
|
|
162
|
+
if ("content" in content && content.encoding === "base64") changedFile.contents = Buffer.from(content.content, "base64").toString("utf-8");
|
|
163
|
+
} catch (error) {
|
|
164
|
+
logger.warn({
|
|
165
|
+
owner,
|
|
166
|
+
repo,
|
|
167
|
+
prNumber,
|
|
168
|
+
headSha,
|
|
169
|
+
file: changedFile.path
|
|
170
|
+
}, `Failed to fetch contents for ${changedFile.path}: ${error}`);
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
164
173
|
}
|
|
165
|
-
files.push(changedFile);
|
|
166
174
|
}
|
|
167
175
|
logger.info({
|
|
168
176
|
owner,
|
|
@@ -171,47 +179,51 @@ async function fetchPrFiles(octokit, owner, repo, prNumber, pathFilters = [], in
|
|
|
171
179
|
headSha,
|
|
172
180
|
pathFilters,
|
|
173
181
|
includeContents,
|
|
174
|
-
|
|
175
|
-
}, `Found ${
|
|
176
|
-
return
|
|
182
|
+
fileCount: collectedFiles.length
|
|
183
|
+
}, `Found ${collectedFiles.length} changed files${pathFilters.length > 0 ? ` matching "${pathFilters.join(", ")}"` : ""}`);
|
|
184
|
+
return collectedFiles;
|
|
177
185
|
}
|
|
178
186
|
/**
|
|
179
187
|
* Get file-based diffs with all commit messages that impacted each file.
|
|
180
188
|
*/
|
|
181
189
|
async function fetchPrFileDiffs(octokit, owner, repo, prNumber) {
|
|
182
190
|
try {
|
|
183
|
-
const commits = await fetchPrCommits(octokit, owner, repo, prNumber);
|
|
184
|
-
const
|
|
191
|
+
const [commits, prFiles] = await Promise.all([fetchPrCommits(octokit, owner, repo, prNumber), fetchPrFiles(octokit, owner, repo, prNumber)]);
|
|
192
|
+
const BATCH_SIZE = 10;
|
|
193
|
+
const commitDetailsList = [];
|
|
194
|
+
for (let i = 0; i < commits.length; i += BATCH_SIZE) {
|
|
195
|
+
const batch = commits.slice(i, i + BATCH_SIZE);
|
|
196
|
+
const batchResults = await Promise.all(batch.map(async (commit) => {
|
|
197
|
+
const commitDetails = await fetchCommitDetails(octokit, owner, repo, commit.sha);
|
|
198
|
+
return {
|
|
199
|
+
sha: commit.sha,
|
|
200
|
+
message: commit.commit.message,
|
|
201
|
+
files: commitDetails.files
|
|
202
|
+
};
|
|
203
|
+
}));
|
|
204
|
+
commitDetailsList.push(...batchResults);
|
|
205
|
+
}
|
|
185
206
|
const fileToCommits = {};
|
|
186
|
-
for (const
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
commit_sha: commitSha,
|
|
195
|
-
commit_message: commitMessage,
|
|
196
|
-
file_info: fileInfo
|
|
197
|
-
});
|
|
198
|
-
}
|
|
207
|
+
for (const { sha, message, files } of commitDetailsList) for (const fileInfo of files || []) {
|
|
208
|
+
const filename = fileInfo.filename;
|
|
209
|
+
if (!fileToCommits[filename]) fileToCommits[filename] = [];
|
|
210
|
+
fileToCommits[filename].push({
|
|
211
|
+
commit_sha: sha,
|
|
212
|
+
commit_message: message,
|
|
213
|
+
file_info: fileInfo
|
|
214
|
+
});
|
|
199
215
|
}
|
|
200
216
|
const fileDiffs = [];
|
|
201
217
|
for (const prFile of prFiles) {
|
|
202
218
|
const filename = prFile.path;
|
|
203
219
|
if (filename in fileToCommits) {
|
|
204
|
-
const commitMessages = fileToCommits[filename].map((commitData) => commitData.commit_message);
|
|
205
|
-
const diff = prFile.patch;
|
|
206
|
-
const additions = prFile.additions || 0;
|
|
207
|
-
const deletions = prFile.deletions || 0;
|
|
208
220
|
const githubFileDiff = {
|
|
209
|
-
commit_messages:
|
|
221
|
+
commit_messages: fileToCommits[filename].map((commitData) => commitData.commit_message),
|
|
210
222
|
path: filename,
|
|
211
223
|
status: prFile.status,
|
|
212
|
-
additions,
|
|
213
|
-
deletions,
|
|
214
|
-
patch:
|
|
224
|
+
additions: prFile.additions || 0,
|
|
225
|
+
deletions: prFile.deletions || 0,
|
|
226
|
+
patch: prFile.patch
|
|
215
227
|
};
|
|
216
228
|
fileDiffs.push(githubFileDiff);
|
|
217
229
|
}
|
|
@@ -222,34 +234,133 @@ async function fetchPrFileDiffs(octokit, owner, repo, prNumber) {
|
|
|
222
234
|
}
|
|
223
235
|
}
|
|
224
236
|
/**
|
|
237
|
+
* Fetch all PR comments (both issue comments and review comments)
|
|
238
|
+
*/
|
|
239
|
+
async function fetchComments(octokit, owner, repo, prNumber) {
|
|
240
|
+
const [issueComments, reviewComments, reviewSummaries] = await Promise.all([
|
|
241
|
+
(async () => {
|
|
242
|
+
const results = [];
|
|
243
|
+
for await (const response of octokit.paginate.iterator(octokit.rest.issues.listComments, {
|
|
244
|
+
owner,
|
|
245
|
+
repo,
|
|
246
|
+
issue_number: prNumber,
|
|
247
|
+
per_page: 100
|
|
248
|
+
})) for (const comment of response.data) {
|
|
249
|
+
if (!comment.user) continue;
|
|
250
|
+
results.push({
|
|
251
|
+
id: comment.id,
|
|
252
|
+
body: comment.body || "",
|
|
253
|
+
author: mapUser(comment.user),
|
|
254
|
+
createdAt: comment.created_at,
|
|
255
|
+
updatedAt: comment.updated_at,
|
|
256
|
+
type: "issue"
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return results;
|
|
260
|
+
})(),
|
|
261
|
+
(async () => {
|
|
262
|
+
const results = [];
|
|
263
|
+
for await (const response of octokit.paginate.iterator(octokit.rest.pulls.listReviewComments, {
|
|
264
|
+
owner,
|
|
265
|
+
repo,
|
|
266
|
+
pull_number: prNumber,
|
|
267
|
+
per_page: 100
|
|
268
|
+
})) for (const comment of response.data) results.push({
|
|
269
|
+
id: comment.id,
|
|
270
|
+
body: comment.body,
|
|
271
|
+
author: mapUser(comment.user),
|
|
272
|
+
createdAt: comment.created_at,
|
|
273
|
+
updatedAt: comment.updated_at,
|
|
274
|
+
type: "review",
|
|
275
|
+
path: comment.path,
|
|
276
|
+
line: comment.line || comment.original_line
|
|
277
|
+
});
|
|
278
|
+
return results;
|
|
279
|
+
})(),
|
|
280
|
+
(async () => {
|
|
281
|
+
const results = [];
|
|
282
|
+
for await (const response of octokit.paginate.iterator(octokit.rest.pulls.listReviews, {
|
|
283
|
+
owner,
|
|
284
|
+
repo,
|
|
285
|
+
pull_number: prNumber,
|
|
286
|
+
per_page: 100
|
|
287
|
+
})) for (const review of response.data) if (review.body && review.user) results.push({
|
|
288
|
+
id: review.id,
|
|
289
|
+
body: review.body,
|
|
290
|
+
author: mapUser(review.user),
|
|
291
|
+
createdAt: review.submitted_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
292
|
+
type: "review_summary",
|
|
293
|
+
state: review.state
|
|
294
|
+
});
|
|
295
|
+
return results;
|
|
296
|
+
})()
|
|
297
|
+
]);
|
|
298
|
+
return [
|
|
299
|
+
...issueComments,
|
|
300
|
+
...reviewComments,
|
|
301
|
+
...reviewSummaries
|
|
302
|
+
].filter((c) => {
|
|
303
|
+
const login = c.author.login;
|
|
304
|
+
if (login.endsWith("[bot]") && login !== "inkeep[bot]") return false;
|
|
305
|
+
return true;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
225
309
|
* Generate a markdown representation of a pull request with file diffs
|
|
226
310
|
*/
|
|
227
|
-
function generatePrMarkdown(pr, fileDiffs, owner, repo) {
|
|
311
|
+
function generatePrMarkdown(pr, fileDiffs, comments, owner, repo) {
|
|
228
312
|
let markdown = `# Pull Request #${pr.number}: ${pr.title}\n\n`;
|
|
229
|
-
markdown +=
|
|
230
|
-
markdown +=
|
|
231
|
-
markdown +=
|
|
232
|
-
markdown +=
|
|
233
|
-
markdown +=
|
|
234
|
-
markdown +=
|
|
235
|
-
markdown +=
|
|
236
|
-
markdown +=
|
|
237
|
-
markdown +=
|
|
238
|
-
if (pr.body) markdown +=
|
|
239
|
-
|
|
240
|
-
if (fileDiffs.length > 0) {
|
|
241
|
-
markdown +=
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
markdown +=
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
313
|
+
markdown += "<metadata>\n";
|
|
314
|
+
markdown += `Repository: ${owner}/${repo}\n`;
|
|
315
|
+
markdown += `State: ${pr.state}\n`;
|
|
316
|
+
markdown += `Author: ${pr.author.login}\n`;
|
|
317
|
+
markdown += `Created: ${new Date(pr.createdAt).toLocaleDateString()}\n`;
|
|
318
|
+
markdown += `Updated: ${new Date(pr.updatedAt).toLocaleDateString()}\n`;
|
|
319
|
+
markdown += `Branch: ${pr.head.ref} → ${pr.base.ref}\n`;
|
|
320
|
+
markdown += `URL: ${pr.url}\n`;
|
|
321
|
+
markdown += "</metadata>\n\n";
|
|
322
|
+
if (pr.body) markdown += `<description>\n${pr.body}\n</description>\n\n`;
|
|
323
|
+
markdown += "<files>\n";
|
|
324
|
+
if (fileDiffs.length > 0) for (const fileDiff of fileDiffs) {
|
|
325
|
+
markdown += `${fileDiff.path} (+${fileDiff.additions}/-${fileDiff.deletions})\n`;
|
|
326
|
+
if (fileDiff.commit_messages.length > 0) {
|
|
327
|
+
const uniqueMessages = [...new Set(fileDiff.commit_messages)];
|
|
328
|
+
for (const message of uniqueMessages) markdown += ` - ${message.split("\n")[0]}\n`;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
markdown += "</files>\n\n";
|
|
332
|
+
if (comments.length > 0) {
|
|
333
|
+
markdown += "<comments>\n";
|
|
334
|
+
const reviewSummaries = comments.filter((c) => c.type === "review_summary");
|
|
335
|
+
const issueComments = comments.filter((c) => c.type === "issue");
|
|
336
|
+
const reviewComments = comments.filter((c) => c.type === "review");
|
|
337
|
+
for (const review of reviewSummaries) {
|
|
338
|
+
markdown += `[${review.state}] @${review.author.login} (${new Date(review.createdAt).toLocaleDateString()})\n`;
|
|
339
|
+
if (review.body) markdown += `${review.body}\n`;
|
|
251
340
|
markdown += "\n";
|
|
252
341
|
}
|
|
342
|
+
for (const comment of issueComments) {
|
|
343
|
+
markdown += `@${comment.author.login} (${new Date(comment.createdAt).toLocaleDateString()})\n`;
|
|
344
|
+
markdown += `${comment.body}\n\n`;
|
|
345
|
+
}
|
|
346
|
+
if (reviewComments.length > 0) {
|
|
347
|
+
const commentsByFile = /* @__PURE__ */ new Map();
|
|
348
|
+
for (const comment of reviewComments) {
|
|
349
|
+
const path = comment.path || "unknown";
|
|
350
|
+
const existing = commentsByFile.get(path) || [];
|
|
351
|
+
existing.push(comment);
|
|
352
|
+
commentsByFile.set(path, existing);
|
|
353
|
+
}
|
|
354
|
+
for (const [path, fileComments] of commentsByFile) {
|
|
355
|
+
markdown += `${path}:\n`;
|
|
356
|
+
for (const comment of fileComments) {
|
|
357
|
+
const lineInfo = comment.line ? ` line ${comment.line}` : "";
|
|
358
|
+
markdown += ` @${comment.author.login}${lineInfo} (${new Date(comment.createdAt).toLocaleDateString()})\n`;
|
|
359
|
+
markdown += ` ${comment.body}\n\n`;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
markdown += "</comments>\n";
|
|
253
364
|
}
|
|
254
365
|
return markdown;
|
|
255
366
|
}
|
|
@@ -461,4 +572,4 @@ async function formatFileDiff(pullRequestNumber, files, includeContents = false)
|
|
|
461
572
|
}
|
|
462
573
|
|
|
463
574
|
//#endregion
|
|
464
|
-
export { applyOperation, applyOperations, commitFileChanges, commitNewFile, fetchCommitDetails, fetchPrCommits, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getFilePathsInRepo, getGitHubClientFromInstallationId, getGitHubClientFromRepo, validateLineNumbers, visualizeUpdateOperations };
|
|
575
|
+
export { applyOperation, applyOperations, commitFileChanges, commitNewFile, fetchComments, fetchCommitDetails, fetchPrCommits, fetchPrFileDiffs, fetchPrFiles, fetchPrInfo, formatFileDiff, generatePrMarkdown, getFilePathsInRepo, getGitHubClientFromInstallationId, getGitHubClientFromRepo, validateLineNumbers, visualizeUpdateOperations };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types8 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/tokenExchange.d.ts
|
|
5
|
-
declare const app: Hono<
|
|
5
|
+
declare const app: Hono<hono_types8.BlankEnv, hono_types8.BlankSchema, "/">;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { app as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import * as
|
|
2
|
+
import * as hono_types6 from "hono/types";
|
|
3
3
|
|
|
4
4
|
//#region src/github/routes/webhooks.d.ts
|
|
5
5
|
interface WebhookVerificationResult {
|
|
@@ -7,6 +7,6 @@ interface WebhookVerificationResult {
|
|
|
7
7
|
error?: string;
|
|
8
8
|
}
|
|
9
9
|
declare function verifyWebhookSignature(payload: string, signature: string | undefined, secret: string): WebhookVerificationResult;
|
|
10
|
-
declare const app: Hono<
|
|
10
|
+
declare const app: Hono<hono_types6.BlankEnv, hono_types6.BlankSchema, "/">;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { WebhookVerificationResult, app as default, verifyWebhookSignature };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/agents-work-apps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "First party integrations for Inkeep Agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"hono": "^4.11.7",
|
|
25
25
|
"jose": "^6.1.0",
|
|
26
26
|
"minimatch": "^10.1.1",
|
|
27
|
-
"@inkeep/agents-core": "0.
|
|
27
|
+
"@inkeep/agents-core": "0.47.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@hono/zod-openapi": "^1.1.5",
|