pullfrog 0.0.203 → 0.0.204
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/cli.mjs +455 -165
- package/dist/external.d.ts +5 -2
- package/dist/index.js +378 -138
- package/dist/internal/index.d.ts +2 -0
- package/dist/internal.js +108 -7
- package/dist/mcp/comment.d.ts +6 -3
- package/dist/mcp/git.d.ts +2 -0
- package/dist/mcp/reviewComments.d.ts +29 -0
- package/dist/mcp/server.d.ts +9 -2
- package/dist/utils/payload.d.ts +8 -2
- package/dist/utils/progressComment.d.ts +146 -0
- package/dist/utils/runContext.d.ts +16 -0
- package/dist/utils/runContextData.d.ts +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -107816,14 +107816,14 @@ var providers = {
|
|
|
107816
107816
|
models: {
|
|
107817
107817
|
grok: {
|
|
107818
107818
|
displayName: "Grok",
|
|
107819
|
-
resolve: "xai/grok-4",
|
|
107820
|
-
openRouterResolve: "openrouter/x-ai/grok-4",
|
|
107819
|
+
resolve: "xai/grok-4.3",
|
|
107820
|
+
openRouterResolve: "openrouter/x-ai/grok-4.3",
|
|
107821
107821
|
preferred: true
|
|
107822
107822
|
},
|
|
107823
107823
|
"grok-fast": {
|
|
107824
107824
|
displayName: "Grok Fast",
|
|
107825
|
-
resolve: "xai/grok-4-fast",
|
|
107826
|
-
openRouterResolve: "openrouter/x-ai/grok-4-fast"
|
|
107825
|
+
resolve: "xai/grok-4-1-fast",
|
|
107826
|
+
openRouterResolve: "openrouter/x-ai/grok-4.1-fast"
|
|
107827
107827
|
},
|
|
107828
107828
|
"grok-code-fast": {
|
|
107829
107829
|
displayName: "Grok Code Fast",
|
|
@@ -108030,8 +108030,8 @@ var providers = {
|
|
|
108030
108030
|
},
|
|
108031
108031
|
grok: {
|
|
108032
108032
|
displayName: "Grok",
|
|
108033
|
-
resolve: "openrouter/x-ai/grok-4",
|
|
108034
|
-
openRouterResolve: "openrouter/x-ai/grok-4"
|
|
108033
|
+
resolve: "openrouter/x-ai/grok-4.3",
|
|
108034
|
+
openRouterResolve: "openrouter/x-ai/grok-4.3"
|
|
108035
108035
|
},
|
|
108036
108036
|
"deepseek-pro": {
|
|
108037
108037
|
displayName: "DeepSeek Pro",
|
|
@@ -108300,6 +108300,93 @@ function aggregateUsage(entries) {
|
|
|
108300
108300
|
return out;
|
|
108301
108301
|
}
|
|
108302
108302
|
|
|
108303
|
+
// utils/progressComment.ts
|
|
108304
|
+
function parseProgressComment(raw2) {
|
|
108305
|
+
if (!raw2?.id) return void 0;
|
|
108306
|
+
const id = parseInt(raw2.id, 10);
|
|
108307
|
+
if (Number.isNaN(id) || id <= 0) return void 0;
|
|
108308
|
+
return { id, type: raw2.type };
|
|
108309
|
+
}
|
|
108310
|
+
async function updateProgressComment(ctx, comment, body) {
|
|
108311
|
+
const result = await (comment.type === "review" ? ctx.octokit.rest.pulls.updateReviewComment({
|
|
108312
|
+
owner: ctx.owner,
|
|
108313
|
+
repo: ctx.repo,
|
|
108314
|
+
comment_id: comment.id,
|
|
108315
|
+
body
|
|
108316
|
+
}) : ctx.octokit.rest.issues.updateComment({
|
|
108317
|
+
owner: ctx.owner,
|
|
108318
|
+
repo: ctx.repo,
|
|
108319
|
+
comment_id: comment.id,
|
|
108320
|
+
body
|
|
108321
|
+
}));
|
|
108322
|
+
return {
|
|
108323
|
+
id: result.data.id,
|
|
108324
|
+
body: result.data.body ?? void 0,
|
|
108325
|
+
html_url: result.data.html_url,
|
|
108326
|
+
node_id: result.data.node_id
|
|
108327
|
+
};
|
|
108328
|
+
}
|
|
108329
|
+
async function deleteProgressCommentApi(ctx, comment) {
|
|
108330
|
+
if (comment.type === "review") {
|
|
108331
|
+
await ctx.octokit.rest.pulls.deleteReviewComment({
|
|
108332
|
+
owner: ctx.owner,
|
|
108333
|
+
repo: ctx.repo,
|
|
108334
|
+
comment_id: comment.id
|
|
108335
|
+
});
|
|
108336
|
+
return;
|
|
108337
|
+
}
|
|
108338
|
+
await ctx.octokit.rest.issues.deleteComment({
|
|
108339
|
+
owner: ctx.owner,
|
|
108340
|
+
repo: ctx.repo,
|
|
108341
|
+
comment_id: comment.id
|
|
108342
|
+
});
|
|
108343
|
+
}
|
|
108344
|
+
async function createLeapingProgressComment(ctx, target, body) {
|
|
108345
|
+
if (target.kind === "reviewReply") {
|
|
108346
|
+
try {
|
|
108347
|
+
const result2 = await ctx.octokit.rest.pulls.createReplyForReviewComment({
|
|
108348
|
+
owner: ctx.owner,
|
|
108349
|
+
repo: ctx.repo,
|
|
108350
|
+
pull_number: target.pullNumber,
|
|
108351
|
+
comment_id: target.replyToCommentId,
|
|
108352
|
+
body
|
|
108353
|
+
});
|
|
108354
|
+
return {
|
|
108355
|
+
comment: { id: result2.data.id, type: "review" },
|
|
108356
|
+
body: result2.data.body ?? void 0,
|
|
108357
|
+
html_url: result2.data.html_url
|
|
108358
|
+
};
|
|
108359
|
+
} catch (error49) {
|
|
108360
|
+
console.warn(
|
|
108361
|
+
`[progressComment] review reply failed (parent ${target.replyToCommentId} on PR #${target.pullNumber}), falling back to issue comment:`,
|
|
108362
|
+
error49
|
|
108363
|
+
);
|
|
108364
|
+
const fallback = await ctx.octokit.rest.issues.createComment({
|
|
108365
|
+
owner: ctx.owner,
|
|
108366
|
+
repo: ctx.repo,
|
|
108367
|
+
issue_number: target.pullNumber,
|
|
108368
|
+
body
|
|
108369
|
+
});
|
|
108370
|
+
return {
|
|
108371
|
+
comment: { id: fallback.data.id, type: "issue" },
|
|
108372
|
+
body: fallback.data.body ?? void 0,
|
|
108373
|
+
html_url: fallback.data.html_url
|
|
108374
|
+
};
|
|
108375
|
+
}
|
|
108376
|
+
}
|
|
108377
|
+
const result = await ctx.octokit.rest.issues.createComment({
|
|
108378
|
+
owner: ctx.owner,
|
|
108379
|
+
repo: ctx.repo,
|
|
108380
|
+
issue_number: target.issueNumber,
|
|
108381
|
+
body
|
|
108382
|
+
});
|
|
108383
|
+
return {
|
|
108384
|
+
comment: { id: result.data.id, type: "issue" },
|
|
108385
|
+
body: result.data.body ?? void 0,
|
|
108386
|
+
html_url: result.data.html_url
|
|
108387
|
+
};
|
|
108388
|
+
}
|
|
108389
|
+
|
|
108303
108390
|
// node_modules/.pnpm/@toon-format+toon@1.4.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
108304
108391
|
var LIST_ITEM_MARKER = "-";
|
|
108305
108392
|
var LIST_ITEM_PREFIX = "- ";
|
|
@@ -108960,6 +109047,7 @@ async function reportProgress(ctx, params) {
|
|
|
108960
109047
|
}
|
|
108961
109048
|
const issueNumber = ctx.payload.event.issue_number ?? ctx.toolState.issueNumber;
|
|
108962
109049
|
const isPlanMode = ctx.toolState.selectedMode === "Plan";
|
|
109050
|
+
const apiCtx = { octokit: ctx.octokit, owner: ctx.repo.owner, repo: ctx.repo.name };
|
|
108963
109051
|
if (target_plan_comment === true && ctx.toolState.existingPlanCommentId === void 0) {
|
|
108964
109052
|
log.warning("target_plan_comment requested but no existingPlanCommentId in tool state");
|
|
108965
109053
|
}
|
|
@@ -108969,86 +109057,74 @@ async function reportProgress(ctx, params) {
|
|
|
108969
109057
|
const bodyWithoutFooter = stripExistingFooter(body);
|
|
108970
109058
|
const footer = buildCommentFooter(ctx, customParts);
|
|
108971
109059
|
const bodyWithFooter = `${bodyWithoutFooter}${footer}`;
|
|
108972
|
-
const
|
|
108973
|
-
|
|
108974
|
-
|
|
108975
|
-
|
|
108976
|
-
|
|
108977
|
-
});
|
|
109060
|
+
const result = await updateProgressComment(
|
|
109061
|
+
apiCtx,
|
|
109062
|
+
{ id: commentId, type: "issue" },
|
|
109063
|
+
bodyWithFooter
|
|
109064
|
+
);
|
|
108978
109065
|
ctx.toolState.wasUpdated = true;
|
|
108979
|
-
if (isPlanMode &&
|
|
108980
|
-
await patchWorkflowRunFields(ctx, { planCommentNodeId:
|
|
109066
|
+
if (isPlanMode && result.node_id) {
|
|
109067
|
+
await patchWorkflowRunFields(ctx, { planCommentNodeId: result.node_id });
|
|
108981
109068
|
}
|
|
108982
109069
|
return {
|
|
108983
|
-
commentId:
|
|
108984
|
-
url:
|
|
108985
|
-
body:
|
|
109070
|
+
commentId: result.id,
|
|
109071
|
+
url: result.html_url,
|
|
109072
|
+
body: result.body || "",
|
|
108986
109073
|
action: "updated"
|
|
108987
109074
|
};
|
|
108988
109075
|
}
|
|
108989
|
-
const
|
|
108990
|
-
if (
|
|
108991
|
-
const customParts = isPlanMode && issueNumber !== void 0 ? [buildImplementPlanLink(ctx, issueNumber,
|
|
109076
|
+
const existingComment = ctx.toolState.progressComment;
|
|
109077
|
+
if (existingComment) {
|
|
109078
|
+
const customParts = isPlanMode && issueNumber !== void 0 ? [buildImplementPlanLink(ctx, issueNumber, existingComment.id)] : void 0;
|
|
108992
109079
|
const bodyWithoutFooter = stripExistingFooter(body);
|
|
108993
109080
|
const footer = buildCommentFooter(ctx, customParts);
|
|
108994
109081
|
const bodyWithFooter = `${bodyWithoutFooter}${footer}`;
|
|
108995
|
-
const
|
|
108996
|
-
owner: ctx.repo.owner,
|
|
108997
|
-
repo: ctx.repo.name,
|
|
108998
|
-
comment_id: existingCommentId,
|
|
108999
|
-
body: bodyWithFooter
|
|
109000
|
-
});
|
|
109082
|
+
const result = await updateProgressComment(apiCtx, existingComment, bodyWithFooter);
|
|
109001
109083
|
ctx.toolState.wasUpdated = true;
|
|
109002
|
-
if (isPlanMode &&
|
|
109003
|
-
await patchWorkflowRunFields(ctx, { planCommentNodeId:
|
|
109084
|
+
if (isPlanMode && result.node_id) {
|
|
109085
|
+
await patchWorkflowRunFields(ctx, { planCommentNodeId: result.node_id });
|
|
109004
109086
|
}
|
|
109005
109087
|
return {
|
|
109006
|
-
commentId:
|
|
109007
|
-
url:
|
|
109008
|
-
body:
|
|
109088
|
+
commentId: result.id,
|
|
109089
|
+
url: result.html_url,
|
|
109090
|
+
body: result.body || "",
|
|
109009
109091
|
action: "updated"
|
|
109010
109092
|
};
|
|
109011
109093
|
}
|
|
109012
|
-
if (
|
|
109094
|
+
if (existingComment === null) {
|
|
109013
109095
|
return { body, action: "skipped" };
|
|
109014
109096
|
}
|
|
109015
109097
|
if (issueNumber === void 0) {
|
|
109016
109098
|
return { body, action: "skipped" };
|
|
109017
109099
|
}
|
|
109018
109100
|
const initialBody = addFooter(ctx, body);
|
|
109019
|
-
const
|
|
109020
|
-
|
|
109021
|
-
|
|
109022
|
-
|
|
109023
|
-
|
|
109024
|
-
|
|
109025
|
-
ctx.toolState.progressCommentId = result.data.id;
|
|
109101
|
+
const created = await createLeapingProgressComment(
|
|
109102
|
+
apiCtx,
|
|
109103
|
+
{ kind: "issue", issueNumber },
|
|
109104
|
+
initialBody
|
|
109105
|
+
);
|
|
109106
|
+
ctx.toolState.progressComment = created.comment;
|
|
109026
109107
|
ctx.toolState.wasUpdated = true;
|
|
109027
109108
|
if (isPlanMode) {
|
|
109028
|
-
const customParts = [buildImplementPlanLink(ctx, issueNumber,
|
|
109109
|
+
const customParts = [buildImplementPlanLink(ctx, issueNumber, created.comment.id)];
|
|
109029
109110
|
const bodyWithoutFooter = stripExistingFooter(body);
|
|
109030
109111
|
const footer = buildCommentFooter(ctx, customParts);
|
|
109031
109112
|
const bodyWithPlanLink = `${bodyWithoutFooter}${footer}`;
|
|
109032
|
-
const updateResult = await
|
|
109033
|
-
|
|
109034
|
-
|
|
109035
|
-
comment_id: result.data.id,
|
|
109036
|
-
body: bodyWithPlanLink
|
|
109037
|
-
});
|
|
109038
|
-
if (updateResult.data.node_id) {
|
|
109039
|
-
await patchWorkflowRunFields(ctx, { planCommentNodeId: updateResult.data.node_id });
|
|
109113
|
+
const updateResult = await updateProgressComment(apiCtx, created.comment, bodyWithPlanLink);
|
|
109114
|
+
if (updateResult.node_id) {
|
|
109115
|
+
await patchWorkflowRunFields(ctx, { planCommentNodeId: updateResult.node_id });
|
|
109040
109116
|
}
|
|
109041
109117
|
return {
|
|
109042
|
-
commentId: updateResult.
|
|
109043
|
-
url: updateResult.
|
|
109044
|
-
body: updateResult.
|
|
109118
|
+
commentId: updateResult.id,
|
|
109119
|
+
url: updateResult.html_url,
|
|
109120
|
+
body: updateResult.body || "",
|
|
109045
109121
|
action: "created"
|
|
109046
109122
|
};
|
|
109047
109123
|
}
|
|
109048
109124
|
return {
|
|
109049
|
-
commentId:
|
|
109050
|
-
url:
|
|
109051
|
-
body:
|
|
109125
|
+
commentId: created.comment.id,
|
|
109126
|
+
url: created.html_url,
|
|
109127
|
+
body: created.body || "",
|
|
109052
109128
|
action: "created"
|
|
109053
109129
|
};
|
|
109054
109130
|
}
|
|
@@ -109093,23 +109169,22 @@ ${collapsible}`;
|
|
|
109093
109169
|
});
|
|
109094
109170
|
}
|
|
109095
109171
|
async function deleteProgressComment(ctx) {
|
|
109096
|
-
const
|
|
109097
|
-
if (!
|
|
109172
|
+
const existing = ctx.toolState.progressComment;
|
|
109173
|
+
if (!existing) {
|
|
109098
109174
|
return false;
|
|
109099
109175
|
}
|
|
109100
109176
|
try {
|
|
109101
|
-
await
|
|
109102
|
-
owner: ctx.repo.owner,
|
|
109103
|
-
|
|
109104
|
-
|
|
109105
|
-
});
|
|
109177
|
+
await deleteProgressCommentApi(
|
|
109178
|
+
{ octokit: ctx.octokit, owner: ctx.repo.owner, repo: ctx.repo.name },
|
|
109179
|
+
existing
|
|
109180
|
+
);
|
|
109106
109181
|
} catch (error49) {
|
|
109107
109182
|
if (error49 instanceof Error && error49.message.includes("Not Found")) {
|
|
109108
109183
|
} else {
|
|
109109
109184
|
throw error49;
|
|
109110
109185
|
}
|
|
109111
109186
|
}
|
|
109112
|
-
ctx.toolState.
|
|
109187
|
+
ctx.toolState.progressComment = null;
|
|
109113
109188
|
return true;
|
|
109114
109189
|
}
|
|
109115
109190
|
var ReplyToReviewComment = type({
|
|
@@ -142190,7 +142265,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
142190
142265
|
// package.json
|
|
142191
142266
|
var package_default = {
|
|
142192
142267
|
name: "pullfrog",
|
|
142193
|
-
version: "0.0.
|
|
142268
|
+
version: "0.0.204",
|
|
142194
142269
|
type: "module",
|
|
142195
142270
|
bin: {
|
|
142196
142271
|
pullfrog: "dist/cli.mjs",
|
|
@@ -142727,8 +142802,13 @@ async function $git(subcommand, args2, options) {
|
|
|
142727
142802
|
}
|
|
142728
142803
|
if (result.exitCode !== 0) {
|
|
142729
142804
|
const stderr = result.stderr.trim();
|
|
142730
|
-
|
|
142731
|
-
|
|
142805
|
+
const stdout = result.stdout.trim();
|
|
142806
|
+
const detail = stderr && stdout ? `${stderr}
|
|
142807
|
+
--- stdout ---
|
|
142808
|
+
${stdout}` : stderr || stdout || "(no output)";
|
|
142809
|
+
const message = `git ${subcommand} failed (exit ${result.exitCode}): ${detail}`;
|
|
142810
|
+
log.info(message);
|
|
142811
|
+
throw new Error(message);
|
|
142732
142812
|
}
|
|
142733
142813
|
return {
|
|
142734
142814
|
stdout: result.stdout.trim(),
|
|
@@ -143005,6 +143085,34 @@ var PushBranch = type({
|
|
|
143005
143085
|
branchName: type.string.describe("The branch name to push (defaults to current branch)").optional(),
|
|
143006
143086
|
force: type.boolean.describe("Force push (use with caution)").default(false)
|
|
143007
143087
|
});
|
|
143088
|
+
var CONCURRENT_PUSH_PATTERNS = ["fetch first", "non-fast-forward", "cannot lock ref"];
|
|
143089
|
+
var TRANSIENT_PATTERNS = [
|
|
143090
|
+
/RPC failed/i,
|
|
143091
|
+
/early EOF/,
|
|
143092
|
+
/the remote end hung up unexpectedly/,
|
|
143093
|
+
/Connection reset/i,
|
|
143094
|
+
/Could not resolve host/i,
|
|
143095
|
+
/Operation timed out/i,
|
|
143096
|
+
/HTTP\/2 stream \d+ was not closed cleanly/i,
|
|
143097
|
+
/unexpected disconnect while reading sideband packet/i,
|
|
143098
|
+
// libcurl HTTP 5xx surfaced by git over https. matches both the
|
|
143099
|
+
// libcurl-style "The requested URL returned error: 502" and the more
|
|
143100
|
+
// recent "HTTP 502" wording. most 4xx is intentionally excluded —
|
|
143101
|
+
// 401/403/404 indicate auth/permission problems that are not
|
|
143102
|
+
// retry-safe — but 429 (rate-limited / abuse detection) IS retry-safe
|
|
143103
|
+
// and GitHub occasionally surfaces it on git push, so it's included
|
|
143104
|
+
// explicitly below.
|
|
143105
|
+
/HTTP 5\d\d/,
|
|
143106
|
+
/returned error: 5\d\d/i,
|
|
143107
|
+
/HTTP 429/,
|
|
143108
|
+
/returned error: 429/i
|
|
143109
|
+
];
|
|
143110
|
+
function classifyPushError(msg) {
|
|
143111
|
+
if (CONCURRENT_PUSH_PATTERNS.some((p) => msg.includes(p))) return "concurrent-push";
|
|
143112
|
+
if (TRANSIENT_PATTERNS.some((p) => p.test(msg))) return "transient";
|
|
143113
|
+
return "unknown";
|
|
143114
|
+
}
|
|
143115
|
+
var TRANSIENT_RETRY_DELAYS_MS = [2e3, 5e3];
|
|
143008
143116
|
function PushBranchTool(ctx) {
|
|
143009
143117
|
const defaultBranch = ctx.repo.data.default_branch || "main";
|
|
143010
143118
|
const pushPermission = ctx.payload.push;
|
|
@@ -143055,25 +143163,48 @@ ${postHookStatus}`
|
|
|
143055
143163
|
if (force) {
|
|
143056
143164
|
log.warning(`force pushing - this will overwrite remote history`);
|
|
143057
143165
|
}
|
|
143058
|
-
|
|
143059
|
-
|
|
143060
|
-
|
|
143061
|
-
|
|
143062
|
-
|
|
143063
|
-
|
|
143064
|
-
|
|
143065
|
-
|
|
143066
|
-
|
|
143067
|
-
|
|
143166
|
+
let lastErr;
|
|
143167
|
+
let pushed = false;
|
|
143168
|
+
for (let attempt = 0; attempt <= TRANSIENT_RETRY_DELAYS_MS.length; attempt++) {
|
|
143169
|
+
try {
|
|
143170
|
+
await $git("push", pushArgs, {
|
|
143171
|
+
token: ctx.gitToken
|
|
143172
|
+
});
|
|
143173
|
+
if (attempt > 0) {
|
|
143174
|
+
log.info(`push succeeded on attempt ${attempt + 1}`);
|
|
143175
|
+
}
|
|
143176
|
+
pushed = true;
|
|
143177
|
+
break;
|
|
143178
|
+
} catch (err) {
|
|
143179
|
+
lastErr = err;
|
|
143180
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
143181
|
+
const kind = classifyPushError(msg);
|
|
143182
|
+
if (kind === "concurrent-push") {
|
|
143183
|
+
const integrateStep = ctx.payload.shell === "disabled" ? `2. use the git tool to merge the remote branch into yours: git({ command: "merge", args: ["origin/${pushDest.remoteBranch}"] })` : `2. use the git tool to rebase or merge your changes on top: git({ command: "merge", args: ["origin/${pushDest.remoteBranch}"] }) (or 'rebase')`;
|
|
143184
|
+
throw new Error(
|
|
143185
|
+
`push rejected: the remote branch '${pushDest.remoteBranch}' has new commits you don't have locally (often a concurrent push to the same branch).
|
|
143068
143186
|
|
|
143069
143187
|
to resolve this:
|
|
143070
143188
|
1. use git_fetch to fetch the remote branch: git_fetch({ ref: "${pushDest.remoteBranch}" })
|
|
143071
143189
|
${integrateStep}
|
|
143072
143190
|
3. resolve any merge conflicts if needed
|
|
143073
143191
|
4. retry push_branch`
|
|
143074
|
-
|
|
143192
|
+
);
|
|
143193
|
+
}
|
|
143194
|
+
if (kind === "transient" && attempt < TRANSIENT_RETRY_DELAYS_MS.length) {
|
|
143195
|
+
const baseDelay = TRANSIENT_RETRY_DELAYS_MS[attempt] ?? 5e3;
|
|
143196
|
+
const delay2 = Math.round(baseDelay * (0.75 + Math.random() * 0.5));
|
|
143197
|
+
log.info(
|
|
143198
|
+
`push attempt ${attempt + 1} failed (transient), retrying in ${delay2}ms: ${msg.slice(0, 300)}`
|
|
143199
|
+
);
|
|
143200
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
143201
|
+
continue;
|
|
143202
|
+
}
|
|
143203
|
+
throw err;
|
|
143075
143204
|
}
|
|
143076
|
-
|
|
143205
|
+
}
|
|
143206
|
+
if (!pushed) {
|
|
143207
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
143077
143208
|
}
|
|
143078
143209
|
return {
|
|
143079
143210
|
success: true,
|
|
@@ -145127,35 +145258,20 @@ async function getReviewThreads(input) {
|
|
|
145127
145258
|
const username = input.approvedBy;
|
|
145128
145259
|
return threadsForReview.filter((thread) => threadHasThumbsUpFrom(thread, username));
|
|
145129
145260
|
}
|
|
145130
|
-
|
|
145131
|
-
const
|
|
145132
|
-
input.octokit.rest.pulls.getReview({
|
|
145133
|
-
owner: input.owner,
|
|
145134
|
-
repo: input.name,
|
|
145135
|
-
pull_number: input.pullNumber,
|
|
145136
|
-
review_id: input.reviewId
|
|
145137
|
-
}),
|
|
145138
|
-
getReviewThreads(input)
|
|
145139
|
-
]);
|
|
145140
|
-
const rawReviewBody = review.data.body;
|
|
145261
|
+
function formatReviewData(input) {
|
|
145262
|
+
const rawReviewBody = input.review.body;
|
|
145141
145263
|
const reviewBody = rawReviewBody ? stripExistingFooter(rawReviewBody) : "";
|
|
145142
|
-
const reviewer = review.
|
|
145143
|
-
if (threads.length === 0 && !reviewBody) return void 0;
|
|
145264
|
+
const reviewer = input.review.user?.login ?? "unknown";
|
|
145265
|
+
if (input.threads.length === 0 && !reviewBody) return void 0;
|
|
145144
145266
|
let threadBlocks = [];
|
|
145145
|
-
if (threads.length > 0) {
|
|
145146
|
-
const prFiles = await input.octokit.paginate(input.octokit.rest.pulls.listFiles, {
|
|
145147
|
-
owner: input.owner,
|
|
145148
|
-
repo: input.name,
|
|
145149
|
-
pull_number: input.pullNumber,
|
|
145150
|
-
per_page: 100
|
|
145151
|
-
});
|
|
145267
|
+
if (input.threads.length > 0) {
|
|
145152
145268
|
const filePatchMap = /* @__PURE__ */ new Map();
|
|
145153
|
-
for (const file2 of prFiles) {
|
|
145269
|
+
for (const file2 of input.prFiles) {
|
|
145154
145270
|
if (file2.patch) {
|
|
145155
145271
|
filePatchMap.set(file2.filename, parseFilePatches(file2.patch));
|
|
145156
145272
|
}
|
|
145157
145273
|
}
|
|
145158
|
-
threadBlocks = buildThreadBlocks(threads, filePatchMap, input.reviewId);
|
|
145274
|
+
threadBlocks = buildThreadBlocks(input.threads, filePatchMap, input.reviewId);
|
|
145159
145275
|
}
|
|
145160
145276
|
const formatted = formatReviewThreads(threadBlocks, {
|
|
145161
145277
|
pullNumber: input.pullNumber,
|
|
@@ -145165,6 +145281,30 @@ async function getReviewData(input) {
|
|
|
145165
145281
|
});
|
|
145166
145282
|
return { threadBlocks, reviewer, formatted };
|
|
145167
145283
|
}
|
|
145284
|
+
async function getReviewData(input) {
|
|
145285
|
+
const [review, threads] = await Promise.all([
|
|
145286
|
+
input.octokit.rest.pulls.getReview({
|
|
145287
|
+
owner: input.owner,
|
|
145288
|
+
repo: input.name,
|
|
145289
|
+
pull_number: input.pullNumber,
|
|
145290
|
+
review_id: input.reviewId
|
|
145291
|
+
}),
|
|
145292
|
+
getReviewThreads(input)
|
|
145293
|
+
]);
|
|
145294
|
+
const prFiles = threads.length > 0 ? await input.octokit.paginate(input.octokit.rest.pulls.listFiles, {
|
|
145295
|
+
owner: input.owner,
|
|
145296
|
+
repo: input.name,
|
|
145297
|
+
pull_number: input.pullNumber,
|
|
145298
|
+
per_page: 100
|
|
145299
|
+
}) : [];
|
|
145300
|
+
return formatReviewData({
|
|
145301
|
+
review: review.data,
|
|
145302
|
+
threads,
|
|
145303
|
+
prFiles,
|
|
145304
|
+
pullNumber: input.pullNumber,
|
|
145305
|
+
reviewId: input.reviewId
|
|
145306
|
+
});
|
|
145307
|
+
}
|
|
145168
145308
|
function GetReviewCommentsTool(ctx) {
|
|
145169
145309
|
return tool({
|
|
145170
145310
|
name: "get_review_comments",
|
|
@@ -146181,14 +146321,13 @@ function UploadFileTool(ctx) {
|
|
|
146181
146321
|
|
|
146182
146322
|
// mcp/server.ts
|
|
146183
146323
|
function initToolState(params) {
|
|
146184
|
-
const
|
|
146185
|
-
|
|
146186
|
-
|
|
146187
|
-
log.info(`\xBB using pre-created progress comment: ${resolvedId}`);
|
|
146324
|
+
const resolved = parseProgressComment(params.progressComment);
|
|
146325
|
+
if (resolved) {
|
|
146326
|
+
log.info(`\xBB using pre-created progress comment: ${resolved.id} (${resolved.type})`);
|
|
146188
146327
|
}
|
|
146189
146328
|
return {
|
|
146190
|
-
|
|
146191
|
-
hadProgressComment: !!
|
|
146329
|
+
progressComment: resolved,
|
|
146330
|
+
hadProgressComment: !!resolved,
|
|
146192
146331
|
backgroundProcesses: /* @__PURE__ */ new Map(),
|
|
146193
146332
|
usageEntries: []
|
|
146194
146333
|
};
|
|
@@ -151925,8 +152064,8 @@ async function reportErrorToComment(ctx) {
|
|
|
151925
152064
|
const formattedError = ctx.title ? `${ctx.title}
|
|
151926
152065
|
|
|
151927
152066
|
${ctx.error}` : ctx.error;
|
|
151928
|
-
const
|
|
151929
|
-
if (!
|
|
152067
|
+
const comment = ctx.toolState.progressComment;
|
|
152068
|
+
if (!comment) {
|
|
151930
152069
|
return;
|
|
151931
152070
|
}
|
|
151932
152071
|
const repoContext = parseRepoContext();
|
|
@@ -151945,12 +152084,11 @@ ${ctx.error}` : ctx.error;
|
|
|
151945
152084
|
customParts,
|
|
151946
152085
|
model: ctx.toolState.model
|
|
151947
152086
|
});
|
|
151948
|
-
await
|
|
151949
|
-
owner: repoContext.owner,
|
|
151950
|
-
|
|
151951
|
-
|
|
151952
|
-
|
|
151953
|
-
});
|
|
152087
|
+
await updateProgressComment(
|
|
152088
|
+
{ octokit, owner: repoContext.owner, repo: repoContext.name },
|
|
152089
|
+
comment,
|
|
152090
|
+
`${formattedError}${footer}`
|
|
152091
|
+
);
|
|
151954
152092
|
ctx.toolState.wasUpdated = true;
|
|
151955
152093
|
}
|
|
151956
152094
|
|
|
@@ -152450,7 +152588,10 @@ var JsonPayload = type({
|
|
|
152450
152588
|
"eventInstructions?": "string",
|
|
152451
152589
|
"event?": "object",
|
|
152452
152590
|
"timeout?": "string | undefined",
|
|
152453
|
-
"
|
|
152591
|
+
"progressComment?": type({
|
|
152592
|
+
id: "string",
|
|
152593
|
+
type: "'issue' | 'review'"
|
|
152594
|
+
}).or("undefined")
|
|
152454
152595
|
});
|
|
152455
152596
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
152456
152597
|
function isCollaborator(event) {
|
|
@@ -152532,7 +152673,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
152532
152673
|
event,
|
|
152533
152674
|
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
152534
152675
|
cwd: resolveCwd(inputs.cwd),
|
|
152535
|
-
|
|
152676
|
+
progressComment: jsonPayload?.progressComment,
|
|
152536
152677
|
// permissions: inputs > repoSettings > fallbacks
|
|
152537
152678
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
152538
152679
|
shell: resolvedShell,
|
|
@@ -152640,10 +152781,10 @@ async function handleAgentResult(ctx) {
|
|
|
152640
152781
|
};
|
|
152641
152782
|
}
|
|
152642
152783
|
|
|
152643
|
-
// utils/runContextData.ts
|
|
152644
|
-
var core5 = __toESM(require_core(), 1);
|
|
152645
|
-
|
|
152646
152784
|
// utils/runContext.ts
|
|
152785
|
+
function isInfraCovered(params) {
|
|
152786
|
+
return params.isOss || params.plan === "payg";
|
|
152787
|
+
}
|
|
152647
152788
|
var defaultSettings = {
|
|
152648
152789
|
model: null,
|
|
152649
152790
|
modes: [],
|
|
@@ -152661,7 +152802,8 @@ var defaultSettings = {
|
|
|
152661
152802
|
var defaultRunContext = {
|
|
152662
152803
|
settings: defaultSettings,
|
|
152663
152804
|
apiToken: "",
|
|
152664
|
-
oss: false
|
|
152805
|
+
oss: false,
|
|
152806
|
+
plan: "none"
|
|
152665
152807
|
};
|
|
152666
152808
|
async function fetchRunContext(params) {
|
|
152667
152809
|
const timeoutMs = 3e4;
|
|
@@ -152700,6 +152842,7 @@ async function fetchRunContext(params) {
|
|
|
152700
152842
|
},
|
|
152701
152843
|
apiToken: data.apiToken,
|
|
152702
152844
|
oss: data.oss ?? false,
|
|
152845
|
+
plan: data.plan ?? "none",
|
|
152703
152846
|
proxyModel: data.proxyModel,
|
|
152704
152847
|
dbSecrets: data.dbSecrets
|
|
152705
152848
|
};
|
|
@@ -152710,6 +152853,7 @@ async function fetchRunContext(params) {
|
|
|
152710
152853
|
}
|
|
152711
152854
|
|
|
152712
152855
|
// utils/runContextData.ts
|
|
152856
|
+
var core5 = __toESM(require_core(), 1);
|
|
152713
152857
|
async function resolveRunContextData(params) {
|
|
152714
152858
|
log.info(`\xBB running Pullfrog v${package_default.version}...`);
|
|
152715
152859
|
const repoContext = parseRepoContext();
|
|
@@ -152731,6 +152875,7 @@ async function resolveRunContextData(params) {
|
|
|
152731
152875
|
repoSettings: runContext.settings,
|
|
152732
152876
|
apiToken: runContext.apiToken,
|
|
152733
152877
|
oss: runContext.oss,
|
|
152878
|
+
plan: runContext.plan,
|
|
152734
152879
|
proxyModel: runContext.proxyModel,
|
|
152735
152880
|
dbSecrets: runContext.dbSecrets
|
|
152736
152881
|
};
|
|
@@ -153057,6 +153202,59 @@ function resolveAgentForLog(ctx) {
|
|
|
153057
153202
|
}
|
|
153058
153203
|
return ctx.agentName;
|
|
153059
153204
|
}
|
|
153205
|
+
var BillingError = class extends Error {
|
|
153206
|
+
code;
|
|
153207
|
+
declineCode;
|
|
153208
|
+
needsReauthentication;
|
|
153209
|
+
constructor(message, opts = {}) {
|
|
153210
|
+
super(message);
|
|
153211
|
+
this.name = "BillingError";
|
|
153212
|
+
this.code = opts.code ?? null;
|
|
153213
|
+
this.declineCode = opts.declineCode ?? null;
|
|
153214
|
+
this.needsReauthentication = opts.needsReauthentication ?? false;
|
|
153215
|
+
}
|
|
153216
|
+
};
|
|
153217
|
+
var TransientError = class extends Error {
|
|
153218
|
+
constructor(message) {
|
|
153219
|
+
super(message);
|
|
153220
|
+
this.name = "TransientError";
|
|
153221
|
+
}
|
|
153222
|
+
};
|
|
153223
|
+
function formatBillingErrorSummary(error49) {
|
|
153224
|
+
if (error49.code === "router_requires_card") {
|
|
153225
|
+
return [
|
|
153226
|
+
"### \u26D4 Pullfrog Router requires a card",
|
|
153227
|
+
"",
|
|
153228
|
+
"This run was going to use Pullfrog Router, which bills at raw OpenRouter cost and needs a card on file. Runs won't proceed until a card is added.",
|
|
153229
|
+
"",
|
|
153230
|
+
"[Add a card \u2192](https://pullfrog.com/console#model-access) \u2014 your first $20 of Router usage is free."
|
|
153231
|
+
].join("\n");
|
|
153232
|
+
}
|
|
153233
|
+
if (error49.needsReauthentication) {
|
|
153234
|
+
return [
|
|
153235
|
+
"### \u274C Pullfrog billing error \u2014 card requires 3DS on every charge",
|
|
153236
|
+
"",
|
|
153237
|
+
`Your card issuer requires a 3D Secure challenge on each off-session charge (\`${error49.declineCode ?? "authentication_required"}\`), which we can't run from the agent. Top up your Router credit balance manually \u2014 3DS runs interactively in Stripe Checkout, and subsequent runs draw from the prepaid balance without triggering another off-session charge.`,
|
|
153238
|
+
"",
|
|
153239
|
+
"[Top up your Router credit balance \u2192](https://pullfrog.com/console)"
|
|
153240
|
+
].join("\n");
|
|
153241
|
+
}
|
|
153242
|
+
const codeSuffix = error49.declineCode ? ` (\`${error49.declineCode}\`)` : "";
|
|
153243
|
+
return `### \u274C Pullfrog billing error
|
|
153244
|
+
|
|
153245
|
+
${error49.message}${codeSuffix}
|
|
153246
|
+
|
|
153247
|
+
[Manage billing \u2192](https://pullfrog.com/console)`;
|
|
153248
|
+
}
|
|
153249
|
+
function formatTransientErrorSummary(error49) {
|
|
153250
|
+
return [
|
|
153251
|
+
"### \u26A0\uFE0F Pullfrog temporarily unavailable",
|
|
153252
|
+
"",
|
|
153253
|
+
error49.message,
|
|
153254
|
+
"",
|
|
153255
|
+
"This is typically transient \u2014 the next dispatch should succeed. If it persists, check [status.pullfrog.com](https://status.pullfrog.com)."
|
|
153256
|
+
].join("\n");
|
|
153257
|
+
}
|
|
153060
153258
|
async function mintProxyKey(ctx) {
|
|
153061
153259
|
try {
|
|
153062
153260
|
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = ctx.oidcCredentials.requestUrl;
|
|
@@ -153069,6 +153267,20 @@ async function mintProxyKey(ctx) {
|
|
|
153069
153267
|
method: "POST",
|
|
153070
153268
|
headers: { Authorization: `Bearer ${oidcToken}` }
|
|
153071
153269
|
});
|
|
153270
|
+
if (response.status === 402) {
|
|
153271
|
+
const body = await response.json().catch(() => null);
|
|
153272
|
+
throw new BillingError(body?.error ?? "insufficient balance", {
|
|
153273
|
+
code: body?.code ?? null,
|
|
153274
|
+
declineCode: body?.declineCode ?? null,
|
|
153275
|
+
needsReauthentication: body?.needsReauthentication ?? false
|
|
153276
|
+
});
|
|
153277
|
+
}
|
|
153278
|
+
if (response.status === 503) {
|
|
153279
|
+
const body = await response.json().catch(() => null);
|
|
153280
|
+
throw new TransientError(
|
|
153281
|
+
body?.error ?? "billing service temporarily unavailable \u2014 retry shortly"
|
|
153282
|
+
);
|
|
153283
|
+
}
|
|
153072
153284
|
if (!response.ok) {
|
|
153073
153285
|
log.warning(`proxy key mint failed (${response.status})`);
|
|
153074
153286
|
return null;
|
|
@@ -153076,6 +153288,8 @@ async function mintProxyKey(ctx) {
|
|
|
153076
153288
|
const data = await response.json();
|
|
153077
153289
|
return data.key;
|
|
153078
153290
|
} catch (error49) {
|
|
153291
|
+
if (error49 instanceof BillingError) throw error49;
|
|
153292
|
+
if (error49 instanceof TransientError) throw error49;
|
|
153079
153293
|
log.warning(`proxy key mint error: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
153080
153294
|
return null;
|
|
153081
153295
|
} finally {
|
|
@@ -153085,19 +153299,19 @@ async function mintProxyKey(ctx) {
|
|
|
153085
153299
|
}
|
|
153086
153300
|
async function resolveProxyModel(ctx) {
|
|
153087
153301
|
if (process.env.PULLFROG_MODEL?.trim()) return;
|
|
153088
|
-
|
|
153089
|
-
|
|
153090
|
-
|
|
153091
|
-
|
|
153092
|
-
}
|
|
153093
|
-
const key = await mintProxyKey({ oidcCredentials: ctx.oidcCredentials });
|
|
153094
|
-
if (!key) return;
|
|
153095
|
-
process.env.OPENROUTER_API_KEY = key;
|
|
153096
|
-
core6.setSecret(key);
|
|
153097
|
-
ctx.payload.proxyModel = ctx.proxyModel;
|
|
153098
|
-
log.info(`\xBB proxy: oss \u2192 ${ctx.proxyModel}`);
|
|
153302
|
+
const needsProxy = isInfraCovered({ isOss: ctx.oss, plan: ctx.plan }) && ctx.proxyModel;
|
|
153303
|
+
if (!needsProxy) return;
|
|
153304
|
+
if (!ctx.oidcCredentials) {
|
|
153305
|
+
log.warning("\xBB proxy requested but no OIDC credentials available \u2014 skipping");
|
|
153099
153306
|
return;
|
|
153100
153307
|
}
|
|
153308
|
+
const key = await mintProxyKey({ oidcCredentials: ctx.oidcCredentials });
|
|
153309
|
+
if (!key) return;
|
|
153310
|
+
process.env.OPENROUTER_API_KEY = key;
|
|
153311
|
+
core6.setSecret(key);
|
|
153312
|
+
ctx.payload.proxyModel = ctx.proxyModel;
|
|
153313
|
+
const label = ctx.oss ? "oss" : "router";
|
|
153314
|
+
log.info(`\xBB proxy: ${label} \u2192 ${ctx.proxyModel}`);
|
|
153101
153315
|
}
|
|
153102
153316
|
async function writeJobSummary(toolState) {
|
|
153103
153317
|
const usageSummary = formatUsageSummary(toolState.usageEntries);
|
|
@@ -153119,7 +153333,7 @@ async function main() {
|
|
|
153119
153333
|
let safetyNetTimer;
|
|
153120
153334
|
const resolvedPromptInput = resolvePromptInput();
|
|
153121
153335
|
const toolState = initToolState({
|
|
153122
|
-
|
|
153336
|
+
progressComment: typeof resolvedPromptInput !== "string" ? resolvedPromptInput.progressComment : void 0
|
|
153123
153337
|
});
|
|
153124
153338
|
resolveGit();
|
|
153125
153339
|
const jobToken = getJobToken();
|
|
@@ -153153,12 +153367,33 @@ async function main() {
|
|
|
153153
153367
|
delete process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
|
153154
153368
|
delete process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
|
153155
153369
|
}
|
|
153156
|
-
|
|
153157
|
-
|
|
153158
|
-
|
|
153159
|
-
|
|
153160
|
-
|
|
153161
|
-
|
|
153370
|
+
try {
|
|
153371
|
+
await resolveProxyModel({
|
|
153372
|
+
payload,
|
|
153373
|
+
oss: runContext.oss,
|
|
153374
|
+
plan: runContext.plan,
|
|
153375
|
+
proxyModel: runContext.proxyModel,
|
|
153376
|
+
oidcCredentials
|
|
153377
|
+
});
|
|
153378
|
+
} catch (error49) {
|
|
153379
|
+
if (error49 instanceof BillingError) {
|
|
153380
|
+
const summary2 = formatBillingErrorSummary(error49);
|
|
153381
|
+
await writeSummary(summary2).catch(() => {
|
|
153382
|
+
});
|
|
153383
|
+
await reportErrorToComment({ toolState, error: summary2 }).catch(() => {
|
|
153384
|
+
});
|
|
153385
|
+
throw error49;
|
|
153386
|
+
}
|
|
153387
|
+
if (error49 instanceof TransientError) {
|
|
153388
|
+
const summary2 = formatTransientErrorSummary(error49);
|
|
153389
|
+
await writeSummary(summary2).catch(() => {
|
|
153390
|
+
});
|
|
153391
|
+
await reportErrorToComment({ toolState, error: summary2 }).catch(() => {
|
|
153392
|
+
});
|
|
153393
|
+
throw error49;
|
|
153394
|
+
}
|
|
153395
|
+
throw error49;
|
|
153396
|
+
}
|
|
153162
153397
|
const octokit = createOctokit(tokenRef.mcpToken);
|
|
153163
153398
|
const runInfo = await resolveRun({ octokit });
|
|
153164
153399
|
let toolContext;
|
|
@@ -153232,6 +153467,8 @@ async function main() {
|
|
|
153232
153467
|
jobId: runInfo.jobId,
|
|
153233
153468
|
mcpServerUrl: "",
|
|
153234
153469
|
tmpdir: tmpdir3,
|
|
153470
|
+
oss: runContext.oss,
|
|
153471
|
+
plan: runContext.plan,
|
|
153235
153472
|
resolvedModel
|
|
153236
153473
|
};
|
|
153237
153474
|
const mcpHttpServer = __using(_stack, await startMcpHttpServer(toolContext, { outputSchema }), true);
|
|
@@ -153295,6 +153532,9 @@ ${instructions.user}` : null,
|
|
|
153295
153532
|
}
|
|
153296
153533
|
});
|
|
153297
153534
|
toolState.todoTracker = todoTracker;
|
|
153535
|
+
onExitSignal(() => {
|
|
153536
|
+
todoTracker?.cancel();
|
|
153537
|
+
});
|
|
153298
153538
|
let innerTimeoutFired = false;
|
|
153299
153539
|
const onInnerActivityTimeout = () => {
|
|
153300
153540
|
if (innerTimeoutFired) return;
|
|
@@ -153380,7 +153620,7 @@ ${instructions.user}` : null,
|
|
|
153380
153620
|
});
|
|
153381
153621
|
}
|
|
153382
153622
|
const trackerWasLastWriter = todoTracker?.hasPublished && !toolState.finalSummaryWritten;
|
|
153383
|
-
if (toolContext && toolState.
|
|
153623
|
+
if (toolContext && toolState.progressComment && (!toolState.wasUpdated || trackerWasLastWriter)) {
|
|
153384
153624
|
await deleteProgressComment(toolContext).catch((error49) => {
|
|
153385
153625
|
log.debug(`stranded progress comment cleanup failed: ${error49}`);
|
|
153386
153626
|
});
|