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/cli.mjs
CHANGED
|
@@ -108099,14 +108099,14 @@ var providers = {
|
|
|
108099
108099
|
models: {
|
|
108100
108100
|
grok: {
|
|
108101
108101
|
displayName: "Grok",
|
|
108102
|
-
resolve: "xai/grok-4",
|
|
108103
|
-
openRouterResolve: "openrouter/x-ai/grok-4",
|
|
108102
|
+
resolve: "xai/grok-4.3",
|
|
108103
|
+
openRouterResolve: "openrouter/x-ai/grok-4.3",
|
|
108104
108104
|
preferred: true
|
|
108105
108105
|
},
|
|
108106
108106
|
"grok-fast": {
|
|
108107
108107
|
displayName: "Grok Fast",
|
|
108108
|
-
resolve: "xai/grok-4-fast",
|
|
108109
|
-
openRouterResolve: "openrouter/x-ai/grok-4-fast"
|
|
108108
|
+
resolve: "xai/grok-4-1-fast",
|
|
108109
|
+
openRouterResolve: "openrouter/x-ai/grok-4.1-fast"
|
|
108110
108110
|
},
|
|
108111
108111
|
"grok-code-fast": {
|
|
108112
108112
|
displayName: "Grok Code Fast",
|
|
@@ -108313,8 +108313,8 @@ var providers = {
|
|
|
108313
108313
|
},
|
|
108314
108314
|
grok: {
|
|
108315
108315
|
displayName: "Grok",
|
|
108316
|
-
resolve: "openrouter/x-ai/grok-4",
|
|
108317
|
-
openRouterResolve: "openrouter/x-ai/grok-4"
|
|
108316
|
+
resolve: "openrouter/x-ai/grok-4.3",
|
|
108317
|
+
openRouterResolve: "openrouter/x-ai/grok-4.3"
|
|
108318
108318
|
},
|
|
108319
108319
|
"deepseek-pro": {
|
|
108320
108320
|
displayName: "DeepSeek Pro",
|
|
@@ -108583,6 +108583,109 @@ function aggregateUsage(entries) {
|
|
|
108583
108583
|
return out;
|
|
108584
108584
|
}
|
|
108585
108585
|
|
|
108586
|
+
// utils/progressComment.ts
|
|
108587
|
+
function parseProgressComment(raw2) {
|
|
108588
|
+
if (!raw2?.id) return void 0;
|
|
108589
|
+
const id = parseInt(raw2.id, 10);
|
|
108590
|
+
if (Number.isNaN(id) || id <= 0) return void 0;
|
|
108591
|
+
return { id, type: raw2.type };
|
|
108592
|
+
}
|
|
108593
|
+
async function getProgressComment(ctx, comment) {
|
|
108594
|
+
const result = await (comment.type === "review" ? ctx.octokit.rest.pulls.getReviewComment({
|
|
108595
|
+
owner: ctx.owner,
|
|
108596
|
+
repo: ctx.repo,
|
|
108597
|
+
comment_id: comment.id
|
|
108598
|
+
}) : ctx.octokit.rest.issues.getComment({
|
|
108599
|
+
owner: ctx.owner,
|
|
108600
|
+
repo: ctx.repo,
|
|
108601
|
+
comment_id: comment.id
|
|
108602
|
+
}));
|
|
108603
|
+
return {
|
|
108604
|
+
id: result.data.id,
|
|
108605
|
+
body: result.data.body ?? void 0,
|
|
108606
|
+
html_url: result.data.html_url
|
|
108607
|
+
};
|
|
108608
|
+
}
|
|
108609
|
+
async function updateProgressComment(ctx, comment, body) {
|
|
108610
|
+
const result = await (comment.type === "review" ? ctx.octokit.rest.pulls.updateReviewComment({
|
|
108611
|
+
owner: ctx.owner,
|
|
108612
|
+
repo: ctx.repo,
|
|
108613
|
+
comment_id: comment.id,
|
|
108614
|
+
body
|
|
108615
|
+
}) : ctx.octokit.rest.issues.updateComment({
|
|
108616
|
+
owner: ctx.owner,
|
|
108617
|
+
repo: ctx.repo,
|
|
108618
|
+
comment_id: comment.id,
|
|
108619
|
+
body
|
|
108620
|
+
}));
|
|
108621
|
+
return {
|
|
108622
|
+
id: result.data.id,
|
|
108623
|
+
body: result.data.body ?? void 0,
|
|
108624
|
+
html_url: result.data.html_url,
|
|
108625
|
+
node_id: result.data.node_id
|
|
108626
|
+
};
|
|
108627
|
+
}
|
|
108628
|
+
async function deleteProgressCommentApi(ctx, comment) {
|
|
108629
|
+
if (comment.type === "review") {
|
|
108630
|
+
await ctx.octokit.rest.pulls.deleteReviewComment({
|
|
108631
|
+
owner: ctx.owner,
|
|
108632
|
+
repo: ctx.repo,
|
|
108633
|
+
comment_id: comment.id
|
|
108634
|
+
});
|
|
108635
|
+
return;
|
|
108636
|
+
}
|
|
108637
|
+
await ctx.octokit.rest.issues.deleteComment({
|
|
108638
|
+
owner: ctx.owner,
|
|
108639
|
+
repo: ctx.repo,
|
|
108640
|
+
comment_id: comment.id
|
|
108641
|
+
});
|
|
108642
|
+
}
|
|
108643
|
+
async function createLeapingProgressComment(ctx, target, body) {
|
|
108644
|
+
if (target.kind === "reviewReply") {
|
|
108645
|
+
try {
|
|
108646
|
+
const result2 = await ctx.octokit.rest.pulls.createReplyForReviewComment({
|
|
108647
|
+
owner: ctx.owner,
|
|
108648
|
+
repo: ctx.repo,
|
|
108649
|
+
pull_number: target.pullNumber,
|
|
108650
|
+
comment_id: target.replyToCommentId,
|
|
108651
|
+
body
|
|
108652
|
+
});
|
|
108653
|
+
return {
|
|
108654
|
+
comment: { id: result2.data.id, type: "review" },
|
|
108655
|
+
body: result2.data.body ?? void 0,
|
|
108656
|
+
html_url: result2.data.html_url
|
|
108657
|
+
};
|
|
108658
|
+
} catch (error49) {
|
|
108659
|
+
console.warn(
|
|
108660
|
+
`[progressComment] review reply failed (parent ${target.replyToCommentId} on PR #${target.pullNumber}), falling back to issue comment:`,
|
|
108661
|
+
error49
|
|
108662
|
+
);
|
|
108663
|
+
const fallback = await ctx.octokit.rest.issues.createComment({
|
|
108664
|
+
owner: ctx.owner,
|
|
108665
|
+
repo: ctx.repo,
|
|
108666
|
+
issue_number: target.pullNumber,
|
|
108667
|
+
body
|
|
108668
|
+
});
|
|
108669
|
+
return {
|
|
108670
|
+
comment: { id: fallback.data.id, type: "issue" },
|
|
108671
|
+
body: fallback.data.body ?? void 0,
|
|
108672
|
+
html_url: fallback.data.html_url
|
|
108673
|
+
};
|
|
108674
|
+
}
|
|
108675
|
+
}
|
|
108676
|
+
const result = await ctx.octokit.rest.issues.createComment({
|
|
108677
|
+
owner: ctx.owner,
|
|
108678
|
+
repo: ctx.repo,
|
|
108679
|
+
issue_number: target.issueNumber,
|
|
108680
|
+
body
|
|
108681
|
+
});
|
|
108682
|
+
return {
|
|
108683
|
+
comment: { id: result.data.id, type: "issue" },
|
|
108684
|
+
body: result.data.body ?? void 0,
|
|
108685
|
+
html_url: result.data.html_url
|
|
108686
|
+
};
|
|
108687
|
+
}
|
|
108688
|
+
|
|
108586
108689
|
// node_modules/.pnpm/@toon-format+toon@1.4.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
108587
108690
|
var LIST_ITEM_MARKER = "-";
|
|
108588
108691
|
var LIST_ITEM_PREFIX = "- ";
|
|
@@ -109249,6 +109352,7 @@ async function reportProgress(ctx, params) {
|
|
|
109249
109352
|
}
|
|
109250
109353
|
const issueNumber = ctx.payload.event.issue_number ?? ctx.toolState.issueNumber;
|
|
109251
109354
|
const isPlanMode = ctx.toolState.selectedMode === "Plan";
|
|
109355
|
+
const apiCtx = { octokit: ctx.octokit, owner: ctx.repo.owner, repo: ctx.repo.name };
|
|
109252
109356
|
if (target_plan_comment === true && ctx.toolState.existingPlanCommentId === void 0) {
|
|
109253
109357
|
log.warning("target_plan_comment requested but no existingPlanCommentId in tool state");
|
|
109254
109358
|
}
|
|
@@ -109258,86 +109362,74 @@ async function reportProgress(ctx, params) {
|
|
|
109258
109362
|
const bodyWithoutFooter = stripExistingFooter(body);
|
|
109259
109363
|
const footer = buildCommentFooter(ctx, customParts);
|
|
109260
109364
|
const bodyWithFooter = `${bodyWithoutFooter}${footer}`;
|
|
109261
|
-
const
|
|
109262
|
-
|
|
109263
|
-
|
|
109264
|
-
|
|
109265
|
-
|
|
109266
|
-
});
|
|
109365
|
+
const result = await updateProgressComment(
|
|
109366
|
+
apiCtx,
|
|
109367
|
+
{ id: commentId, type: "issue" },
|
|
109368
|
+
bodyWithFooter
|
|
109369
|
+
);
|
|
109267
109370
|
ctx.toolState.wasUpdated = true;
|
|
109268
|
-
if (isPlanMode &&
|
|
109269
|
-
await patchWorkflowRunFields(ctx, { planCommentNodeId:
|
|
109371
|
+
if (isPlanMode && result.node_id) {
|
|
109372
|
+
await patchWorkflowRunFields(ctx, { planCommentNodeId: result.node_id });
|
|
109270
109373
|
}
|
|
109271
109374
|
return {
|
|
109272
|
-
commentId:
|
|
109273
|
-
url:
|
|
109274
|
-
body:
|
|
109375
|
+
commentId: result.id,
|
|
109376
|
+
url: result.html_url,
|
|
109377
|
+
body: result.body || "",
|
|
109275
109378
|
action: "updated"
|
|
109276
109379
|
};
|
|
109277
109380
|
}
|
|
109278
|
-
const
|
|
109279
|
-
if (
|
|
109280
|
-
const customParts = isPlanMode && issueNumber !== void 0 ? [buildImplementPlanLink(ctx, issueNumber,
|
|
109381
|
+
const existingComment = ctx.toolState.progressComment;
|
|
109382
|
+
if (existingComment) {
|
|
109383
|
+
const customParts = isPlanMode && issueNumber !== void 0 ? [buildImplementPlanLink(ctx, issueNumber, existingComment.id)] : void 0;
|
|
109281
109384
|
const bodyWithoutFooter = stripExistingFooter(body);
|
|
109282
109385
|
const footer = buildCommentFooter(ctx, customParts);
|
|
109283
109386
|
const bodyWithFooter = `${bodyWithoutFooter}${footer}`;
|
|
109284
|
-
const
|
|
109285
|
-
owner: ctx.repo.owner,
|
|
109286
|
-
repo: ctx.repo.name,
|
|
109287
|
-
comment_id: existingCommentId,
|
|
109288
|
-
body: bodyWithFooter
|
|
109289
|
-
});
|
|
109387
|
+
const result = await updateProgressComment(apiCtx, existingComment, bodyWithFooter);
|
|
109290
109388
|
ctx.toolState.wasUpdated = true;
|
|
109291
|
-
if (isPlanMode &&
|
|
109292
|
-
await patchWorkflowRunFields(ctx, { planCommentNodeId:
|
|
109389
|
+
if (isPlanMode && result.node_id) {
|
|
109390
|
+
await patchWorkflowRunFields(ctx, { planCommentNodeId: result.node_id });
|
|
109293
109391
|
}
|
|
109294
109392
|
return {
|
|
109295
|
-
commentId:
|
|
109296
|
-
url:
|
|
109297
|
-
body:
|
|
109393
|
+
commentId: result.id,
|
|
109394
|
+
url: result.html_url,
|
|
109395
|
+
body: result.body || "",
|
|
109298
109396
|
action: "updated"
|
|
109299
109397
|
};
|
|
109300
109398
|
}
|
|
109301
|
-
if (
|
|
109399
|
+
if (existingComment === null) {
|
|
109302
109400
|
return { body, action: "skipped" };
|
|
109303
109401
|
}
|
|
109304
109402
|
if (issueNumber === void 0) {
|
|
109305
109403
|
return { body, action: "skipped" };
|
|
109306
109404
|
}
|
|
109307
109405
|
const initialBody = addFooter(ctx, body);
|
|
109308
|
-
const
|
|
109309
|
-
|
|
109310
|
-
|
|
109311
|
-
|
|
109312
|
-
|
|
109313
|
-
|
|
109314
|
-
ctx.toolState.progressCommentId = result.data.id;
|
|
109406
|
+
const created = await createLeapingProgressComment(
|
|
109407
|
+
apiCtx,
|
|
109408
|
+
{ kind: "issue", issueNumber },
|
|
109409
|
+
initialBody
|
|
109410
|
+
);
|
|
109411
|
+
ctx.toolState.progressComment = created.comment;
|
|
109315
109412
|
ctx.toolState.wasUpdated = true;
|
|
109316
109413
|
if (isPlanMode) {
|
|
109317
|
-
const customParts = [buildImplementPlanLink(ctx, issueNumber,
|
|
109414
|
+
const customParts = [buildImplementPlanLink(ctx, issueNumber, created.comment.id)];
|
|
109318
109415
|
const bodyWithoutFooter = stripExistingFooter(body);
|
|
109319
109416
|
const footer = buildCommentFooter(ctx, customParts);
|
|
109320
109417
|
const bodyWithPlanLink = `${bodyWithoutFooter}${footer}`;
|
|
109321
|
-
const updateResult = await
|
|
109322
|
-
|
|
109323
|
-
|
|
109324
|
-
comment_id: result.data.id,
|
|
109325
|
-
body: bodyWithPlanLink
|
|
109326
|
-
});
|
|
109327
|
-
if (updateResult.data.node_id) {
|
|
109328
|
-
await patchWorkflowRunFields(ctx, { planCommentNodeId: updateResult.data.node_id });
|
|
109418
|
+
const updateResult = await updateProgressComment(apiCtx, created.comment, bodyWithPlanLink);
|
|
109419
|
+
if (updateResult.node_id) {
|
|
109420
|
+
await patchWorkflowRunFields(ctx, { planCommentNodeId: updateResult.node_id });
|
|
109329
109421
|
}
|
|
109330
109422
|
return {
|
|
109331
|
-
commentId: updateResult.
|
|
109332
|
-
url: updateResult.
|
|
109333
|
-
body: updateResult.
|
|
109423
|
+
commentId: updateResult.id,
|
|
109424
|
+
url: updateResult.html_url,
|
|
109425
|
+
body: updateResult.body || "",
|
|
109334
109426
|
action: "created"
|
|
109335
109427
|
};
|
|
109336
109428
|
}
|
|
109337
109429
|
return {
|
|
109338
|
-
commentId:
|
|
109339
|
-
url:
|
|
109340
|
-
body:
|
|
109430
|
+
commentId: created.comment.id,
|
|
109431
|
+
url: created.html_url,
|
|
109432
|
+
body: created.body || "",
|
|
109341
109433
|
action: "created"
|
|
109342
109434
|
};
|
|
109343
109435
|
}
|
|
@@ -109382,23 +109474,22 @@ ${collapsible}`;
|
|
|
109382
109474
|
});
|
|
109383
109475
|
}
|
|
109384
109476
|
async function deleteProgressComment(ctx) {
|
|
109385
|
-
const
|
|
109386
|
-
if (!
|
|
109477
|
+
const existing = ctx.toolState.progressComment;
|
|
109478
|
+
if (!existing) {
|
|
109387
109479
|
return false;
|
|
109388
109480
|
}
|
|
109389
109481
|
try {
|
|
109390
|
-
await
|
|
109391
|
-
owner: ctx.repo.owner,
|
|
109392
|
-
|
|
109393
|
-
|
|
109394
|
-
});
|
|
109482
|
+
await deleteProgressCommentApi(
|
|
109483
|
+
{ octokit: ctx.octokit, owner: ctx.repo.owner, repo: ctx.repo.name },
|
|
109484
|
+
existing
|
|
109485
|
+
);
|
|
109395
109486
|
} catch (error49) {
|
|
109396
109487
|
if (error49 instanceof Error && error49.message.includes("Not Found")) {
|
|
109397
109488
|
} else {
|
|
109398
109489
|
throw error49;
|
|
109399
109490
|
}
|
|
109400
109491
|
}
|
|
109401
|
-
ctx.toolState.
|
|
109492
|
+
ctx.toolState.progressComment = null;
|
|
109402
109493
|
return true;
|
|
109403
109494
|
}
|
|
109404
109495
|
var ReplyToReviewComment = type({
|
|
@@ -142479,7 +142570,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
142479
142570
|
// package.json
|
|
142480
142571
|
var package_default = {
|
|
142481
142572
|
name: "pullfrog",
|
|
142482
|
-
version: "0.0.
|
|
142573
|
+
version: "0.0.204",
|
|
142483
142574
|
type: "module",
|
|
142484
142575
|
bin: {
|
|
142485
142576
|
pullfrog: "dist/cli.mjs",
|
|
@@ -143016,8 +143107,13 @@ async function $git(subcommand, args2, options) {
|
|
|
143016
143107
|
}
|
|
143017
143108
|
if (result.exitCode !== 0) {
|
|
143018
143109
|
const stderr = result.stderr.trim();
|
|
143019
|
-
|
|
143020
|
-
|
|
143110
|
+
const stdout = result.stdout.trim();
|
|
143111
|
+
const detail = stderr && stdout ? `${stderr}
|
|
143112
|
+
--- stdout ---
|
|
143113
|
+
${stdout}` : stderr || stdout || "(no output)";
|
|
143114
|
+
const message = `git ${subcommand} failed (exit ${result.exitCode}): ${detail}`;
|
|
143115
|
+
log.info(message);
|
|
143116
|
+
throw new Error(message);
|
|
143021
143117
|
}
|
|
143022
143118
|
return {
|
|
143023
143119
|
stdout: result.stdout.trim(),
|
|
@@ -143294,6 +143390,34 @@ var PushBranch = type({
|
|
|
143294
143390
|
branchName: type.string.describe("The branch name to push (defaults to current branch)").optional(),
|
|
143295
143391
|
force: type.boolean.describe("Force push (use with caution)").default(false)
|
|
143296
143392
|
});
|
|
143393
|
+
var CONCURRENT_PUSH_PATTERNS = ["fetch first", "non-fast-forward", "cannot lock ref"];
|
|
143394
|
+
var TRANSIENT_PATTERNS = [
|
|
143395
|
+
/RPC failed/i,
|
|
143396
|
+
/early EOF/,
|
|
143397
|
+
/the remote end hung up unexpectedly/,
|
|
143398
|
+
/Connection reset/i,
|
|
143399
|
+
/Could not resolve host/i,
|
|
143400
|
+
/Operation timed out/i,
|
|
143401
|
+
/HTTP\/2 stream \d+ was not closed cleanly/i,
|
|
143402
|
+
/unexpected disconnect while reading sideband packet/i,
|
|
143403
|
+
// libcurl HTTP 5xx surfaced by git over https. matches both the
|
|
143404
|
+
// libcurl-style "The requested URL returned error: 502" and the more
|
|
143405
|
+
// recent "HTTP 502" wording. most 4xx is intentionally excluded —
|
|
143406
|
+
// 401/403/404 indicate auth/permission problems that are not
|
|
143407
|
+
// retry-safe — but 429 (rate-limited / abuse detection) IS retry-safe
|
|
143408
|
+
// and GitHub occasionally surfaces it on git push, so it's included
|
|
143409
|
+
// explicitly below.
|
|
143410
|
+
/HTTP 5\d\d/,
|
|
143411
|
+
/returned error: 5\d\d/i,
|
|
143412
|
+
/HTTP 429/,
|
|
143413
|
+
/returned error: 429/i
|
|
143414
|
+
];
|
|
143415
|
+
function classifyPushError(msg) {
|
|
143416
|
+
if (CONCURRENT_PUSH_PATTERNS.some((p2) => msg.includes(p2))) return "concurrent-push";
|
|
143417
|
+
if (TRANSIENT_PATTERNS.some((p2) => p2.test(msg))) return "transient";
|
|
143418
|
+
return "unknown";
|
|
143419
|
+
}
|
|
143420
|
+
var TRANSIENT_RETRY_DELAYS_MS = [2e3, 5e3];
|
|
143297
143421
|
function PushBranchTool(ctx) {
|
|
143298
143422
|
const defaultBranch = ctx.repo.data.default_branch || "main";
|
|
143299
143423
|
const pushPermission = ctx.payload.push;
|
|
@@ -143344,25 +143468,48 @@ ${postHookStatus}`
|
|
|
143344
143468
|
if (force) {
|
|
143345
143469
|
log.warning(`force pushing - this will overwrite remote history`);
|
|
143346
143470
|
}
|
|
143347
|
-
|
|
143348
|
-
|
|
143349
|
-
|
|
143350
|
-
|
|
143351
|
-
|
|
143352
|
-
|
|
143353
|
-
|
|
143354
|
-
|
|
143355
|
-
|
|
143356
|
-
|
|
143471
|
+
let lastErr;
|
|
143472
|
+
let pushed = false;
|
|
143473
|
+
for (let attempt = 0; attempt <= TRANSIENT_RETRY_DELAYS_MS.length; attempt++) {
|
|
143474
|
+
try {
|
|
143475
|
+
await $git("push", pushArgs, {
|
|
143476
|
+
token: ctx.gitToken
|
|
143477
|
+
});
|
|
143478
|
+
if (attempt > 0) {
|
|
143479
|
+
log.info(`push succeeded on attempt ${attempt + 1}`);
|
|
143480
|
+
}
|
|
143481
|
+
pushed = true;
|
|
143482
|
+
break;
|
|
143483
|
+
} catch (err) {
|
|
143484
|
+
lastErr = err;
|
|
143485
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
143486
|
+
const kind = classifyPushError(msg);
|
|
143487
|
+
if (kind === "concurrent-push") {
|
|
143488
|
+
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')`;
|
|
143489
|
+
throw new Error(
|
|
143490
|
+
`push rejected: the remote branch '${pushDest.remoteBranch}' has new commits you don't have locally (often a concurrent push to the same branch).
|
|
143357
143491
|
|
|
143358
143492
|
to resolve this:
|
|
143359
143493
|
1. use git_fetch to fetch the remote branch: git_fetch({ ref: "${pushDest.remoteBranch}" })
|
|
143360
143494
|
${integrateStep}
|
|
143361
143495
|
3. resolve any merge conflicts if needed
|
|
143362
143496
|
4. retry push_branch`
|
|
143363
|
-
|
|
143497
|
+
);
|
|
143498
|
+
}
|
|
143499
|
+
if (kind === "transient" && attempt < TRANSIENT_RETRY_DELAYS_MS.length) {
|
|
143500
|
+
const baseDelay = TRANSIENT_RETRY_DELAYS_MS[attempt] ?? 5e3;
|
|
143501
|
+
const delay2 = Math.round(baseDelay * (0.75 + Math.random() * 0.5));
|
|
143502
|
+
log.info(
|
|
143503
|
+
`push attempt ${attempt + 1} failed (transient), retrying in ${delay2}ms: ${msg.slice(0, 300)}`
|
|
143504
|
+
);
|
|
143505
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
143506
|
+
continue;
|
|
143507
|
+
}
|
|
143508
|
+
throw err;
|
|
143364
143509
|
}
|
|
143365
|
-
|
|
143510
|
+
}
|
|
143511
|
+
if (!pushed) {
|
|
143512
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
143366
143513
|
}
|
|
143367
143514
|
return {
|
|
143368
143515
|
success: true,
|
|
@@ -145416,35 +145563,20 @@ async function getReviewThreads(input) {
|
|
|
145416
145563
|
const username = input.approvedBy;
|
|
145417
145564
|
return threadsForReview.filter((thread) => threadHasThumbsUpFrom(thread, username));
|
|
145418
145565
|
}
|
|
145419
|
-
|
|
145420
|
-
const
|
|
145421
|
-
input.octokit.rest.pulls.getReview({
|
|
145422
|
-
owner: input.owner,
|
|
145423
|
-
repo: input.name,
|
|
145424
|
-
pull_number: input.pullNumber,
|
|
145425
|
-
review_id: input.reviewId
|
|
145426
|
-
}),
|
|
145427
|
-
getReviewThreads(input)
|
|
145428
|
-
]);
|
|
145429
|
-
const rawReviewBody = review.data.body;
|
|
145566
|
+
function formatReviewData(input) {
|
|
145567
|
+
const rawReviewBody = input.review.body;
|
|
145430
145568
|
const reviewBody = rawReviewBody ? stripExistingFooter(rawReviewBody) : "";
|
|
145431
|
-
const reviewer = review.
|
|
145432
|
-
if (threads.length === 0 && !reviewBody) return void 0;
|
|
145569
|
+
const reviewer = input.review.user?.login ?? "unknown";
|
|
145570
|
+
if (input.threads.length === 0 && !reviewBody) return void 0;
|
|
145433
145571
|
let threadBlocks = [];
|
|
145434
|
-
if (threads.length > 0) {
|
|
145435
|
-
const prFiles = await input.octokit.paginate(input.octokit.rest.pulls.listFiles, {
|
|
145436
|
-
owner: input.owner,
|
|
145437
|
-
repo: input.name,
|
|
145438
|
-
pull_number: input.pullNumber,
|
|
145439
|
-
per_page: 100
|
|
145440
|
-
});
|
|
145572
|
+
if (input.threads.length > 0) {
|
|
145441
145573
|
const filePatchMap = /* @__PURE__ */ new Map();
|
|
145442
|
-
for (const file2 of prFiles) {
|
|
145574
|
+
for (const file2 of input.prFiles) {
|
|
145443
145575
|
if (file2.patch) {
|
|
145444
145576
|
filePatchMap.set(file2.filename, parseFilePatches(file2.patch));
|
|
145445
145577
|
}
|
|
145446
145578
|
}
|
|
145447
|
-
threadBlocks = buildThreadBlocks(threads, filePatchMap, input.reviewId);
|
|
145579
|
+
threadBlocks = buildThreadBlocks(input.threads, filePatchMap, input.reviewId);
|
|
145448
145580
|
}
|
|
145449
145581
|
const formatted = formatReviewThreads(threadBlocks, {
|
|
145450
145582
|
pullNumber: input.pullNumber,
|
|
@@ -145454,6 +145586,30 @@ async function getReviewData(input) {
|
|
|
145454
145586
|
});
|
|
145455
145587
|
return { threadBlocks, reviewer, formatted };
|
|
145456
145588
|
}
|
|
145589
|
+
async function getReviewData(input) {
|
|
145590
|
+
const [review, threads] = await Promise.all([
|
|
145591
|
+
input.octokit.rest.pulls.getReview({
|
|
145592
|
+
owner: input.owner,
|
|
145593
|
+
repo: input.name,
|
|
145594
|
+
pull_number: input.pullNumber,
|
|
145595
|
+
review_id: input.reviewId
|
|
145596
|
+
}),
|
|
145597
|
+
getReviewThreads(input)
|
|
145598
|
+
]);
|
|
145599
|
+
const prFiles = threads.length > 0 ? await input.octokit.paginate(input.octokit.rest.pulls.listFiles, {
|
|
145600
|
+
owner: input.owner,
|
|
145601
|
+
repo: input.name,
|
|
145602
|
+
pull_number: input.pullNumber,
|
|
145603
|
+
per_page: 100
|
|
145604
|
+
}) : [];
|
|
145605
|
+
return formatReviewData({
|
|
145606
|
+
review: review.data,
|
|
145607
|
+
threads,
|
|
145608
|
+
prFiles,
|
|
145609
|
+
pullNumber: input.pullNumber,
|
|
145610
|
+
reviewId: input.reviewId
|
|
145611
|
+
});
|
|
145612
|
+
}
|
|
145457
145613
|
function GetReviewCommentsTool(ctx) {
|
|
145458
145614
|
return tool({
|
|
145459
145615
|
name: "get_review_comments",
|
|
@@ -146470,14 +146626,13 @@ function UploadFileTool(ctx) {
|
|
|
146470
146626
|
|
|
146471
146627
|
// mcp/server.ts
|
|
146472
146628
|
function initToolState(params) {
|
|
146473
|
-
const
|
|
146474
|
-
|
|
146475
|
-
|
|
146476
|
-
log.info(`\xBB using pre-created progress comment: ${resolvedId}`);
|
|
146629
|
+
const resolved = parseProgressComment(params.progressComment);
|
|
146630
|
+
if (resolved) {
|
|
146631
|
+
log.info(`\xBB using pre-created progress comment: ${resolved.id} (${resolved.type})`);
|
|
146477
146632
|
}
|
|
146478
146633
|
return {
|
|
146479
|
-
|
|
146480
|
-
hadProgressComment: !!
|
|
146634
|
+
progressComment: resolved,
|
|
146635
|
+
hadProgressComment: !!resolved,
|
|
146481
146636
|
backgroundProcesses: /* @__PURE__ */ new Map(),
|
|
146482
146637
|
usageEntries: []
|
|
146483
146638
|
};
|
|
@@ -152214,8 +152369,8 @@ async function reportErrorToComment(ctx) {
|
|
|
152214
152369
|
const formattedError = ctx.title ? `${ctx.title}
|
|
152215
152370
|
|
|
152216
152371
|
${ctx.error}` : ctx.error;
|
|
152217
|
-
const
|
|
152218
|
-
if (!
|
|
152372
|
+
const comment = ctx.toolState.progressComment;
|
|
152373
|
+
if (!comment) {
|
|
152219
152374
|
return;
|
|
152220
152375
|
}
|
|
152221
152376
|
const repoContext = parseRepoContext();
|
|
@@ -152234,12 +152389,11 @@ ${ctx.error}` : ctx.error;
|
|
|
152234
152389
|
customParts,
|
|
152235
152390
|
model: ctx.toolState.model
|
|
152236
152391
|
});
|
|
152237
|
-
await
|
|
152238
|
-
owner: repoContext.owner,
|
|
152239
|
-
|
|
152240
|
-
|
|
152241
|
-
|
|
152242
|
-
});
|
|
152392
|
+
await updateProgressComment(
|
|
152393
|
+
{ octokit, owner: repoContext.owner, repo: repoContext.name },
|
|
152394
|
+
comment,
|
|
152395
|
+
`${formattedError}${footer}`
|
|
152396
|
+
);
|
|
152243
152397
|
ctx.toolState.wasUpdated = true;
|
|
152244
152398
|
}
|
|
152245
152399
|
|
|
@@ -152739,7 +152893,10 @@ var JsonPayload = type({
|
|
|
152739
152893
|
"eventInstructions?": "string",
|
|
152740
152894
|
"event?": "object",
|
|
152741
152895
|
"timeout?": "string | undefined",
|
|
152742
|
-
"
|
|
152896
|
+
"progressComment?": type({
|
|
152897
|
+
id: "string",
|
|
152898
|
+
type: "'issue' | 'review'"
|
|
152899
|
+
}).or("undefined")
|
|
152743
152900
|
});
|
|
152744
152901
|
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
152745
152902
|
function isCollaborator(event) {
|
|
@@ -152821,7 +152978,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
152821
152978
|
event,
|
|
152822
152979
|
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
152823
152980
|
cwd: resolveCwd(inputs.cwd),
|
|
152824
|
-
|
|
152981
|
+
progressComment: jsonPayload?.progressComment,
|
|
152825
152982
|
// permissions: inputs > repoSettings > fallbacks
|
|
152826
152983
|
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
152827
152984
|
shell: resolvedShell,
|
|
@@ -152929,10 +153086,10 @@ async function handleAgentResult(ctx) {
|
|
|
152929
153086
|
};
|
|
152930
153087
|
}
|
|
152931
153088
|
|
|
152932
|
-
// utils/runContextData.ts
|
|
152933
|
-
var core5 = __toESM(require_core(), 1);
|
|
152934
|
-
|
|
152935
153089
|
// utils/runContext.ts
|
|
153090
|
+
function isInfraCovered(params) {
|
|
153091
|
+
return params.isOss || params.plan === "payg";
|
|
153092
|
+
}
|
|
152936
153093
|
var defaultSettings = {
|
|
152937
153094
|
model: null,
|
|
152938
153095
|
modes: [],
|
|
@@ -152950,7 +153107,8 @@ var defaultSettings = {
|
|
|
152950
153107
|
var defaultRunContext = {
|
|
152951
153108
|
settings: defaultSettings,
|
|
152952
153109
|
apiToken: "",
|
|
152953
|
-
oss: false
|
|
153110
|
+
oss: false,
|
|
153111
|
+
plan: "none"
|
|
152954
153112
|
};
|
|
152955
153113
|
async function fetchRunContext(params) {
|
|
152956
153114
|
const timeoutMs = 3e4;
|
|
@@ -152989,6 +153147,7 @@ async function fetchRunContext(params) {
|
|
|
152989
153147
|
},
|
|
152990
153148
|
apiToken: data.apiToken,
|
|
152991
153149
|
oss: data.oss ?? false,
|
|
153150
|
+
plan: data.plan ?? "none",
|
|
152992
153151
|
proxyModel: data.proxyModel,
|
|
152993
153152
|
dbSecrets: data.dbSecrets
|
|
152994
153153
|
};
|
|
@@ -152999,6 +153158,7 @@ async function fetchRunContext(params) {
|
|
|
152999
153158
|
}
|
|
153000
153159
|
|
|
153001
153160
|
// utils/runContextData.ts
|
|
153161
|
+
var core5 = __toESM(require_core(), 1);
|
|
153002
153162
|
async function resolveRunContextData(params) {
|
|
153003
153163
|
log.info(`\xBB running Pullfrog v${package_default.version}...`);
|
|
153004
153164
|
const repoContext = parseRepoContext();
|
|
@@ -153020,6 +153180,7 @@ async function resolveRunContextData(params) {
|
|
|
153020
153180
|
repoSettings: runContext.settings,
|
|
153021
153181
|
apiToken: runContext.apiToken,
|
|
153022
153182
|
oss: runContext.oss,
|
|
153183
|
+
plan: runContext.plan,
|
|
153023
153184
|
proxyModel: runContext.proxyModel,
|
|
153024
153185
|
dbSecrets: runContext.dbSecrets
|
|
153025
153186
|
};
|
|
@@ -153346,6 +153507,59 @@ function resolveAgentForLog(ctx) {
|
|
|
153346
153507
|
}
|
|
153347
153508
|
return ctx.agentName;
|
|
153348
153509
|
}
|
|
153510
|
+
var BillingError = class extends Error {
|
|
153511
|
+
code;
|
|
153512
|
+
declineCode;
|
|
153513
|
+
needsReauthentication;
|
|
153514
|
+
constructor(message, opts = {}) {
|
|
153515
|
+
super(message);
|
|
153516
|
+
this.name = "BillingError";
|
|
153517
|
+
this.code = opts.code ?? null;
|
|
153518
|
+
this.declineCode = opts.declineCode ?? null;
|
|
153519
|
+
this.needsReauthentication = opts.needsReauthentication ?? false;
|
|
153520
|
+
}
|
|
153521
|
+
};
|
|
153522
|
+
var TransientError = class extends Error {
|
|
153523
|
+
constructor(message) {
|
|
153524
|
+
super(message);
|
|
153525
|
+
this.name = "TransientError";
|
|
153526
|
+
}
|
|
153527
|
+
};
|
|
153528
|
+
function formatBillingErrorSummary(error49) {
|
|
153529
|
+
if (error49.code === "router_requires_card") {
|
|
153530
|
+
return [
|
|
153531
|
+
"### \u26D4 Pullfrog Router requires a card",
|
|
153532
|
+
"",
|
|
153533
|
+
"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.",
|
|
153534
|
+
"",
|
|
153535
|
+
"[Add a card \u2192](https://pullfrog.com/console#model-access) \u2014 your first $20 of Router usage is free."
|
|
153536
|
+
].join("\n");
|
|
153537
|
+
}
|
|
153538
|
+
if (error49.needsReauthentication) {
|
|
153539
|
+
return [
|
|
153540
|
+
"### \u274C Pullfrog billing error \u2014 card requires 3DS on every charge",
|
|
153541
|
+
"",
|
|
153542
|
+
`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.`,
|
|
153543
|
+
"",
|
|
153544
|
+
"[Top up your Router credit balance \u2192](https://pullfrog.com/console)"
|
|
153545
|
+
].join("\n");
|
|
153546
|
+
}
|
|
153547
|
+
const codeSuffix = error49.declineCode ? ` (\`${error49.declineCode}\`)` : "";
|
|
153548
|
+
return `### \u274C Pullfrog billing error
|
|
153549
|
+
|
|
153550
|
+
${error49.message}${codeSuffix}
|
|
153551
|
+
|
|
153552
|
+
[Manage billing \u2192](https://pullfrog.com/console)`;
|
|
153553
|
+
}
|
|
153554
|
+
function formatTransientErrorSummary(error49) {
|
|
153555
|
+
return [
|
|
153556
|
+
"### \u26A0\uFE0F Pullfrog temporarily unavailable",
|
|
153557
|
+
"",
|
|
153558
|
+
error49.message,
|
|
153559
|
+
"",
|
|
153560
|
+
"This is typically transient \u2014 the next dispatch should succeed. If it persists, check [status.pullfrog.com](https://status.pullfrog.com)."
|
|
153561
|
+
].join("\n");
|
|
153562
|
+
}
|
|
153349
153563
|
async function mintProxyKey(ctx) {
|
|
153350
153564
|
try {
|
|
153351
153565
|
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = ctx.oidcCredentials.requestUrl;
|
|
@@ -153358,6 +153572,20 @@ async function mintProxyKey(ctx) {
|
|
|
153358
153572
|
method: "POST",
|
|
153359
153573
|
headers: { Authorization: `Bearer ${oidcToken}` }
|
|
153360
153574
|
});
|
|
153575
|
+
if (response.status === 402) {
|
|
153576
|
+
const body = await response.json().catch(() => null);
|
|
153577
|
+
throw new BillingError(body?.error ?? "insufficient balance", {
|
|
153578
|
+
code: body?.code ?? null,
|
|
153579
|
+
declineCode: body?.declineCode ?? null,
|
|
153580
|
+
needsReauthentication: body?.needsReauthentication ?? false
|
|
153581
|
+
});
|
|
153582
|
+
}
|
|
153583
|
+
if (response.status === 503) {
|
|
153584
|
+
const body = await response.json().catch(() => null);
|
|
153585
|
+
throw new TransientError(
|
|
153586
|
+
body?.error ?? "billing service temporarily unavailable \u2014 retry shortly"
|
|
153587
|
+
);
|
|
153588
|
+
}
|
|
153361
153589
|
if (!response.ok) {
|
|
153362
153590
|
log.warning(`proxy key mint failed (${response.status})`);
|
|
153363
153591
|
return null;
|
|
@@ -153365,6 +153593,8 @@ async function mintProxyKey(ctx) {
|
|
|
153365
153593
|
const data = await response.json();
|
|
153366
153594
|
return data.key;
|
|
153367
153595
|
} catch (error49) {
|
|
153596
|
+
if (error49 instanceof BillingError) throw error49;
|
|
153597
|
+
if (error49 instanceof TransientError) throw error49;
|
|
153368
153598
|
log.warning(`proxy key mint error: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
153369
153599
|
return null;
|
|
153370
153600
|
} finally {
|
|
@@ -153374,19 +153604,19 @@ async function mintProxyKey(ctx) {
|
|
|
153374
153604
|
}
|
|
153375
153605
|
async function resolveProxyModel(ctx) {
|
|
153376
153606
|
if (process.env.PULLFROG_MODEL?.trim()) return;
|
|
153377
|
-
|
|
153378
|
-
|
|
153379
|
-
|
|
153380
|
-
|
|
153381
|
-
}
|
|
153382
|
-
const key = await mintProxyKey({ oidcCredentials: ctx.oidcCredentials });
|
|
153383
|
-
if (!key) return;
|
|
153384
|
-
process.env.OPENROUTER_API_KEY = key;
|
|
153385
|
-
core6.setSecret(key);
|
|
153386
|
-
ctx.payload.proxyModel = ctx.proxyModel;
|
|
153387
|
-
log.info(`\xBB proxy: oss \u2192 ${ctx.proxyModel}`);
|
|
153607
|
+
const needsProxy = isInfraCovered({ isOss: ctx.oss, plan: ctx.plan }) && ctx.proxyModel;
|
|
153608
|
+
if (!needsProxy) return;
|
|
153609
|
+
if (!ctx.oidcCredentials) {
|
|
153610
|
+
log.warning("\xBB proxy requested but no OIDC credentials available \u2014 skipping");
|
|
153388
153611
|
return;
|
|
153389
153612
|
}
|
|
153613
|
+
const key = await mintProxyKey({ oidcCredentials: ctx.oidcCredentials });
|
|
153614
|
+
if (!key) return;
|
|
153615
|
+
process.env.OPENROUTER_API_KEY = key;
|
|
153616
|
+
core6.setSecret(key);
|
|
153617
|
+
ctx.payload.proxyModel = ctx.proxyModel;
|
|
153618
|
+
const label = ctx.oss ? "oss" : "router";
|
|
153619
|
+
log.info(`\xBB proxy: ${label} \u2192 ${ctx.proxyModel}`);
|
|
153390
153620
|
}
|
|
153391
153621
|
async function writeJobSummary(toolState) {
|
|
153392
153622
|
const usageSummary = formatUsageSummary(toolState.usageEntries);
|
|
@@ -153408,7 +153638,7 @@ async function main() {
|
|
|
153408
153638
|
let safetyNetTimer;
|
|
153409
153639
|
const resolvedPromptInput = resolvePromptInput();
|
|
153410
153640
|
const toolState = initToolState({
|
|
153411
|
-
|
|
153641
|
+
progressComment: typeof resolvedPromptInput !== "string" ? resolvedPromptInput.progressComment : void 0
|
|
153412
153642
|
});
|
|
153413
153643
|
resolveGit();
|
|
153414
153644
|
const jobToken = getJobToken();
|
|
@@ -153442,12 +153672,33 @@ async function main() {
|
|
|
153442
153672
|
delete process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
|
153443
153673
|
delete process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
|
153444
153674
|
}
|
|
153445
|
-
|
|
153446
|
-
|
|
153447
|
-
|
|
153448
|
-
|
|
153449
|
-
|
|
153450
|
-
|
|
153675
|
+
try {
|
|
153676
|
+
await resolveProxyModel({
|
|
153677
|
+
payload,
|
|
153678
|
+
oss: runContext.oss,
|
|
153679
|
+
plan: runContext.plan,
|
|
153680
|
+
proxyModel: runContext.proxyModel,
|
|
153681
|
+
oidcCredentials
|
|
153682
|
+
});
|
|
153683
|
+
} catch (error49) {
|
|
153684
|
+
if (error49 instanceof BillingError) {
|
|
153685
|
+
const summary2 = formatBillingErrorSummary(error49);
|
|
153686
|
+
await writeSummary(summary2).catch(() => {
|
|
153687
|
+
});
|
|
153688
|
+
await reportErrorToComment({ toolState, error: summary2 }).catch(() => {
|
|
153689
|
+
});
|
|
153690
|
+
throw error49;
|
|
153691
|
+
}
|
|
153692
|
+
if (error49 instanceof TransientError) {
|
|
153693
|
+
const summary2 = formatTransientErrorSummary(error49);
|
|
153694
|
+
await writeSummary(summary2).catch(() => {
|
|
153695
|
+
});
|
|
153696
|
+
await reportErrorToComment({ toolState, error: summary2 }).catch(() => {
|
|
153697
|
+
});
|
|
153698
|
+
throw error49;
|
|
153699
|
+
}
|
|
153700
|
+
throw error49;
|
|
153701
|
+
}
|
|
153451
153702
|
const octokit = createOctokit(tokenRef.mcpToken);
|
|
153452
153703
|
const runInfo = await resolveRun({ octokit });
|
|
153453
153704
|
let toolContext;
|
|
@@ -153521,6 +153772,8 @@ async function main() {
|
|
|
153521
153772
|
jobId: runInfo.jobId,
|
|
153522
153773
|
mcpServerUrl: "",
|
|
153523
153774
|
tmpdir: tmpdir3,
|
|
153775
|
+
oss: runContext.oss,
|
|
153776
|
+
plan: runContext.plan,
|
|
153524
153777
|
resolvedModel
|
|
153525
153778
|
};
|
|
153526
153779
|
const mcpHttpServer = __using(_stack, await startMcpHttpServer(toolContext, { outputSchema }), true);
|
|
@@ -153584,6 +153837,9 @@ ${instructions.user}` : null,
|
|
|
153584
153837
|
}
|
|
153585
153838
|
});
|
|
153586
153839
|
toolState.todoTracker = todoTracker;
|
|
153840
|
+
onExitSignal(() => {
|
|
153841
|
+
todoTracker?.cancel();
|
|
153842
|
+
});
|
|
153587
153843
|
let innerTimeoutFired = false;
|
|
153588
153844
|
const onInnerActivityTimeout = () => {
|
|
153589
153845
|
if (innerTimeoutFired) return;
|
|
@@ -153669,7 +153925,7 @@ ${instructions.user}` : null,
|
|
|
153669
153925
|
});
|
|
153670
153926
|
}
|
|
153671
153927
|
const trackerWasLastWriter = todoTracker?.hasPublished && !toolState.finalSummaryWritten;
|
|
153672
|
-
if (toolContext && toolState.
|
|
153928
|
+
if (toolContext && toolState.progressComment && (!toolState.wasUpdated || trackerWasLastWriter)) {
|
|
153673
153929
|
await deleteProgressComment(toolContext).catch((error49) => {
|
|
153674
153930
|
log.debug(`stranded progress comment cleanup failed: ${error49}`);
|
|
153675
153931
|
});
|
|
@@ -153777,32 +154033,36 @@ The workflow encountered an error before any progress could be reported.`;
|
|
|
153777
154033
|
return `${errorMessage}${footer}`;
|
|
153778
154034
|
}
|
|
153779
154035
|
async function validateStuckProgressComment(ctx) {
|
|
153780
|
-
|
|
153781
|
-
|
|
154036
|
+
const promptComment = ctx.promptInput?.progressComment;
|
|
154037
|
+
if (!promptComment) {
|
|
154038
|
+
log.info("[post] no progressComment in prompt input, skipping cleanup");
|
|
154039
|
+
return null;
|
|
154040
|
+
}
|
|
154041
|
+
const comment = parseProgressComment(promptComment);
|
|
154042
|
+
if (!comment) {
|
|
154043
|
+
log.info(`[post] progressComment.id is not a positive integer: ${promptComment.id}`);
|
|
153782
154044
|
return null;
|
|
153783
154045
|
}
|
|
153784
|
-
|
|
153785
|
-
log.info(`[post] validating progressCommentId from prompt input: ${commentId}`);
|
|
154046
|
+
log.info(`[post] validating progressComment from prompt input: ${comment.id} (${comment.type})`);
|
|
153786
154047
|
try {
|
|
153787
|
-
const
|
|
153788
|
-
owner: ctx.repoContext.owner,
|
|
153789
|
-
|
|
153790
|
-
|
|
153791
|
-
|
|
153792
|
-
const body = commentResult.data.body ?? "";
|
|
154048
|
+
const fetched = await getProgressComment(
|
|
154049
|
+
{ octokit: ctx.octokit, owner: ctx.repoContext.owner, repo: ctx.repoContext.name },
|
|
154050
|
+
comment
|
|
154051
|
+
);
|
|
154052
|
+
const body = fetched.body ?? "";
|
|
153793
154053
|
if (isLeapingIntoActionCommentBody(body)) {
|
|
153794
|
-
log.info(`[post] comment ${
|
|
153795
|
-
return
|
|
154054
|
+
log.info(`[post] comment ${comment.id} is stuck on "Leaping into action"`);
|
|
154055
|
+
return comment;
|
|
153796
154056
|
}
|
|
153797
154057
|
if (/^- \[[ x]\] |^- \*\*→\*\* |^- ~~/.test(body)) {
|
|
153798
|
-
log.info(`[post] comment ${
|
|
153799
|
-
return
|
|
154058
|
+
log.info(`[post] comment ${comment.id} is stuck on a todo checklist`);
|
|
154059
|
+
return comment;
|
|
153800
154060
|
}
|
|
153801
|
-
log.info(`[post] comment ${
|
|
154061
|
+
log.info(`[post] comment ${comment.id} is not stuck (already updated or different content)`);
|
|
153802
154062
|
return null;
|
|
153803
154063
|
} catch (error49) {
|
|
153804
154064
|
const errorMessage = error49 instanceof Error ? error49.message : String(error49);
|
|
153805
|
-
log.info(`[post] failed to get comment ${
|
|
154065
|
+
log.info(`[post] failed to get comment ${comment.id}: ${errorMessage}`);
|
|
153806
154066
|
return null;
|
|
153807
154067
|
}
|
|
153808
154068
|
}
|
|
@@ -153853,26 +154113,56 @@ async function runPostCleanup() {
|
|
|
153853
154113
|
const repoContext = parseRepoContext();
|
|
153854
154114
|
const octokit = createOctokit(token);
|
|
153855
154115
|
const ctx = { repoContext, octokit, runId, promptInput };
|
|
153856
|
-
const
|
|
153857
|
-
if (!
|
|
153858
|
-
log.info(
|
|
154116
|
+
const stuck = await validateStuckProgressComment(ctx);
|
|
154117
|
+
if (!stuck) return log.info("\xBB [post] no stuck progress comment to update, skipping cleanup");
|
|
154118
|
+
log.info(
|
|
154119
|
+
`\xBB [post] validated stuck comment: ${stuck.id} (${stuck.type}), updating with error message`
|
|
154120
|
+
);
|
|
153859
154121
|
try {
|
|
153860
154122
|
const body = buildErrorCommentBody(
|
|
153861
154123
|
ctx,
|
|
153862
154124
|
SHOULD_CHECK_REASON ? await getIsCancelled(ctx) : false
|
|
153863
154125
|
);
|
|
153864
|
-
await ctx
|
|
153865
|
-
owner: ctx.repoContext.owner,
|
|
153866
|
-
repo: ctx.repoContext.name,
|
|
153867
|
-
comment_id: commentId,
|
|
153868
|
-
body
|
|
153869
|
-
});
|
|
153870
|
-
log.info("\xBB [post] successfully updated progress comment");
|
|
154126
|
+
await writeAndVerify(ctx, stuck, body);
|
|
153871
154127
|
} catch (error49) {
|
|
153872
154128
|
const errorMessage = error49 instanceof Error ? error49.message : String(error49);
|
|
153873
154129
|
log.info(`[post] failed to update comment: ${errorMessage}`);
|
|
153874
154130
|
}
|
|
153875
154131
|
}
|
|
154132
|
+
var VERIFY_DELAY_MS = 3e3;
|
|
154133
|
+
var MAX_WRITE_ATTEMPTS = 3;
|
|
154134
|
+
async function writeAndVerify(ctx, comment, body) {
|
|
154135
|
+
const apiCtx = {
|
|
154136
|
+
octokit: ctx.octokit,
|
|
154137
|
+
owner: ctx.repoContext.owner,
|
|
154138
|
+
repo: ctx.repoContext.name
|
|
154139
|
+
};
|
|
154140
|
+
for (let attempt = 1; attempt <= MAX_WRITE_ATTEMPTS; attempt++) {
|
|
154141
|
+
await updateProgressComment(apiCtx, comment, body);
|
|
154142
|
+
await new Promise((resolve3) => setTimeout(resolve3, VERIFY_DELAY_MS));
|
|
154143
|
+
let fetched;
|
|
154144
|
+
try {
|
|
154145
|
+
fetched = await getProgressComment(apiCtx, comment);
|
|
154146
|
+
} catch (error49) {
|
|
154147
|
+
log.warning(
|
|
154148
|
+
`[post] verify GET failed after attempt ${attempt} \u2014 trusting our PUT landed: ${error49 instanceof Error ? error49.message : String(error49)}`
|
|
154149
|
+
);
|
|
154150
|
+
return;
|
|
154151
|
+
}
|
|
154152
|
+
if (fetched.body === body) {
|
|
154153
|
+
log.info(
|
|
154154
|
+
`\xBB [post] successfully updated progress comment (attempt ${attempt}/${MAX_WRITE_ATTEMPTS})`
|
|
154155
|
+
);
|
|
154156
|
+
return;
|
|
154157
|
+
}
|
|
154158
|
+
log.info(
|
|
154159
|
+
`[post] body was overwritten after our write (attempt ${attempt}/${MAX_WRITE_ATTEMPTS}), retrying`
|
|
154160
|
+
);
|
|
154161
|
+
}
|
|
154162
|
+
log.warning(
|
|
154163
|
+
`[post] gave up after ${MAX_WRITE_ATTEMPTS} attempts \u2014 comment may be stale (in-flight writes from the cancelled run kept clobbering us)`
|
|
154164
|
+
);
|
|
154165
|
+
}
|
|
153876
154166
|
|
|
153877
154167
|
// commands/gha.ts
|
|
153878
154168
|
process.env.PATH = `${dirname4(process.execPath)}:${process.env.PATH}`;
|
|
@@ -155659,7 +155949,7 @@ async function run2() {
|
|
|
155659
155949
|
}
|
|
155660
155950
|
|
|
155661
155951
|
// cli.ts
|
|
155662
|
-
var VERSION10 = "0.0.
|
|
155952
|
+
var VERSION10 = "0.0.204";
|
|
155663
155953
|
var bin = basename2(process.argv[1] || "");
|
|
155664
155954
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
155665
155955
|
var rawArgs = process.argv.slice(2);
|