Update lock
This commit is contained in:
committed by
pullfrog[bot]
parent
c15049446f
commit
57895ae342
@@ -3,6 +3,7 @@ import { initToolState, startMcpHttpServer } from "./mcp/server.ts";
|
||||
import { computeModes } from "./modes.ts";
|
||||
import { resolveAgent } from "./utils/agent.ts";
|
||||
import { validateApiKey } from "./utils/apiKeys.ts";
|
||||
import { resolveBody } from "./utils/body.ts";
|
||||
import { log, writeSummary } from "./utils/cli.ts";
|
||||
import { reportErrorToComment } from "./utils/errorReport.ts";
|
||||
import { createOctokit } from "./utils/github.ts";
|
||||
@@ -50,6 +51,18 @@ export async function main(): Promise<MainResult> {
|
||||
process.chdir(payload.cwd);
|
||||
}
|
||||
|
||||
// resolve body - fetches body_html and converts to markdown if images present
|
||||
// this ensures agents receive markdown with working signed image URLs
|
||||
const originalBody = payload.event.body;
|
||||
const resolvedBody = await resolveBody({ event: payload.event, octokit, repo });
|
||||
if (resolvedBody !== originalBody) {
|
||||
payload.event.body = resolvedBody;
|
||||
// also update prompt if original body was included there
|
||||
if (originalBody && payload.prompt.includes(originalBody)) {
|
||||
payload.prompt = payload.prompt.replace(originalBody, resolvedBody ?? "");
|
||||
}
|
||||
}
|
||||
|
||||
const tmpdir = createTempDirectory();
|
||||
|
||||
const agent = resolveAgent({ payload, repoSettings: repo.repoSettings });
|
||||
|
||||
+4
-1
@@ -43,11 +43,14 @@
|
||||
"fastmcp": "^3.26.8",
|
||||
"package-manager-detector": "^1.6.0",
|
||||
"semver": "^7.7.3",
|
||||
"table": "^6.9.0"
|
||||
"table": "^6.9.0",
|
||||
"turndown": "^7.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2",
|
||||
"@types/turndown": "^5.0.5",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/turndown": "^5.0.5",
|
||||
"arg": "^5.0.2",
|
||||
"esbuild": "^0.25.9",
|
||||
"husky": "^9.0.0",
|
||||
|
||||
Generated
+23
@@ -65,6 +65,9 @@ importers:
|
||||
table:
|
||||
specifier: ^6.9.0
|
||||
version: 6.9.0
|
||||
turndown:
|
||||
specifier: ^7.2.0
|
||||
version: 7.2.2
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^24.7.2
|
||||
@@ -72,6 +75,9 @@ importers:
|
||||
'@types/semver':
|
||||
specifier: ^7.7.1
|
||||
version: 7.7.1
|
||||
'@types/turndown':
|
||||
specifier: ^5.0.5
|
||||
version: 5.0.6
|
||||
arg:
|
||||
specifier: ^5.0.2
|
||||
version: 5.0.2
|
||||
@@ -534,6 +540,9 @@ packages:
|
||||
'@jridgewell/sourcemap-codec@1.5.5':
|
||||
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||
|
||||
'@mixmark-io/domino@2.2.0':
|
||||
resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.25.2':
|
||||
resolution: {integrity: sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -826,6 +835,9 @@ packages:
|
||||
'@types/semver@7.7.1':
|
||||
resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==}
|
||||
|
||||
'@types/turndown@5.0.6':
|
||||
resolution: {integrity: sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==}
|
||||
|
||||
'@vitest/expect@4.0.17':
|
||||
resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==}
|
||||
|
||||
@@ -1500,6 +1512,9 @@ packages:
|
||||
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
|
||||
engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
|
||||
|
||||
turndown@7.2.2:
|
||||
resolution: {integrity: sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==}
|
||||
|
||||
type-is@2.0.1:
|
||||
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@@ -1959,6 +1974,8 @@ snapshots:
|
||||
|
||||
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||
|
||||
'@mixmark-io/domino@2.2.0': {}
|
||||
|
||||
'@modelcontextprotocol/sdk@1.25.2(hono@4.11.3)(zod@4.3.5)':
|
||||
dependencies:
|
||||
'@hono/node-server': 1.19.7(hono@4.11.3)
|
||||
@@ -2226,6 +2243,8 @@ snapshots:
|
||||
|
||||
'@types/semver@7.7.1': {}
|
||||
|
||||
'@types/turndown@5.0.6': {}
|
||||
|
||||
'@vitest/expect@4.0.17':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.0.0
|
||||
@@ -2980,6 +2999,10 @@ snapshots:
|
||||
|
||||
tunnel@0.0.6: {}
|
||||
|
||||
turndown@7.2.2:
|
||||
dependencies:
|
||||
'@mixmark-io/domino': 2.2.0
|
||||
|
||||
type-is@2.0.1:
|
||||
dependencies:
|
||||
content-type: 1.0.5
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
import TurndownService from "turndown";
|
||||
import type { PayloadEvent } from "../external.ts";
|
||||
import type { OctokitWithPlugins } from "./github.ts";
|
||||
import type { RepoData } from "./repoData.ts";
|
||||
|
||||
const turndown = new TurndownService();
|
||||
|
||||
function hasImages(body: string | null | undefined): boolean {
|
||||
if (!body) return false;
|
||||
return body.includes("<img") || body.includes("![");
|
||||
}
|
||||
|
||||
interface ResolveBodyContext {
|
||||
event: PayloadEvent;
|
||||
octokit: OctokitWithPlugins;
|
||||
repo: RepoData;
|
||||
}
|
||||
|
||||
/**
|
||||
* resolves the body of an event by fetching body_html and converting to markdown.
|
||||
* only fetches body_html if the body contains images (to avoid unnecessary API calls).
|
||||
* this ensures agents receive markdown with working signed image URLs instead of
|
||||
* broken user-attachments URLs.
|
||||
*/
|
||||
export async function resolveBody(ctx: ResolveBodyContext): Promise<string | null> {
|
||||
const body = ctx.event.body;
|
||||
|
||||
// pass through if no images - no API call needed
|
||||
if (!hasImages(body)) return body ?? null;
|
||||
|
||||
const bodyHtml = await fetchBodyHtml(ctx);
|
||||
if (!bodyHtml) return body ?? null;
|
||||
|
||||
return turndown.turndown(bodyHtml);
|
||||
}
|
||||
|
||||
async function fetchBodyHtml(ctx: ResolveBodyContext): Promise<string | undefined> {
|
||||
const event = ctx.event;
|
||||
const headers = { accept: "application/vnd.github.full+json" };
|
||||
const owner = ctx.repo.owner;
|
||||
const repo = ctx.repo.name;
|
||||
|
||||
switch (event.trigger) {
|
||||
case "issue_comment_created":
|
||||
if (!event.comment_id) return;
|
||||
return (
|
||||
await ctx.octokit.rest.issues.getComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: event.comment_id,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
case "issues_opened":
|
||||
case "issues_assigned":
|
||||
case "issues_labeled":
|
||||
if (!event.issue_number) return;
|
||||
return (
|
||||
await ctx.octokit.rest.issues.get({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: event.issue_number,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
case "pull_request_opened":
|
||||
case "pull_request_ready_for_review":
|
||||
case "pull_request_review_requested":
|
||||
// PRs are also issues - use issues.get which returns body_html
|
||||
if (!event.issue_number) return;
|
||||
return (
|
||||
await ctx.octokit.rest.issues.get({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: event.issue_number,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
case "pull_request_review_submitted":
|
||||
if (!event.issue_number || !event.review_id) return;
|
||||
return (
|
||||
await ctx.octokit.rest.pulls.getReview({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: event.issue_number,
|
||||
review_id: event.review_id,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
case "pull_request_review_comment_created":
|
||||
if (!event.comment_id) return;
|
||||
return (
|
||||
await ctx.octokit.rest.pulls.getReviewComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: event.comment_id,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
case "check_suite_completed":
|
||||
// body is the PR body
|
||||
if (!event.issue_number) return;
|
||||
return (
|
||||
await ctx.octokit.rest.issues.get({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: event.issue_number,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
case "implement_plan":
|
||||
// body is the plan content from an issue comment
|
||||
if (!event.plan_comment_id) return;
|
||||
return (
|
||||
await ctx.octokit.rest.issues.getComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: event.plan_comment_id,
|
||||
headers,
|
||||
})
|
||||
).data.body_html;
|
||||
|
||||
// triggers without a body field that needs resolution
|
||||
case "workflow_dispatch":
|
||||
case "fix_review":
|
||||
case "unknown":
|
||||
return undefined;
|
||||
|
||||
default:
|
||||
// exhaustiveness check - TypeScript will error if a trigger is missing
|
||||
event satisfies never;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user