pullfrog 0.0.203 → 0.0.205
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/README.md +5 -11
- package/dist/agents/postRun.d.ts +21 -2
- package/dist/agents/shared.d.ts +22 -0
- package/dist/cli.mjs +1152 -828
- package/dist/external.d.ts +7 -2
- package/dist/index.js +1101 -670
- package/dist/internal/index.d.ts +3 -0
- package/dist/internal.js +144 -49
- package/dist/mcp/comment.d.ts +10 -13
- package/dist/mcp/git.d.ts +2 -0
- package/dist/mcp/review.d.ts +2 -2
- package/dist/mcp/reviewComments.d.ts +29 -0
- package/dist/mcp/selectMode.d.ts +0 -6
- package/dist/mcp/server.d.ts +12 -3
- package/dist/utils/diffCoverage.d.ts +1 -0
- package/dist/utils/leapingComment.d.ts +11 -0
- package/dist/utils/patchWorkflowRunFields.d.ts +1 -1
- package/dist/utils/payload.d.ts +10 -2
- package/dist/utils/prSummary.d.ts +40 -0
- 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/internal/index.d.ts
CHANGED
|
@@ -9,4 +9,7 @@ export { modes } from "../modes.ts";
|
|
|
9
9
|
export type { BuildPullfrogFooterParams, WorkflowRunFooterInfo, } from "../utils/buildPullfrogFooter.ts";
|
|
10
10
|
export { buildPullfrogFooter, PULLFROG_DIVIDER, stripExistingFooter, } from "../utils/buildPullfrogFooter.ts";
|
|
11
11
|
export type { ResourceUsage, UsageSummary } from "../utils/github.ts";
|
|
12
|
+
export { isLeapingIntoActionCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../utils/leapingComment.ts";
|
|
13
|
+
export type { CreateProgressCommentTarget, ProgressComment, ProgressCommentType, } from "../utils/progressComment.ts";
|
|
14
|
+
export { createLeapingProgressComment, deleteProgressCommentApi, getProgressComment, updateProgressComment, } from "../utils/progressComment.ts";
|
|
12
15
|
export { isValidTimeString, parseTimeString, TIMEOUT_DISABLED, } from "../utils/time.ts";
|
package/dist/internal.js
CHANGED
|
@@ -93,14 +93,14 @@ var providers = {
|
|
|
93
93
|
models: {
|
|
94
94
|
grok: {
|
|
95
95
|
displayName: "Grok",
|
|
96
|
-
resolve: "xai/grok-4",
|
|
97
|
-
openRouterResolve: "openrouter/x-ai/grok-4",
|
|
96
|
+
resolve: "xai/grok-4.3",
|
|
97
|
+
openRouterResolve: "openrouter/x-ai/grok-4.3",
|
|
98
98
|
preferred: true
|
|
99
99
|
},
|
|
100
100
|
"grok-fast": {
|
|
101
101
|
displayName: "Grok Fast",
|
|
102
|
-
resolve: "xai/grok-4-fast",
|
|
103
|
-
openRouterResolve: "openrouter/x-ai/grok-4-fast"
|
|
102
|
+
resolve: "xai/grok-4-1-fast",
|
|
103
|
+
openRouterResolve: "openrouter/x-ai/grok-4.1-fast"
|
|
104
104
|
},
|
|
105
105
|
"grok-code-fast": {
|
|
106
106
|
displayName: "Grok Code Fast",
|
|
@@ -307,8 +307,8 @@ var providers = {
|
|
|
307
307
|
},
|
|
308
308
|
grok: {
|
|
309
309
|
displayName: "Grok",
|
|
310
|
-
resolve: "openrouter/x-ai/grok-4",
|
|
311
|
-
openRouterResolve: "openrouter/x-ai/grok-4"
|
|
310
|
+
resolve: "openrouter/x-ai/grok-4.3",
|
|
311
|
+
openRouterResolve: "openrouter/x-ai/grok-4.3"
|
|
312
312
|
},
|
|
313
313
|
"deepseek-pro": {
|
|
314
314
|
displayName: "DeepSeek Pro",
|
|
@@ -514,7 +514,7 @@ function computeModes(agentId) {
|
|
|
514
514
|
- Do NOT defect-hunt the diff yourself in parallel with the subagent. Your role is dispatch + evaluation; doing the review yourself reintroduces the implementation bias the subagent is meant to mitigate.
|
|
515
515
|
- For diffs that rely on third-party API contracts, SDK semantics, framework directives, or DB engine specifics, instruct the subagent to verify load-bearing claims via web search and quote source URLs rather than trust training data \u2014 this is the single most common review-quality failure mode.
|
|
516
516
|
|
|
517
|
-
Review the findings, address valid points, and discard nitpicks or false positives. The reviewer is fallible \u2014 it biases toward *recommending additions* (defensive checks for impossible cases, extra logging, new abstractions used once, comments restating code, tests asserting tautologies, "just-in-case" guards). For each finding, ask: would applying it leave the code more sound, correct, AND elegant? Two-out-of-three is
|
|
517
|
+
Review the findings, address valid points, and discard nitpicks or false positives. The reviewer is fallible \u2014 it biases toward *recommending additions* (defensive checks for impossible cases, extra logging, new abstractions used once, comments restating code, tests asserting tautologies, "just-in-case" guards). For each finding, ask: would applying it leave the code more sound, correct, AND elegant? Two-out-of-three is usually a signal to look harder for a fix that gets all three before settling for one that trades elegance for correctness. Reject bloat-shaped findings without applying them, and after applying the rest re-read your diff and be discerning about what *you just changed*: if any fix turned out to be bloat in context, revert it. The goal is code that is sound and correct *while remaining elegant*; the smallest diff that fixes the real defect almost always wins. Then verify only intended changes are present, no debug artifacts or commented-out code remain, no unrelated files were modified. Commit locally via shell (\`git add . && git commit -m "..."\`).
|
|
518
518
|
|
|
519
519
|
5. **finalize**:
|
|
520
520
|
- confirm a clean working tree, then push via \`${t("push_branch")}\` (see *SYSTEM* Git rules if this fails \u2014 prepush errors are usually the repo's tests/lint, not infra timeouts)
|
|
@@ -538,7 +538,7 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
538
538
|
|
|
539
539
|
3. For each comment:
|
|
540
540
|
- understand the feedback
|
|
541
|
-
- evaluate whether applying it would leave the code more **sound, correct, AND elegant**. reviewers are fallible and bias toward *recommending additions* (defensive checks for impossible cases, extra abstractions, comments restating obvious code, tests asserting tautologies, "just-in-case" guards). if a request would add bloat \u2014 ceremony without commensurate correctness benefit \u2014 push back in your reply rather than mechanically applying it. two-out-of-three is
|
|
541
|
+
- evaluate whether applying it would leave the code more **sound, correct, AND elegant**. reviewers are fallible and bias toward *recommending additions* (defensive checks for impossible cases, extra abstractions, comments restating obvious code, tests asserting tautologies, "just-in-case" guards). if a request would add bloat \u2014 ceremony without commensurate correctness benefit \u2014 push back in your reply rather than mechanically applying it. two-out-of-three is usually a signal to look harder for a fix that gets all three before settling.
|
|
542
542
|
- if the request stands, make the code change using your native tools; otherwise reply explaining why
|
|
543
543
|
- record what was done (or why nothing was done)
|
|
544
544
|
|
|
@@ -575,7 +575,7 @@ ${learningsStep(t, 6)}`
|
|
|
575
575
|
|
|
576
576
|
2. **triage**: orient yourself on the PR \u2014 identify *what kind of thing this is* (domain it touches, seams it crosses, external contracts it depends on, user-facing surfaces it changes). orientation only \u2014 defer specific defect-hunting to the subagents; pre-reviewing biases the lenses you pick. use \`${t("get_pull_request")}\` and other read-only GitHub tools for additional context if needed.
|
|
577
577
|
|
|
578
|
-
if the PR is **genuinely trivial**, skip steps 3\u20134 entirely and submit \`
|
|
578
|
+
if the PR is **genuinely trivial**, skip steps 3\u20134 entirely and submit a \`No new issues found.\` review per step 5. there's no value in dispatching even one lens for a typo.
|
|
579
579
|
|
|
580
580
|
"Genuinely trivial" (skip):
|
|
581
581
|
- single-word doc typo, whitespace/format-only, comment-only across any number of files
|
|
@@ -643,26 +643,28 @@ ${learningsStep(t, 6)}`
|
|
|
643
643
|
|
|
644
644
|
note: the first create_pull_request_review submission may error with a one-time diff-coverage nudge listing unread TOC regions. retry the same call to proceed \u2014 optionally after reading the listed ranges. the pre-flight will not block again this session.
|
|
645
645
|
|
|
646
|
+
The review body is structured as: \`[optional alert blockquote]\` \u2192 \`[PR summary using the default format below]\`. Inline comments are passed via the \`comments\` parameter, not in the body.
|
|
647
|
+
|
|
646
648
|
- **critical issues** (blocks merge \u2014 bugs, security, data loss):
|
|
647
|
-
\`approved: false\`. Body
|
|
648
|
-
\`> [!CAUTION]\\n> This PR introduces a race condition in ...\`
|
|
649
|
-
Follow with a brief summary if needed. Include all inline comments.
|
|
649
|
+
\`approved: false\`. Body opens with \`> [!CAUTION]\\n> This PR introduces ...\`, followed by the PR summary. Include all inline comments via \`comments\`.
|
|
650
650
|
- **recommended changes** (non-critical):
|
|
651
|
-
\`approved: false\`. Body
|
|
652
|
-
\`> [!IMPORTANT]\\n> Consider adding input validation for ...\`
|
|
653
|
-
Follow with a brief summary if needed. Include all inline comments.
|
|
651
|
+
\`approved: false\`. Body opens with \`> [!IMPORTANT]\\n> Consider ...\`, followed by the PR summary. Include all inline comments via \`comments\`.
|
|
654
652
|
- **no actionable issues**:
|
|
655
|
-
\`approved: true
|
|
653
|
+
\`approved: true\`. Body opens with \`No new issues found.\` followed by the PR summary.
|
|
654
|
+
|
|
655
|
+
${PR_SUMMARY_FORMAT}`
|
|
656
656
|
},
|
|
657
657
|
// IncrementalReview shares Review's multi-lens orchestrator pattern but
|
|
658
|
-
// scopes the target to the incremental diff
|
|
659
|
-
//
|
|
660
|
-
//
|
|
661
|
-
//
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
//
|
|
665
|
-
//
|
|
658
|
+
// scopes the target to the incremental diff. The "issues must be NEW
|
|
659
|
+
// since the last Pullfrog review" filter lives at aggregation time
|
|
660
|
+
// (step 5), NOT in the subagent prompt — pushing the filter into
|
|
661
|
+
// subagents matches the canonical anneal anti-pattern of "list known
|
|
662
|
+
// pre-existing failures — don't flag these" and suppresses signal on
|
|
663
|
+
// regressions the new commits amplified. The review body is just
|
|
664
|
+
// "Reviewed changes" — a separate "Prior review feedback" checklist
|
|
665
|
+
// would duplicate the rolling PR summary snapshot's record of what
|
|
666
|
+
// earlier runs already addressed and add noise to the user-facing
|
|
667
|
+
// body. Same severity-table omission as Review.
|
|
666
668
|
{
|
|
667
669
|
name: "IncrementalReview",
|
|
668
670
|
description: "Re-review a PR after new commits are pushed; focus on new changes since the last review",
|
|
@@ -672,7 +674,7 @@ ${learningsStep(t, 6)}`
|
|
|
672
674
|
|
|
673
675
|
2. **incremental scope**: if \`incrementalDiffPath\` is present, read it to see what changed since the last review. this is a range-diff that isolates the net changes, filtering out base branch noise. if not present, fall back to reviewing the full PR diff and determine what changed since Pullfrog's most recent review.
|
|
674
676
|
|
|
675
|
-
3. **prior feedback**: fetch previous reviews via \`${t("list_pull_request_reviews")}\`. for the most recent Pullfrog review, call \`${t("get_review_comments")}\` with the review ID to retrieve specific prior line-level feedback. you'll
|
|
677
|
+
3. **prior feedback**: fetch previous reviews via \`${t("list_pull_request_reviews")}\`. for the most recent Pullfrog review, call \`${t("get_review_comments")}\` with the review ID to retrieve specific prior line-level feedback. you'll use this to filter your aggregation in step 5 \u2014 anything already flagged in a prior review and not changed by the new commits should not be re-raised. you do NOT need to render this in the review body; the rolling PR summary snapshot is the durable record of what's been addressed.
|
|
676
678
|
|
|
677
679
|
4. **triage & fan out**: orient on the *incremental* changes \u2014 domain, seams, external contracts, user-facing surfaces.
|
|
678
680
|
|
|
@@ -701,20 +703,14 @@ ${learningsStep(t, 6)}`
|
|
|
701
703
|
|
|
702
704
|
5. **aggregate, draft, self-critique**: merge findings; de-dup overlaps; trace each finding yourself. drop praise, style preferences, speculative/unverified claims, findings about pre-existing code unrelated to the new commits, anything not actionable, and anything that re-states prior review feedback (heuristic: if the finding's root cause lives in lines the *new commits* added or modified, it's in scope; otherwise drop). also drop **bloat-shaped findings** \u2014 proposed fixes that would add defensive checks for cases that can't happen, abstractions used once, comments restating obvious code, tests asserting tautologies, or "just-in-case" guards. subagents are fallible and bias toward recommending changes; the bar for an actionable inline comment is sound + correct + elegant. recommending a change that improves only one of the three (or degrades elegance to nominally improve correctness) makes the codebase worse, not better. To compute "lines the new commits added or modified": if \`incrementalDiffPath\` from step 1 is present, use it directly. Otherwise, take the prior Pullfrog review's \`commit_id\` (returned alongside each entry from \`${t("list_pull_request_reviews")}\` in step 3) and run \`git diff <prior-review-sha>..HEAD\` to isolate the lines added since that review. draft inline comments with NEW line numbers from the full PR diff \u2014 every comment must be actionable, 2-3 sentences max.
|
|
703
705
|
|
|
704
|
-
|
|
706
|
+
6. **build the review body** \u2014 a single "Reviewed changes" section: summarize at the logical-change level, not per-file. each bullet starts with a past-tense verb (e.g. \`- Extracted shared CLI runtime into a single module\`, \`- Renamed package to pullfrog\`). avoid file paths unless they add clarity. if the changes can be described in one sentence, use one sentence \u2014 no bullets needed. do NOT include a separate "Prior review feedback" checklist; that's tracked in the rolling PR summary snapshot for the next agent run, and surfacing it in the user-facing body is noise (changes that addressed prior feedback are already covered by the Reviewed-changes bullets). in some cases you may receive a complete diff for the whole pull request instead of an incremental one \u2014 when this happens, you will need to determine what changes have happened since Pullfrog's most recent review.
|
|
705
707
|
|
|
706
|
-
|
|
707
|
-
a. **Reviewed changes**: summarize at the logical-change level, not per-file. each bullet starts with a past-tense verb (e.g. \`- Extracted shared CLI runtime into a single module\`, \`- Renamed package to pullfrog\`). avoid file paths unless they add clarity. if the changes can be described in one sentence, use one sentence \u2014 no bullets needed.
|
|
708
|
-
b. **Prior review feedback** (only if any were addressed): list only the prior review comments that WERE addressed by the new commits (\`- [x] safeParse instead of parse \u2014 addressed\`). omit unaddressed comments. omit this entire section if nothing was addressed. a change can appear in both sections.
|
|
709
|
-
- no headings, no tables, no prose paragraphs in either section \u2014 just bullets
|
|
710
|
-
- in some cases you may receive a complete diff for the whole pull request instead of an incremental one. when this happens, you will need to determine what changes have happened since Pullfrog's most recent review.
|
|
711
|
-
|
|
712
|
-
7. Submit \u2014 Do NOT call \`report_progress\` or \`create_issue_comment\` \u2014 the review is the final record and the progress comment will be cleaned up automatically. the review body always includes the reviewed changes from step 6a. append \`Prior review feedback:\\n\` with the checklist from step 6b only if any prior comments were addressed. Follow these rules:
|
|
708
|
+
7. Submit \u2014 Do NOT call \`report_progress\` or \`create_issue_comment\` \u2014 the review is the final record and the progress comment will be cleaned up automatically. Follow these rules:
|
|
713
709
|
- note: the first create_pull_request_review submission may error with a one-time diff-coverage nudge listing unread TOC regions. retry the same call to proceed \u2014 optionally after reading the listed ranges. the pre-flight will not block again this session.
|
|
714
710
|
- IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Do NOT call \`report_progress\`. Exit \u2014 the progress comment will be cleaned up automatically.
|
|
715
|
-
- ELSE IF NEW CRITICAL ISSUES (blocks merge): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with a GitHub alert blockquote (e.g. \`> [!CAUTION]\\n> This PR introduces ...\`), then the
|
|
716
|
-
- ELSE IF NEW RECOMMENDED CHANGES (non-critical): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!IMPORTANT]\\n> ...\` alert, then the
|
|
717
|
-
- ELSE IF NO NEW ISSUES, SUBSTANTIVE CHANGES (new functionality, behavior changes, or fixes to prior review feedback): call \`${t("create_pull_request_review")}\` to create a PR review. If all previous reviews have been properly addressed and no new issues were discovered, you can set \`approved: true\`. body opens with \`No new issues. Reviewed the following changes:\\n\`, then the
|
|
711
|
+
- ELSE IF NEW CRITICAL ISSUES (blocks merge): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with a GitHub alert blockquote (e.g. \`> [!CAUTION]\\n> This PR introduces ...\`), then the Reviewed-changes summary.
|
|
712
|
+
- ELSE IF NEW RECOMMENDED CHANGES (non-critical): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!IMPORTANT]\\n> ...\` alert, then the Reviewed-changes summary.
|
|
713
|
+
- ELSE IF NO NEW ISSUES, SUBSTANTIVE CHANGES (new functionality, behavior changes, or fixes to prior review feedback): call \`${t("create_pull_request_review")}\` to create a PR review. If all previous reviews have been properly addressed and no new issues were discovered, you can set \`approved: true\`. body opens with \`No new issues. Reviewed the following changes:\\n\`, then the Reviewed-changes summary.`
|
|
718
714
|
},
|
|
719
715
|
{
|
|
720
716
|
name: "Plan",
|
|
@@ -800,18 +796,6 @@ ${learningsStep(t, 6)}`
|
|
|
800
796
|
- if the task involved labeling, commenting, or other GitHub operations, perform those directly
|
|
801
797
|
|
|
802
798
|
${learningsStep(t, 4)}`
|
|
803
|
-
},
|
|
804
|
-
{
|
|
805
|
-
name: "Summarize",
|
|
806
|
-
description: "Summarize a PR with a structured comment that is updated in place on subsequent pushes",
|
|
807
|
-
prompt: `### Checklist
|
|
808
|
-
|
|
809
|
-
1. Checkout the PR via \`${t("checkout_pr")}\` \u2014 this returns PR metadata and a \`diffPath\`.
|
|
810
|
-
2. Read the diff using the TOC to selectively read relevant sections (not the entire file). Produce a structured summary. If EVENT INSTRUCTIONS specify a custom format, follow that instead of the default format below.
|
|
811
|
-
3. Call \`${t("create_issue_comment")}\` with \`type: "Summary"\` and the summary body.
|
|
812
|
-
4. Call \`${t("report_progress")}\` with a brief note (e.g., "Posted PR summary.").
|
|
813
|
-
|
|
814
|
-
${PR_SUMMARY_FORMAT}`
|
|
815
799
|
}
|
|
816
800
|
];
|
|
817
801
|
}
|
|
@@ -857,6 +841,111 @@ function stripExistingFooter(body) {
|
|
|
857
841
|
return body.substring(0, dividerIndex).trimEnd();
|
|
858
842
|
}
|
|
859
843
|
|
|
844
|
+
// utils/leapingComment.ts
|
|
845
|
+
var LEAPING_INTO_ACTION_PREFIX = "Leaping into action";
|
|
846
|
+
function isLeapingIntoActionCommentBody(body) {
|
|
847
|
+
const content = stripExistingFooter(body).trimStart();
|
|
848
|
+
const firstLine = content.split(/\r?\n/, 1)[0]?.trimEnd() ?? "";
|
|
849
|
+
return new RegExp(`(^|\\s)${LEAPING_INTO_ACTION_PREFIX}(\\.\\.\\.)?$`).test(firstLine);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// utils/progressComment.ts
|
|
853
|
+
async function getProgressComment(ctx, comment) {
|
|
854
|
+
const result = await (comment.type === "review" ? ctx.octokit.rest.pulls.getReviewComment({
|
|
855
|
+
owner: ctx.owner,
|
|
856
|
+
repo: ctx.repo,
|
|
857
|
+
comment_id: comment.id
|
|
858
|
+
}) : ctx.octokit.rest.issues.getComment({
|
|
859
|
+
owner: ctx.owner,
|
|
860
|
+
repo: ctx.repo,
|
|
861
|
+
comment_id: comment.id
|
|
862
|
+
}));
|
|
863
|
+
return {
|
|
864
|
+
id: result.data.id,
|
|
865
|
+
body: result.data.body ?? void 0,
|
|
866
|
+
html_url: result.data.html_url
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
async function updateProgressComment(ctx, comment, body) {
|
|
870
|
+
const result = await (comment.type === "review" ? ctx.octokit.rest.pulls.updateReviewComment({
|
|
871
|
+
owner: ctx.owner,
|
|
872
|
+
repo: ctx.repo,
|
|
873
|
+
comment_id: comment.id,
|
|
874
|
+
body
|
|
875
|
+
}) : ctx.octokit.rest.issues.updateComment({
|
|
876
|
+
owner: ctx.owner,
|
|
877
|
+
repo: ctx.repo,
|
|
878
|
+
comment_id: comment.id,
|
|
879
|
+
body
|
|
880
|
+
}));
|
|
881
|
+
return {
|
|
882
|
+
id: result.data.id,
|
|
883
|
+
body: result.data.body ?? void 0,
|
|
884
|
+
html_url: result.data.html_url,
|
|
885
|
+
node_id: result.data.node_id
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
async function deleteProgressCommentApi(ctx, comment) {
|
|
889
|
+
if (comment.type === "review") {
|
|
890
|
+
await ctx.octokit.rest.pulls.deleteReviewComment({
|
|
891
|
+
owner: ctx.owner,
|
|
892
|
+
repo: ctx.repo,
|
|
893
|
+
comment_id: comment.id
|
|
894
|
+
});
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
await ctx.octokit.rest.issues.deleteComment({
|
|
898
|
+
owner: ctx.owner,
|
|
899
|
+
repo: ctx.repo,
|
|
900
|
+
comment_id: comment.id
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
async function createLeapingProgressComment(ctx, target, body) {
|
|
904
|
+
if (target.kind === "reviewReply") {
|
|
905
|
+
try {
|
|
906
|
+
const result2 = await ctx.octokit.rest.pulls.createReplyForReviewComment({
|
|
907
|
+
owner: ctx.owner,
|
|
908
|
+
repo: ctx.repo,
|
|
909
|
+
pull_number: target.pullNumber,
|
|
910
|
+
comment_id: target.replyToCommentId,
|
|
911
|
+
body
|
|
912
|
+
});
|
|
913
|
+
return {
|
|
914
|
+
comment: { id: result2.data.id, type: "review" },
|
|
915
|
+
body: result2.data.body ?? void 0,
|
|
916
|
+
html_url: result2.data.html_url
|
|
917
|
+
};
|
|
918
|
+
} catch (error) {
|
|
919
|
+
console.warn(
|
|
920
|
+
`[progressComment] review reply failed (parent ${target.replyToCommentId} on PR #${target.pullNumber}), falling back to issue comment:`,
|
|
921
|
+
error
|
|
922
|
+
);
|
|
923
|
+
const fallback = await ctx.octokit.rest.issues.createComment({
|
|
924
|
+
owner: ctx.owner,
|
|
925
|
+
repo: ctx.repo,
|
|
926
|
+
issue_number: target.pullNumber,
|
|
927
|
+
body
|
|
928
|
+
});
|
|
929
|
+
return {
|
|
930
|
+
comment: { id: fallback.data.id, type: "issue" },
|
|
931
|
+
body: fallback.data.body ?? void 0,
|
|
932
|
+
html_url: fallback.data.html_url
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
const result = await ctx.octokit.rest.issues.createComment({
|
|
937
|
+
owner: ctx.owner,
|
|
938
|
+
repo: ctx.repo,
|
|
939
|
+
issue_number: target.issueNumber,
|
|
940
|
+
body
|
|
941
|
+
});
|
|
942
|
+
return {
|
|
943
|
+
comment: { id: result.data.id, type: "issue" },
|
|
944
|
+
body: result.data.body ?? void 0,
|
|
945
|
+
html_url: result.data.html_url
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
|
|
860
949
|
// utils/time.ts
|
|
861
950
|
var TIMEOUT_DISABLED = "none";
|
|
862
951
|
var TIME_STRING_REGEX = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
|
|
@@ -872,12 +961,17 @@ function isValidTimeString(input) {
|
|
|
872
961
|
return parseTimeString(input) !== null;
|
|
873
962
|
}
|
|
874
963
|
export {
|
|
964
|
+
LEAPING_INTO_ACTION_PREFIX,
|
|
875
965
|
PULLFROG_DIVIDER,
|
|
876
966
|
TIMEOUT_DISABLED,
|
|
877
967
|
buildPullfrogFooter,
|
|
968
|
+
createLeapingProgressComment,
|
|
969
|
+
deleteProgressCommentApi,
|
|
878
970
|
getModelEnvVars,
|
|
879
971
|
getModelProvider,
|
|
972
|
+
getProgressComment,
|
|
880
973
|
getProviderDisplayName,
|
|
974
|
+
isLeapingIntoActionCommentBody,
|
|
881
975
|
isValidTimeString,
|
|
882
976
|
modelAliases,
|
|
883
977
|
modes,
|
|
@@ -889,5 +983,6 @@ export {
|
|
|
889
983
|
resolveDisplayAlias,
|
|
890
984
|
resolveModelSlug,
|
|
891
985
|
resolveOpenRouterModel,
|
|
892
|
-
stripExistingFooter
|
|
986
|
+
stripExistingFooter,
|
|
987
|
+
updateProgressComment
|
|
893
988
|
};
|
package/dist/mcp/comment.d.ts
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import type { ToolContext } from "./server.ts";
|
|
2
|
-
|
|
3
|
-
* The prefix text for the initial "leaping into action" comment.
|
|
4
|
-
* This is used to identify if a comment is still in its initial state
|
|
5
|
-
* and hasn't been updated with progress or error messages.
|
|
6
|
-
*/
|
|
7
|
-
export declare const LEAPING_INTO_ACTION_PREFIX = "Leaping into action";
|
|
8
|
-
export declare function isLeapingIntoActionCommentBody(body: string): boolean;
|
|
2
|
+
export { isLeapingIntoActionCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../utils/leapingComment.ts";
|
|
9
3
|
export declare function addFooter(ctx: ToolContext, body: string): string;
|
|
10
4
|
export declare const Comment: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
11
5
|
issueNumber: number;
|
|
12
6
|
body: string;
|
|
13
|
-
type?: "Plan" | "
|
|
7
|
+
type?: "Plan" | "Comment";
|
|
14
8
|
}, {}>;
|
|
15
9
|
export declare function CreateCommentTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
|
|
16
10
|
issueNumber: number;
|
|
17
11
|
body: string;
|
|
18
|
-
type?: "Plan" | "
|
|
12
|
+
type?: "Plan" | "Comment";
|
|
19
13
|
}, {
|
|
20
14
|
issueNumber: number;
|
|
21
15
|
body: string;
|
|
22
|
-
type?: "Plan" | "
|
|
16
|
+
type?: "Plan" | "Comment";
|
|
23
17
|
}>>;
|
|
24
18
|
export declare const EditComment: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
25
19
|
commentId: number;
|
|
@@ -39,12 +33,15 @@ export declare const ReportProgress: import("arktype/internal/variants/object.ts
|
|
|
39
33
|
/**
|
|
40
34
|
* Report progress to a GitHub comment.
|
|
41
35
|
*
|
|
42
|
-
*
|
|
36
|
+
* progressComment has three states:
|
|
43
37
|
* - undefined: no comment yet — will create one if an issue/PR target exists
|
|
44
|
-
* -
|
|
38
|
+
* - object: active comment — will update it in place via the right REST endpoint for its type
|
|
45
39
|
* - null: deliberately deleted (e.g. after submitting a PR review) — skips silently
|
|
46
40
|
*
|
|
47
41
|
* The body is always tracked in lastProgressBody for the job summary regardless of comment state.
|
|
42
|
+
*
|
|
43
|
+
* The "existing plan comment" path always targets a top-level issue comment (plan comments are
|
|
44
|
+
* created by create_issue_comment with type:"Plan", never as review-thread replies).
|
|
48
45
|
*/
|
|
49
46
|
export declare function reportProgress(ctx: ToolContext, params: {
|
|
50
47
|
body: string;
|
|
@@ -66,7 +63,7 @@ export declare function ReportProgressTool(ctx: ToolContext): import("fastmcp").
|
|
|
66
63
|
* Delete the progress comment if it exists.
|
|
67
64
|
* Used by main.ts for stranded-comment cleanup (orphaned "Leaping into action" or
|
|
68
65
|
* checklist left by the todo tracker when the agent didn't call report_progress).
|
|
69
|
-
* Sets
|
|
66
|
+
* Sets progressComment to null so subsequent report_progress calls are no-ops.
|
|
70
67
|
*/
|
|
71
68
|
export declare function deleteProgressComment(ctx: ToolContext): Promise<boolean>;
|
|
72
69
|
export declare const ReplyToReviewComment: import("arktype/internal/variants/object.ts").ObjectType<{
|
package/dist/mcp/git.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare const PushBranch: import("arktype/internal/variants/object.ts").O
|
|
|
6
6
|
force: import("arktype/internal/attributes.ts").Default<boolean, false>;
|
|
7
7
|
branchName?: string;
|
|
8
8
|
}, {}>;
|
|
9
|
+
export type PushErrorKind = "concurrent-push" | "transient" | "unknown";
|
|
10
|
+
export declare function classifyPushError(msg: string): PushErrorKind;
|
|
9
11
|
export declare function PushBranchTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
|
|
10
12
|
branchName?: string;
|
|
11
13
|
force?: boolean;
|
package/dist/mcp/review.d.ts
CHANGED
|
@@ -52,8 +52,8 @@ export type DuplicateReviewDecision = {
|
|
|
52
52
|
* the agent is instructed to call create_pull_request_review exactly once per
|
|
53
53
|
* Review-mode session (see action/modes.ts), but in practice it sometimes
|
|
54
54
|
* submits twice — once with substantive feedback, then again with the
|
|
55
|
-
* canonical "
|
|
56
|
-
*
|
|
55
|
+
* canonical "No new issues found." body when the prompt's branch logic
|
|
56
|
+
* re-classifies non-blocking observations. the second submission is
|
|
57
57
|
* always redundant: the first review is the record, and the duplicate just
|
|
58
58
|
* adds noise to the PR.
|
|
59
59
|
*
|
|
@@ -97,6 +97,35 @@ interface GetReviewDataInput {
|
|
|
97
97
|
reviewId: number;
|
|
98
98
|
approvedBy?: string | undefined;
|
|
99
99
|
}
|
|
100
|
+
export interface FormatReviewDataInput {
|
|
101
|
+
review: ReviewResponse;
|
|
102
|
+
threads: ReviewThread[];
|
|
103
|
+
prFiles: ReviewPrFile[];
|
|
104
|
+
pullNumber: number;
|
|
105
|
+
reviewId: number;
|
|
106
|
+
}
|
|
107
|
+
export type ReviewResponse = {
|
|
108
|
+
body: string | null | undefined;
|
|
109
|
+
user: {
|
|
110
|
+
login: string;
|
|
111
|
+
} | null | undefined;
|
|
112
|
+
};
|
|
113
|
+
export type ReviewPrFile = {
|
|
114
|
+
filename: string;
|
|
115
|
+
patch?: string | undefined;
|
|
116
|
+
};
|
|
117
|
+
export declare function formatReviewData(input: FormatReviewDataInput): {
|
|
118
|
+
threadBlocks: Array<{
|
|
119
|
+
path: string;
|
|
120
|
+
lineRange: string;
|
|
121
|
+
content: string[];
|
|
122
|
+
}>;
|
|
123
|
+
reviewer: string;
|
|
124
|
+
formatted: {
|
|
125
|
+
toc: string;
|
|
126
|
+
content: string;
|
|
127
|
+
};
|
|
128
|
+
} | undefined;
|
|
100
129
|
export declare function getReviewData(input: GetReviewDataInput): Promise<{
|
|
101
130
|
threadBlocks: Array<{
|
|
102
131
|
path: string;
|
package/dist/mcp/selectMode.d.ts
CHANGED
|
@@ -9,12 +9,6 @@ export type PlanCommentResponsePayload = {
|
|
|
9
9
|
commentId: number;
|
|
10
10
|
body: string;
|
|
11
11
|
};
|
|
12
|
-
export type SummaryCommentResponsePayload = {
|
|
13
|
-
error: string;
|
|
14
|
-
} | {
|
|
15
|
-
commentId: number;
|
|
16
|
-
body: string;
|
|
17
|
-
};
|
|
18
12
|
export declare function SelectModeTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
|
|
19
13
|
mode: string;
|
|
20
14
|
issue_number?: number;
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ import type { PrepResult } from "../prep/index.ts";
|
|
|
6
6
|
import type { DiffCoverageState } from "../utils/diffCoverage.ts";
|
|
7
7
|
import type { OctokitWithPlugins } from "../utils/github.ts";
|
|
8
8
|
import type { ResolvedPayload } from "../utils/payload.ts";
|
|
9
|
+
import { type ProgressComment, type ProgressCommentType } from "../utils/progressComment.ts";
|
|
10
|
+
import type { AccountPlan } from "../utils/runContext.ts";
|
|
9
11
|
import type { RunContextData } from "../utils/runContextData.ts";
|
|
10
12
|
import type { TodoTracker } from "../utils/todoTracking.ts";
|
|
11
13
|
import type { CommentableLines } from "./review.ts";
|
|
@@ -48,14 +50,16 @@ export interface ToolState {
|
|
|
48
50
|
promise: Promise<PrepResult[]> | undefined;
|
|
49
51
|
results: PrepResult[] | undefined;
|
|
50
52
|
};
|
|
51
|
-
|
|
53
|
+
progressComment: ProgressComment | null | undefined;
|
|
52
54
|
hadProgressComment: boolean;
|
|
53
55
|
lastProgressBody?: string;
|
|
54
56
|
wasUpdated?: boolean;
|
|
55
57
|
finalSummaryWritten?: boolean;
|
|
56
58
|
existingPlanCommentId?: number;
|
|
57
59
|
previousPlanBody?: string;
|
|
58
|
-
|
|
60
|
+
summaryFilePath?: string;
|
|
61
|
+
summarySeed?: string;
|
|
62
|
+
summaryPersistAttempted?: boolean;
|
|
59
63
|
output?: string;
|
|
60
64
|
usageEntries: AgentUsage[];
|
|
61
65
|
model?: string | undefined;
|
|
@@ -63,7 +67,10 @@ export interface ToolState {
|
|
|
63
67
|
diffCoverage?: DiffCoverageState | undefined;
|
|
64
68
|
}
|
|
65
69
|
interface InitToolStateParams {
|
|
66
|
-
|
|
70
|
+
progressComment: {
|
|
71
|
+
id: string;
|
|
72
|
+
type: ProgressCommentType;
|
|
73
|
+
} | undefined;
|
|
67
74
|
}
|
|
68
75
|
export declare function initToolState(params: InitToolStateParams): ToolState;
|
|
69
76
|
export interface ToolContext {
|
|
@@ -84,6 +91,8 @@ export interface ToolContext {
|
|
|
84
91
|
jobId: string | undefined;
|
|
85
92
|
mcpServerUrl: string;
|
|
86
93
|
tmpdir: string;
|
|
94
|
+
oss: boolean;
|
|
95
|
+
plan: AccountPlan;
|
|
87
96
|
resolvedModel: string | undefined;
|
|
88
97
|
}
|
|
89
98
|
type JsonSchema = Record<string, unknown>;
|
|
@@ -43,6 +43,7 @@ export declare function createDiffCoverageState(params: {
|
|
|
43
43
|
diffPath: string;
|
|
44
44
|
totalLines: number;
|
|
45
45
|
toc: string;
|
|
46
|
+
previous?: DiffCoverageState | undefined;
|
|
46
47
|
}): DiffCoverageState;
|
|
47
48
|
export declare function recordDiffReadFromToolUse(params: {
|
|
48
49
|
state: DiffCoverageState | undefined;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The prefix text for the initial "leaping into action" comment.
|
|
3
|
+
* Used to detect whether a progress comment is still in its initial state
|
|
4
|
+
* and hasn't been updated with real progress or error messages.
|
|
5
|
+
*
|
|
6
|
+
* Lives in `utils/` (not `mcp/`) so it can be re-exported via `pullfrog/internal`
|
|
7
|
+
* without dragging the MCP server's transitive imports into the Next.js app's
|
|
8
|
+
* type-check graph.
|
|
9
|
+
*/
|
|
10
|
+
export declare const LEAPING_INTO_ACTION_PREFIX = "Leaping into action";
|
|
11
|
+
export declare function isLeapingIntoActionCommentBody(body: string): boolean;
|
|
@@ -5,7 +5,7 @@ import type { ToolContext } from "../mcp/server.ts";
|
|
|
5
5
|
* are created during the run. Strings only (GraphQL node IDs).
|
|
6
6
|
* Keep in sync with `STRING_FIELDS` in `app/api/workflow-run/[runId]/route.ts`.
|
|
7
7
|
*/
|
|
8
|
-
export type WorkflowRunArtifactPatchKey = "prNodeId" | "issueNodeId" | "reviewNodeId" | "planCommentNodeId" | "summaryCommentNodeId";
|
|
8
|
+
export type WorkflowRunArtifactPatchKey = "prNodeId" | "issueNodeId" | "reviewNodeId" | "planCommentNodeId" | "summaryCommentNodeId" | "summarySnapshot";
|
|
9
9
|
/**
|
|
10
10
|
* Usage fields — aggregated across all agent calls and PATCHed once at
|
|
11
11
|
* end-of-run. Token counts are Int4 on the DB side (ample for any realistic
|
package/dist/utils/payload.d.ts
CHANGED
|
@@ -9,7 +9,11 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
|
|
|
9
9
|
eventInstructions?: string;
|
|
10
10
|
event?: object;
|
|
11
11
|
timeout?: string | undefined;
|
|
12
|
-
|
|
12
|
+
progressComment?: {
|
|
13
|
+
id: string;
|
|
14
|
+
type: "issue" | "review";
|
|
15
|
+
} | undefined;
|
|
16
|
+
generateSummary?: boolean | undefined;
|
|
13
17
|
}, {}>;
|
|
14
18
|
export declare const Inputs: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
15
19
|
prompt: string;
|
|
@@ -33,7 +37,11 @@ export declare function resolvePayload(resolvedPromptInput: ResolvedPromptInput,
|
|
|
33
37
|
event: PayloadEvent;
|
|
34
38
|
timeout: string | undefined;
|
|
35
39
|
cwd: string | undefined;
|
|
36
|
-
|
|
40
|
+
progressComment: {
|
|
41
|
+
id: string;
|
|
42
|
+
type: "issue" | "review";
|
|
43
|
+
} | undefined;
|
|
44
|
+
generateSummary: boolean | undefined;
|
|
37
45
|
push: import("../external.ts").PushPermission;
|
|
38
46
|
shell: import("../external.ts").ShellPermission;
|
|
39
47
|
proxyModel: string | undefined;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PR-level summary snapshot is a markdown file the agent edits in place
|
|
3
|
+
* during a Review / IncrementalReview run. The server seeds the file with
|
|
4
|
+
* either the previous run's snapshot (incremental) or a stub scaffold (first
|
|
5
|
+
* run), lets the agent edit it with its native file-editing tools, then
|
|
6
|
+
* reads it back at end-of-run and persists it to `WorkflowRun.summarySnapshot`.
|
|
7
|
+
*
|
|
8
|
+
* The snapshot is an internal artifact — it is consumed by future agent runs
|
|
9
|
+
* as durable cross-run context, not surfaced to humans. User-visible summary
|
|
10
|
+
* content lives in the Review / IncrementalReview review bodies, governed by
|
|
11
|
+
* `action/modes.ts`.
|
|
12
|
+
*
|
|
13
|
+
* Edit-in-place avoids the output-token tax of a tool call that regurgitates
|
|
14
|
+
* the full snapshot, and gives incremental runs a clean surface that
|
|
15
|
+
* range-diffs cleanly across runs because the section headings are stable.
|
|
16
|
+
*/
|
|
17
|
+
export declare const SUMMARY_FILE_NAME = "pullfrog-summary.md";
|
|
18
|
+
/**
|
|
19
|
+
* minimal seed for first-run PRs. just a header + a one-line note about
|
|
20
|
+
* what this file is for. structure is intentionally NOT prescribed —
|
|
21
|
+
* different PRs warrant different organization, and the agent should pick
|
|
22
|
+
* a shape that fits this PR. the agent's prompt (see selectMode.ts
|
|
23
|
+
* `buildSummaryAddendum`) carries the actual instructions for what to
|
|
24
|
+
* capture and how.
|
|
25
|
+
*
|
|
26
|
+
* keeping the seed short also makes the unchanged-from-seed gate more
|
|
27
|
+
* sensitive — any meaningful edit moves the file off the seed, so
|
|
28
|
+
* `persistSummary` can reliably skip the DB write when the agent didn't
|
|
29
|
+
* touch the file.
|
|
30
|
+
*/
|
|
31
|
+
export declare const SUMMARY_SCAFFOLD = "# PR summary\n\n<!-- durable cross-run context. edit in place; the next agent run reads this\n before reviewing new commits. structure however serves the PR best. -->\n";
|
|
32
|
+
export declare function summaryFilePath(tmpdir: string): string;
|
|
33
|
+
/** seed the summary file with previous snapshot (incremental) or scaffold (first run). */
|
|
34
|
+
export declare function seedSummaryFile(params: {
|
|
35
|
+
tmpdir: string;
|
|
36
|
+
previousSnapshot: string | null;
|
|
37
|
+
}): Promise<string>;
|
|
38
|
+
/** read + validate the summary file written by the agent.
|
|
39
|
+
* returns null when the file is missing or fails sanity checks. */
|
|
40
|
+
export declare function readSummaryFile(path: string): Promise<string | null>;
|