pullfrog 0.1.34 → 0.1.36
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/agents/opencodeShared.d.ts +1 -1
- package/dist/agents/reviewer.d.ts +1 -1
- package/dist/cli.mjs +639 -238
- package/dist/index.js +638 -237
- package/dist/internal.js +137 -113
- package/dist/mcp/checkout.d.ts +1 -0
- package/dist/mcp/shared.d.ts +3 -1
- package/dist/models.d.ts +7 -2
- package/dist/toolState.d.ts +0 -1
- package/dist/utils/changeImpact.d.ts +18 -0
- package/dist/utils/diffCoverage.d.ts +0 -5
- package/package.json +1 -1
package/dist/internal.js
CHANGED
|
@@ -50,37 +50,40 @@ var providers = {
|
|
|
50
50
|
managedCredentials: ["CODEX_AUTH_JSON"],
|
|
51
51
|
models: {
|
|
52
52
|
gpt: {
|
|
53
|
-
displayName: "GPT",
|
|
54
|
-
resolve: "openai/gpt-5.
|
|
55
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
53
|
+
displayName: "GPT Sol",
|
|
54
|
+
resolve: "openai/gpt-5.6-sol",
|
|
55
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-sol",
|
|
56
56
|
preferred: true,
|
|
57
|
-
subagentModel: "gpt-
|
|
57
|
+
subagentModel: "gpt-terra"
|
|
58
58
|
},
|
|
59
|
+
// Sol served at reasoning.mode=pro — same $/token as Sol, just more tokens
|
|
60
|
+
// burned; not a pricier premium tier. models.dev has no -pro id, so direct-key
|
|
61
|
+
// (BYOK) resolves to plain Sol; only the Router/OpenRouter path gets sol-pro.
|
|
59
62
|
"gpt-pro": {
|
|
60
|
-
displayName: "GPT Pro",
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
displayName: "GPT Sol Pro",
|
|
64
|
+
description: "Maximum reasoning effort",
|
|
65
|
+
resolve: "openai/gpt-5.6-sol",
|
|
66
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
|
|
63
67
|
subagentModel: "gpt"
|
|
64
68
|
},
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
"gpt-
|
|
69
|
-
displayName: "GPT
|
|
70
|
-
resolve: "openai/gpt-5.
|
|
71
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
72
|
-
hidden: true
|
|
69
|
+
// gpt-5.6's balanced mid-tier (Sol/Terra/Luna are durable capability tiers,
|
|
70
|
+
// not version bumps). selectable on its own and doubles as `gpt`'s cheaper
|
|
71
|
+
// lens-fanout subagent — replaces the old hidden gpt-5.4 subagent target.
|
|
72
|
+
"gpt-terra": {
|
|
73
|
+
displayName: "GPT Terra",
|
|
74
|
+
resolve: "openai/gpt-5.6-terra",
|
|
75
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-terra"
|
|
73
76
|
},
|
|
74
77
|
"gpt-mini": {
|
|
75
|
-
displayName: "GPT
|
|
76
|
-
resolve: "openai/gpt-5.
|
|
77
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
78
|
+
displayName: "GPT Luna",
|
|
79
|
+
resolve: "openai/gpt-5.6-luna",
|
|
80
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-luna"
|
|
78
81
|
},
|
|
79
82
|
// legacy aliases — openai unified the codex line into the main GPT family
|
|
80
83
|
// and is shutting down every "-codex" snapshot on 2026-07-23. transparently
|
|
81
84
|
// upgrade existing users via the fallback chain. UI display sites resolve
|
|
82
85
|
// to the terminal alias's label (so dropdown trigger + PR footers show
|
|
83
|
-
// "GPT" / "GPT
|
|
86
|
+
// "GPT Sol" / "GPT Luna", not the historical name).
|
|
84
87
|
"gpt-codex": {
|
|
85
88
|
displayName: "GPT Codex",
|
|
86
89
|
resolve: "openai/gpt-5.3-codex",
|
|
@@ -93,6 +96,13 @@ var providers = {
|
|
|
93
96
|
openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
|
|
94
97
|
fallback: "openai/gpt-mini"
|
|
95
98
|
},
|
|
99
|
+
// dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
|
|
100
|
+
"gpt-5.4": {
|
|
101
|
+
displayName: "GPT 5.4",
|
|
102
|
+
resolve: "openai/gpt-5.4",
|
|
103
|
+
openRouterResolve: "openrouter/openai/gpt-5.4",
|
|
104
|
+
fallback: "openai/gpt"
|
|
105
|
+
},
|
|
96
106
|
o3: {
|
|
97
107
|
displayName: "O3",
|
|
98
108
|
resolve: "openai/o3",
|
|
@@ -222,28 +232,29 @@ var providers = {
|
|
|
222
232
|
openRouterResolve: "openrouter/anthropic/claude-haiku-4.5"
|
|
223
233
|
},
|
|
224
234
|
gpt: {
|
|
225
|
-
displayName: "GPT",
|
|
226
|
-
resolve: "opencode/gpt-5.
|
|
227
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
228
|
-
subagentModel: "gpt-
|
|
235
|
+
displayName: "GPT Sol",
|
|
236
|
+
resolve: "opencode/gpt-5.6-sol",
|
|
237
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-sol",
|
|
238
|
+
subagentModel: "gpt-terra"
|
|
229
239
|
},
|
|
240
|
+
// see openai/gpt-pro — Zen has no -pro id, so direct resolves to plain Sol.
|
|
230
241
|
"gpt-pro": {
|
|
231
|
-
displayName: "GPT Pro",
|
|
232
|
-
|
|
233
|
-
|
|
242
|
+
displayName: "GPT Sol Pro",
|
|
243
|
+
description: "Maximum reasoning effort",
|
|
244
|
+
resolve: "opencode/gpt-5.6-sol",
|
|
245
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
|
|
234
246
|
subagentModel: "gpt"
|
|
235
247
|
},
|
|
236
|
-
//
|
|
237
|
-
"gpt-
|
|
238
|
-
displayName: "GPT
|
|
239
|
-
resolve: "opencode/gpt-5.
|
|
240
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
241
|
-
hidden: true
|
|
248
|
+
// gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
|
|
249
|
+
"gpt-terra": {
|
|
250
|
+
displayName: "GPT Terra",
|
|
251
|
+
resolve: "opencode/gpt-5.6-terra",
|
|
252
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-terra"
|
|
242
253
|
},
|
|
243
254
|
"gpt-mini": {
|
|
244
|
-
displayName: "GPT
|
|
245
|
-
resolve: "opencode/gpt-5.
|
|
246
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
255
|
+
displayName: "GPT Luna",
|
|
256
|
+
resolve: "opencode/gpt-5.6-luna",
|
|
257
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-luna"
|
|
247
258
|
},
|
|
248
259
|
// legacy aliases — see openai provider above for context.
|
|
249
260
|
"gpt-codex": {
|
|
@@ -258,6 +269,13 @@ var providers = {
|
|
|
258
269
|
openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
|
|
259
270
|
fallback: "opencode/gpt-mini"
|
|
260
271
|
},
|
|
272
|
+
// dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
|
|
273
|
+
"gpt-5.4": {
|
|
274
|
+
displayName: "GPT 5.4",
|
|
275
|
+
resolve: "opencode/gpt-5.4",
|
|
276
|
+
openRouterResolve: "openrouter/openai/gpt-5.4",
|
|
277
|
+
fallback: "opencode/gpt"
|
|
278
|
+
},
|
|
261
279
|
"gemini-pro": {
|
|
262
280
|
displayName: "Gemini Pro",
|
|
263
281
|
resolve: "opencode/gemini-3.1-pro",
|
|
@@ -374,29 +392,34 @@ var providers = {
|
|
|
374
392
|
resolve: "openrouter/~anthropic/claude-haiku-latest",
|
|
375
393
|
openRouterResolve: "openrouter/~anthropic/claude-haiku-latest"
|
|
376
394
|
},
|
|
395
|
+
// pinned to the explicit gpt-5.6 tiers (not the ~openai/gpt-latest rolling
|
|
396
|
+
// alias): after the Sol/Terra/Luna rename, ~gpt-mini-latest no longer maps
|
|
397
|
+
// to Luna, so rolling aliases would silently diverge `gpt`/`gpt-mini` from
|
|
398
|
+
// the chosen tiers across funding paths.
|
|
377
399
|
gpt: {
|
|
378
|
-
displayName: "GPT",
|
|
379
|
-
resolve: "openrouter
|
|
380
|
-
openRouterResolve: "openrouter
|
|
381
|
-
subagentModel: "gpt-
|
|
400
|
+
displayName: "GPT Sol",
|
|
401
|
+
resolve: "openrouter/openai/gpt-5.6-sol",
|
|
402
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-sol",
|
|
403
|
+
subagentModel: "gpt-terra"
|
|
382
404
|
},
|
|
405
|
+
// see openai/gpt-pro. openrouter serves sol-pro directly on both routes.
|
|
383
406
|
"gpt-pro": {
|
|
384
|
-
displayName: "GPT Pro",
|
|
385
|
-
|
|
386
|
-
|
|
407
|
+
displayName: "GPT Sol Pro",
|
|
408
|
+
description: "Maximum reasoning effort",
|
|
409
|
+
resolve: "openrouter/openai/gpt-5.6-sol-pro",
|
|
410
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
|
|
387
411
|
subagentModel: "gpt"
|
|
388
412
|
},
|
|
389
|
-
//
|
|
390
|
-
"gpt-
|
|
391
|
-
displayName: "GPT
|
|
392
|
-
resolve: "openrouter/openai/gpt-5.
|
|
393
|
-
openRouterResolve: "openrouter/openai/gpt-5.
|
|
394
|
-
hidden: true
|
|
413
|
+
// gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
|
|
414
|
+
"gpt-terra": {
|
|
415
|
+
displayName: "GPT Terra",
|
|
416
|
+
resolve: "openrouter/openai/gpt-5.6-terra",
|
|
417
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-terra"
|
|
395
418
|
},
|
|
396
419
|
"gpt-mini": {
|
|
397
|
-
displayName: "GPT
|
|
398
|
-
resolve: "openrouter
|
|
399
|
-
openRouterResolve: "openrouter
|
|
420
|
+
displayName: "GPT Luna",
|
|
421
|
+
resolve: "openrouter/openai/gpt-5.6-luna",
|
|
422
|
+
openRouterResolve: "openrouter/openai/gpt-5.6-luna"
|
|
400
423
|
},
|
|
401
424
|
// legacy aliases — see openai provider for context.
|
|
402
425
|
"gpt-codex": {
|
|
@@ -411,6 +434,13 @@ var providers = {
|
|
|
411
434
|
openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
|
|
412
435
|
fallback: "openrouter/gpt-mini"
|
|
413
436
|
},
|
|
437
|
+
// dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
|
|
438
|
+
"gpt-5.4": {
|
|
439
|
+
displayName: "GPT 5.4",
|
|
440
|
+
resolve: "openrouter/openai/gpt-5.4",
|
|
441
|
+
openRouterResolve: "openrouter/openai/gpt-5.4",
|
|
442
|
+
fallback: "openrouter/gpt"
|
|
443
|
+
},
|
|
414
444
|
"o4-mini": {
|
|
415
445
|
displayName: "O4 Mini",
|
|
416
446
|
resolve: "openrouter/openai/o4-mini",
|
|
@@ -499,6 +529,7 @@ var modelAliases = Object.entries(providers).flatMap(
|
|
|
499
529
|
slug: `${providerKey}/${modelId}`,
|
|
500
530
|
provider: providerKey,
|
|
501
531
|
displayName: def.displayName,
|
|
532
|
+
description: def.description,
|
|
502
533
|
resolve: def.resolve,
|
|
503
534
|
openRouterResolve: def.openRouterResolve,
|
|
504
535
|
preferred: def.preferred ?? false,
|
|
@@ -837,20 +868,15 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
837
868
|
- **immediately** call \`${t("resolve_review_thread")}\` with that thread's \`thread=\` value as \`thread_id\`. Resolve every thread where you (a) made the requested code change in full \u2014 partial fixes leave the thread open \u2014 OR (b) replied with a substantive answer the user explicitly asked for. Do NOT resolve threads where you pushed back on the request and the disagreement is unresolved; leave those open for the human to mediate.
|
|
838
869
|
- call \`${t("report_progress")}\` with a brief summary`
|
|
839
870
|
},
|
|
840
|
-
// Review and IncrementalReview
|
|
841
|
-
//
|
|
842
|
-
//
|
|
843
|
-
// high-stakes-subsystem touches — and when it fires, ALL lenses must
|
|
844
|
-
// dispatch in a single assistant turn or the parallelism win disappears.
|
|
845
|
-
// We never dispatch exactly one lens: a single lens is just a worse,
|
|
846
|
-
// slower version of doing the work yourself.
|
|
871
|
+
// Review and IncrementalReview route the minimum reviewfrog specialists
|
|
872
|
+
// needed to cover unresolved, disposition-changing hypotheses. Most runs
|
|
873
|
+
// use zero or one; multiple orthogonal hypotheses dispatch in parallel.
|
|
847
874
|
//
|
|
848
875
|
// Build mode self-review is a different problem shape: the orchestrator
|
|
849
876
|
// wrote the code, so bias-mitigation comes from delegating to one
|
|
850
877
|
// fresh-eyes subagent that doesn't share the implementation context. A
|
|
851
|
-
// single subagent there is appropriate
|
|
852
|
-
// the
|
|
853
|
-
// perspectives is what's being purchased.
|
|
878
|
+
// single subagent there is appropriate. Review-mode specialist routing
|
|
879
|
+
// instead scales with the unresolved hypotheses in someone else's diff.
|
|
854
880
|
//
|
|
855
881
|
// Severity categorization is split across two surfaces: the opening
|
|
856
882
|
// callout (CAUTION/IMPORTANT/ℹ️/✅) sets the review's overall tier, and
|
|
@@ -865,11 +891,11 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
865
891
|
|
|
866
892
|
1. **task list**: create your task list for this run as your first action.
|
|
867
893
|
|
|
868
|
-
2. **checkout**: call \`${t("checkout_pr")}\` \u2014 this returns PR metadata and a \`
|
|
894
|
+
2. **checkout**: call \`${t("checkout_pr")}\` \u2014 this returns PR metadata, a \`diffPath\`, and a supplemental \`impactPath\` when change-impact extraction is enabled. read the complete raw diff end-to-end, beginning with the TOC and using its file line ranges as your coverage checklist. only after that, use \`impactPath\` as an explicitly incomplete list of reference leads; it never replaces raw-diff reading or establishes coverage.
|
|
869
895
|
|
|
870
896
|
3. **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). pull as much context as you need to render a confident, well-grounded review: read related files, grep for callers of changed symbols, check tests that exercise the touched paths, fetch related GitHub state. **you are the synthesizer** \u2014 never delegate understanding to subagents.
|
|
871
897
|
|
|
872
|
-
if the PR is **genuinely trivial**, skip
|
|
898
|
+
if the PR is **genuinely trivial**, skip specialists entirely and submit a \`No new issues found.\` review per step 7.
|
|
873
899
|
|
|
874
900
|
"Genuinely trivial" (skip):
|
|
875
901
|
- single-word doc typo, whitespace/format-only, comment-only across any number of files
|
|
@@ -888,22 +914,24 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
888
914
|
- any "typo fix" in user-facing copy that changes meaning ("approved" \u2192 "denied")
|
|
889
915
|
- mixed diffs where a semantic 1-liner is buried in whitespace/formatting changes
|
|
890
916
|
|
|
891
|
-
4. **
|
|
917
|
+
4. **specialist decision \u2014 minimum hypothesis coverage**.
|
|
892
918
|
|
|
893
|
-
|
|
919
|
+
After full-diff coverage and triage, identify the load-bearing questions you still cannot resolve confidently yourself. A specialist hypothesis is load-bearing only when its answer could yield an actionable finding that changes the review disposition and warrants independent investigation, and falsifiable only when the specialist can return evidence that supports or refutes it. Generic requests for extra confidence, polish, or "another look" do not qualify.
|
|
894
920
|
|
|
895
|
-
|
|
896
|
-
-
|
|
897
|
-
-
|
|
898
|
-
- parallel-
|
|
921
|
+
Route the **minimum number of \`${REVIEWER_AGENT_NAME}\` specialists** needed to cover those unresolved hypotheses. Most reviews need **0 or 1**:
|
|
922
|
+
- dispatch 0 when you can resolve every disposition-changing question directly
|
|
923
|
+
- dispatch 1 when exactly one falsifiable, load-bearing hypothesis warrants independent investigation
|
|
924
|
+
- dispatch 2+ in parallel when multiple orthogonal load-bearing hypotheses remain, or when the user explicitly requests an exhaustive or multi-angle review
|
|
899
925
|
|
|
900
|
-
**
|
|
926
|
+
**There is NO one-specialist cap or fixed maximum.** Cover every orthogonal load-bearing hypothesis that remains; do not collapse multiple real questions into one broad prompt just to reduce the count. There is also no file-count, line-count, schema, quota, or hard-budget threshold \u2014 diff size is not a proxy for review uncertainty.
|
|
901
927
|
|
|
902
|
-
|
|
928
|
+
The primary reviewer remains responsible for reading the complete raw diff, investigating surrounding code, validating every returned finding, and synthesizing the final review. Specialist reads supplement that work; they never replace it or satisfy the primary's diff-coverage obligation.
|
|
929
|
+
|
|
930
|
+
Specialist hypotheses can draw on two kinds of framing:
|
|
903
931
|
- **themed lenses** \u2014 a perspective applied across the whole diff (correctness, security, user-journey, performance, etc.).
|
|
904
932
|
- **subsystem lenses** \u2014 a domain-scoped frame for high-stakes subsystems the PR touches (e.g. "the auth lens", "the billing lens", "the schema-migration lens"). **for high-stakes domains, lead with the subsystem lens rather than the generic themed equivalent** \u2014 "billing-subsystem" outperforms "correctness on billing code" because the framing primes the subagent to remember domain-specific failure modes (double-charges, refund races, currency rounding, dispute flows) the generic lens misses.
|
|
905
933
|
|
|
906
|
-
starter menu (combine, omit, or invent your own):
|
|
934
|
+
starter menu for identifying hypotheses (combine, omit, or invent your own; do not dispatch a bare menu label without a falsifiable question):
|
|
907
935
|
- **correctness & invariants** \u2014 bugs, races, error handling, edge cases, state-machine boundaries
|
|
908
936
|
- **impact** \u2014 stale references in code/tests/docs/configs/UI after rename/remove
|
|
909
937
|
- **research-validated assumptions** \u2014 third-party API contracts, SDK semantics, framework directives, version-gated behavior. **only pick when the PR's correctness depends on the contract behaving a specific way** \u2014 not when the API is merely used. The bar is "if the third-party contract differs from what the diff assumes, the PR is incorrect." When dispatched, the subagent must verify load-bearing claims via web search and quote source URLs.
|
|
@@ -918,30 +946,27 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
918
946
|
|
|
919
947
|
The only subagent type is \`${REVIEWER_AGENT_NAME}\` \u2014 used for lens judgment work ("is this safe / correct / well-tested?"), runs on a mid-tier model.
|
|
920
948
|
|
|
921
|
-
5. **
|
|
922
|
-
|
|
923
|
-
\u26A0\uFE0F CRITICAL \u2014 PARALLELISM IS THE ONLY REASON LENSES EXIST. \u26A0\uFE0F
|
|
924
|
-
The default tool-call behavior of Claude Code (and most agent runtimes) is **serial dispatch**: emit one Task call, await result, emit next, await, etc. This collapses your fan-out into a sequential review where each lens adds N \xD7 (orchestrator-think-time + lens-execution-time) to wall time. **YOU MUST OVERRIDE THIS DEFAULT.** Emit ALL of your Task tool_use blocks in the SAME assistant message, BEFORE you read ANY result from ANY of them. If you find yourself emitting one Task call, then thinking about the result, then emitting another \u2014 STOP and re-issue them all together. The whole point of going multi-lens is the wall-clock speedup from parallel execution; serial dispatch defeats it entirely.
|
|
949
|
+
5. **dispatch specialists (only if step 4 found unresolved hypotheses)**: dispatch one \`${REVIEWER_AGENT_NAME}\` for one hypothesis. For 2+ hypotheses, emit every Task tool_use block **IN A SINGLE ASSISTANT TURN** before reading any result so the investigations run in parallel rather than serially.
|
|
925
950
|
|
|
926
|
-
\u2705 Right pattern: one assistant turn with N Task tool_use blocks \u2192 wait \u2192 N results arrive together \u2192 aggregate.
|
|
927
|
-
\u274C Wrong pattern:
|
|
951
|
+
\u2705 Right multi-specialist pattern: one assistant turn with N Task tool_use blocks \u2192 wait \u2192 N results arrive together \u2192 aggregate.
|
|
952
|
+
\u274C Wrong multi-specialist pattern: Task(hypothesis A) \u2192 wait for A \u2192 Task(hypothesis B).
|
|
928
953
|
|
|
929
954
|
You can also include your own \`read\` / \`grep\` / \`webfetch\` calls in the SAME turn as the parallel \`${REVIEWER_AGENT_NAME}\` dispatches \u2014 concurrent context-pulling on the orchestrator side runs in parallel with the lens fan-out and costs zero extra wall time.
|
|
930
955
|
|
|
931
|
-
if a
|
|
956
|
+
if a specialist errors out, times out, or returns nothing usable, retry it once with the same hypothesis. if it still fails, attempt to resolve the hypothesis yourself; if it remains disposition-changing and unresolved, surface the limitation and do not approve. each specialist gets:
|
|
932
957
|
- **the absolute \`diffPath\` (and \`incrementalDiffPath\` if available) from step 2's \`${t("checkout_pr")}\` return, named verbatim in the dispatch prompt** (e.g. \`diffPath: /tmp/pullfrog-XXXX/pr-NNN-SHA.diff\`). the reviewer's baked-in system prompt selects its FIRST action on this token \u2014 paraphrasing ("review the diff", "look at this PR") sends it down the \`git diff origin/<base>\` fallback, which fails on shallow GHA checkouts. the subagent \`read\`s those files for scope; it must NOT re-derive the diff via \`git diff\` (bare \`git diff origin/<base>\` is symmetric and pulls in the inverse of any commits that landed on \`<base>\` since the branch forked \u2014 pure noise, and the git tool rejects it). reading and codebase exploration are still its job.
|
|
933
|
-
- **
|
|
934
|
-
- **a Task \`description\` set to
|
|
958
|
+
- **exactly one falsifiable hypothesis with explicit scope boundaries** \u2014 ask for evidence that supports or refutes it, never a broad "review for X, Y, and Z" prompt
|
|
959
|
+
- **a Task \`description\` set to a short hypothesis label** (e.g. \`"webhook-replay"\`, \`"billing-rounding"\`) \u2014 the harness reads this field to label the subagent's log lines so parallel runs can be told apart in CI output. without it, every subagent shows up as \`subagent#N\`.
|
|
935
960
|
- if the lens touches external contracts, instruct the subagent to verify load-bearing claims via web search rather than trust training data, and to quote source URLs in its reasoning. action runs are non-interactive \u2014 there's no human in the loop to catch "I'm pretty sure Stripe does X."
|
|
936
|
-
- ask the subagent to report findings with file paths and NEW line numbers from the diff so you can anchor
|
|
961
|
+
- ask the subagent to report findings with file paths and NEW line numbers from the diff so you can validate and anchor them. you must still read the complete diff yourself.
|
|
937
962
|
|
|
938
963
|
delegation discipline:
|
|
939
|
-
- do NOT summarize the PR for them (biases toward a validation frame)
|
|
964
|
+
- do NOT summarize the PR for them (a lossy summary biases toward a validation frame; the raw diff is the source)
|
|
940
965
|
- do NOT hand them a curated reading list (let them discover scope)
|
|
941
966
|
- do NOT pre-shape their output with a finding schema
|
|
942
967
|
- do NOT mention the other lenses (independence is the point \u2014 overlapping findings are a strong signal)
|
|
943
968
|
|
|
944
|
-
6. **aggregate & draft**: when
|
|
969
|
+
6. **aggregate & draft**: when specialist results land, merge findings; de-dup overlaps (two specialists catching the same issue = higher-confidence signal); trace each finding yourself before accepting it. drop praise, style preferences, speculative/unverified claims, findings about pre-existing code unrelated to the PR (heuristic: if the finding's root cause lives in lines this PR added or modified, it's in scope; otherwise drop unless the PR plausibly introduced or amplified the regression), and anything not actionable. 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 worse, degrades elegance to nominally improve correctness) makes the codebase worse, not better.
|
|
945
970
|
|
|
946
971
|
**Hunt for non-anchored concerns before drafting.** After collecting your anchored findings, deliberately scan for concerns that have no specific line to point at \u2014 typically: deletion / cleanup plans for code the diff replaces or shadows; rollout sequencing (what happens to in-flight state during deploy / revert?); coverage gaps the diff implies but doesn't add; scope questions that only the human can answer (e.g. is the legacy path going away or is this a long-term dual track?); architectural risks the diff opens up that aren't a single-line bug. On substantial PRs (migrations, refactors, multi-file rewrites, version bumps that change runtime semantics), at least one such concern almost always exists; if you can't think of any, your bar is probably too high.
|
|
947
972
|
|
|
@@ -975,10 +1000,10 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
975
1000
|
|
|
976
1001
|
${PR_SUMMARY_FORMAT}`
|
|
977
1002
|
},
|
|
978
|
-
// IncrementalReview shares Review's
|
|
979
|
-
// format
|
|
980
|
-
// prior
|
|
981
|
-
// review" filter lives at aggregation time
|
|
1003
|
+
// IncrementalReview shares Review's minimum hypothesis-covering specialist
|
|
1004
|
+
// routing and body format, scoped to the incremental delta against the
|
|
1005
|
+
// prior Pullfrog review. The "issues must be NEW since the last Pullfrog
|
|
1006
|
+
// review" filter lives at aggregation time, NOT in the subagent
|
|
982
1007
|
// prompt — pushing the filter into subagents matches the canonical anneal
|
|
983
1008
|
// anti-pattern of "list known pre-existing failures — don't flag these"
|
|
984
1009
|
// and suppresses signal on regressions the new commits amplified. A
|
|
@@ -993,9 +1018,9 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
993
1018
|
|
|
994
1019
|
1. **task list**: create your task list for this run as your first action.
|
|
995
1020
|
|
|
996
|
-
2. **checkout**: call \`${t("checkout_pr")}\` \u2014 this returns PR metadata, \`diffPath\` (full diff),
|
|
1021
|
+
2. **checkout**: call \`${t("checkout_pr")}\` \u2014 this returns PR metadata, \`diffPath\` (full diff), \`incrementalDiffPath\` (changes since last reviewed version, if available), and a supplemental \`impactPath\` when change-impact extraction is enabled.
|
|
997
1022
|
|
|
998
|
-
3. **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.
|
|
1023
|
+
3. **incremental scope**: if \`incrementalDiffPath\` is present, read it FIRST to see what changed since the last review. this is a range-diff that isolates the net changes, filtering out base branch noise. then read the authoritative full diff end-to-end, beginning with the TOC and using its line ranges as your coverage checklist. if no incremental diff is present, start with the full-diff TOC, determine what changed since Pullfrog's most recent review, and complete the raw-diff read. only after establishing that authoritative scope and completing raw-diff coverage, use \`impactPath\` as an explicitly incomplete list of reference leads; it never replaces raw-diff reading or establishes coverage.
|
|
999
1024
|
|
|
1000
1025
|
4. **prior feedback \u2014 read AND retire it**: fetch previous reviews via \`${t("list_pull_request_reviews")}\`, then call \`${t("get_review_comments")}\` on each prior Pullfrog review. Each thread renders as a section whose first line is a fenced tag \`comment author=<login> id=<fullDatabaseId> review=<reviewId> thread=<graphqlId>\`; section headers carry \`[RESOLVED]\` / \`[OUTDATED]\` when relevant. For every **open, Pullfrog-originated** thread, decide and act:
|
|
1001
1026
|
|
|
@@ -1009,49 +1034,48 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
1009
1034
|
|
|
1010
1035
|
5. **triage**: orient on the *incremental* changes \u2014 domain, seams, external contracts, user-facing surfaces. pull as much context as you need to render a confident review: read related files, grep for callers of changed symbols, check tests that exercise the touched paths. **you are the synthesizer.**
|
|
1011
1036
|
|
|
1012
|
-
if the incremental changes are **genuinely trivial**, skip
|
|
1037
|
+
if the incremental changes are **genuinely trivial**, skip specialists entirely and jump to step 10's non-substantive path (do NOT submit a review).
|
|
1013
1038
|
|
|
1014
1039
|
"Genuinely trivial" (skip): formatting/comment tweaks, import reordering, lockfile regen, mechanical rename of import paths, whitespace-only.
|
|
1015
1040
|
"Looks trivial but isn't" (do NOT skip \u2014 same anti-patterns as Review mode): 1-line changes to SQL/regex/auth/billing/permissions/signature-verification code; flipping feature-flag defaults or retry/timeout constants; money/tax/HTTP-method/redirect changes; tightening or loosening a comparison operator; mixed diffs with a semantic line buried in formatting.
|
|
1016
1041
|
When unsure, treat as non-trivial.
|
|
1017
1042
|
|
|
1018
|
-
6. **
|
|
1043
|
+
6. **specialist decision \u2014 minimum hypothesis coverage**.
|
|
1019
1044
|
|
|
1020
|
-
|
|
1045
|
+
After full-diff coverage and triage, identify the load-bearing questions about the incremental changes that you still cannot resolve confidently yourself. A specialist hypothesis is load-bearing only when its answer could yield an actionable new finding that changes the review disposition and warrants independent investigation, and falsifiable only when the specialist can return evidence that supports or refutes it. Generic requests for extra confidence, polish, or "another look" do not qualify.
|
|
1021
1046
|
|
|
1022
|
-
|
|
1023
|
-
-
|
|
1024
|
-
-
|
|
1025
|
-
- parallel-
|
|
1047
|
+
Route the **minimum number of \`${REVIEWER_AGENT_NAME}\` specialists** needed to cover those unresolved hypotheses. Most incremental reviews need **0 or 1**, especially thread-reply re-reviews:
|
|
1048
|
+
- dispatch 0 when you can resolve every disposition-changing question directly
|
|
1049
|
+
- dispatch 1 when exactly one falsifiable, load-bearing hypothesis warrants independent investigation
|
|
1050
|
+
- dispatch 2+ in parallel when multiple orthogonal load-bearing hypotheses remain, or when the user explicitly requests an exhaustive or multi-angle review
|
|
1026
1051
|
|
|
1027
|
-
**
|
|
1052
|
+
**There is NO one-specialist cap or fixed maximum.** Cover every orthogonal load-bearing hypothesis that remains; do not collapse multiple real questions into one broad prompt just to reduce the count. There is also no file-count, line-count, schema, quota, or hard-budget threshold \u2014 diff size is not a proxy for review uncertainty.
|
|
1028
1053
|
|
|
1029
|
-
|
|
1054
|
+
The primary reviewer remains responsible for reading the complete raw full diff plus the incremental diff, investigating surrounding code, validating every returned finding, and synthesizing the final review. Specialist reads supplement that work; they never replace it or satisfy the primary's diff-coverage obligation.
|
|
1030
1055
|
|
|
1031
|
-
|
|
1056
|
+
Specialist hypotheses can draw on Review mode's themed or subsystem framings, but every dispatch must turn the framing into one falsifiable question with explicit scope boundaries.
|
|
1032
1057
|
|
|
1033
|
-
|
|
1034
|
-
Default tool-call behavior is **serial dispatch**: emit one Task call, await result, emit next, await, etc. This collapses your fan-out into a sequential review where each lens adds N \xD7 (orchestrator-think-time + lens-execution-time) to wall time. **YOU MUST OVERRIDE THIS DEFAULT.** Emit ALL of your Task tool_use blocks in the SAME assistant message, BEFORE you read ANY result from ANY of them.
|
|
1058
|
+
7. **dispatch specialists (only if step 6 found unresolved hypotheses)**: dispatch one \`${REVIEWER_AGENT_NAME}\` for one hypothesis. For 2+ hypotheses, emit every Task tool_use block **IN A SINGLE ASSISTANT TURN** before reading any result so the investigations run in parallel rather than serially.
|
|
1035
1059
|
|
|
1036
|
-
\u2705 Right pattern: one assistant turn with N Task tool_use blocks \u2192 wait \u2192 N results arrive together \u2192 aggregate.
|
|
1037
|
-
\u274C Wrong pattern:
|
|
1060
|
+
\u2705 Right multi-specialist pattern: one assistant turn with N Task tool_use blocks \u2192 wait \u2192 N results arrive together \u2192 aggregate.
|
|
1061
|
+
\u274C Wrong multi-specialist pattern: Task(hypothesis A) \u2192 wait for A \u2192 Task(hypothesis B).
|
|
1038
1062
|
|
|
1039
1063
|
You can also include your own \`read\` / \`grep\` / \`webfetch\` calls in the SAME turn as the parallel \`${REVIEWER_AGENT_NAME}\` dispatches.
|
|
1040
1064
|
|
|
1041
|
-
if a
|
|
1065
|
+
if a specialist errors out, times out, or returns nothing usable, retry it once with the same hypothesis. if it still fails, attempt to resolve the hypothesis yourself; if it remains disposition-changing and unresolved, surface the limitation and do not approve. each specialist gets:
|
|
1042
1066
|
- **the absolute diff path(s) from step 2's \`${t("checkout_pr")}\` return, named verbatim in the dispatch prompt.** when \`incrementalDiffPath\` is present, name BOTH (\`incrementalDiffPath: /tmp/.../pr-NNN-SHA-incremental.diff\` then \`diffPath: /tmp/.../pr-NNN-SHA.diff\`) \u2014 the reviewer's baked-in prompt reads incremental first and uses full for context; when only \`diffPath\` exists, name it alone. the subagent \`read\`s those files; it must NOT re-derive via \`git diff\` (bare \`git diff origin/<base>\` is symmetric and pulls in the inverse of base-branch progress \u2014 pure noise, and the git tool rejects it), and paraphrasing ("review the new commits") sends it down that fallback, which also fails on shallow GHA checkouts. do NOT tell them to skip pre-existing issues \u2014 that suppresses regressions the new commits amplified; the "issues must be NEW" filter lives at aggregation time (step 8), not in the subagent prompt.
|
|
1043
|
-
- **
|
|
1044
|
-
- **a Task \`description\` set to
|
|
1067
|
+
- **exactly one falsifiable hypothesis with explicit scope boundaries** \u2014 ask for evidence that supports or refutes it, never a broad "review for X, Y, and Z" prompt
|
|
1068
|
+
- **a Task \`description\` set to a short hypothesis label** \u2014 the harness reads this field to label log lines so parallel runs can be told apart.
|
|
1045
1069
|
- if the lens touches external contracts, instruct the subagent to verify load-bearing claims via web search and quote source URLs.
|
|
1046
|
-
- ask the subagent to report findings with file paths and NEW line numbers from the full PR diff so you can anchor
|
|
1070
|
+
- ask the subagent to report findings with file paths and NEW line numbers from the full PR diff so you can validate and anchor them. you must still read the complete incremental and full diff scope yourself.
|
|
1047
1071
|
|
|
1048
1072
|
delegation discipline:
|
|
1049
|
-
- do NOT summarize the changes for them (biases toward validation frame)
|
|
1073
|
+
- do NOT summarize the changes for them (a lossy summary biases toward a validation frame; the raw diff is the source)
|
|
1050
1074
|
- do NOT hand them a curated reading list (let them discover scope)
|
|
1051
1075
|
- do NOT pre-shape their output with a finding schema
|
|
1052
1076
|
- do NOT mention the other lenses (independence is the point)
|
|
1053
1077
|
|
|
1054
|
-
8. **aggregate, draft, self-critique**: merge findings (yours +
|
|
1078
|
+
8. **aggregate, draft, self-critique**: merge findings (yours + output from every specialist you dispatched); 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 2 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 4) and run \`git diff <prior-review-sha>..HEAD\` to isolate the lines added since that review.
|
|
1055
1079
|
|
|
1056
1080
|
**Hunt for non-anchored concerns before drafting.** After collecting your anchored findings, deliberately scan for concerns that have no specific line to point at \u2014 typically: deletion / cleanup plans for code the new commits replace or shadow; rollout sequencing (what happens to in-flight state during deploy / revert?); coverage gaps the new commits imply but don't add; scope questions that only the human can answer (e.g. is the legacy path going away or is this a long-term dual track?); architectural risks the new commits open up that aren't a single-line bug. On substantial incremental diffs (migrations, refactors, multi-file rewrites, version bumps that change runtime semantics), at least one such concern almost always exists; if you can't think of any, your bar is probably too high.
|
|
1057
1081
|
|
|
@@ -1148,7 +1172,7 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
1148
1172
|
|
|
1149
1173
|
1. **task list**: create your task list for this run as your first action.
|
|
1150
1174
|
|
|
1151
|
-
2. Analyze the task. For simple operations (labeling,
|
|
1175
|
+
2. Analyze the task. For simple operations (labeling, answering questions, running a single command), handle directly \u2014 but your answer only reaches the user through \`${t("report_progress")}\` (step 4); raw assistant text is discarded. If a standalone comment on the current issue/PR is the task's sole requested deliverable, create that comment directly and skip \`${t("report_progress")}\`.
|
|
1152
1176
|
|
|
1153
1177
|
3. For substantial work \u2014 code changes across multiple files, multi-step investigations:
|
|
1154
1178
|
- plan your approach before starting
|
|
@@ -1158,8 +1182,8 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
1158
1182
|
|
|
1159
1183
|
4. Finalize:
|
|
1160
1184
|
- if code changes were made, get them onto a pull request (new or existing) using ${signedCommits ? `\`${t("commit_changes")}\`` : `\`${t("push_branch")}\``} and \`${t("create_pull_request")}\` as needed. \`git status\` must be clean before you finish (see *SYSTEM* Git rules if this fails).
|
|
1161
|
-
- call \`${t("report_progress")}\` once with results \u2014 include exact tool errors if push or PR creation failed
|
|
1162
|
-
- if the task involved labeling
|
|
1185
|
+
- call \`${t("report_progress")}\` once with results \u2014 include exact tool errors if push or PR creation failed. skip this only when a standalone comment on the current target was the task's sole requested deliverable
|
|
1186
|
+
- if the task involved labeling or other GitHub operations, perform those directly`
|
|
1163
1187
|
}
|
|
1164
1188
|
];
|
|
1165
1189
|
}
|
package/dist/mcp/checkout.d.ts
CHANGED
package/dist/mcp/shared.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export declare function getHttpStatus(err: unknown): number | undefined;
|
|
|
9
9
|
* the single source of truth the subagent deny list derives from (see
|
|
10
10
|
* action/agents/subagentToolGates.ts). general-purpose execution tools (`git`,
|
|
11
11
|
* `shell`) are deliberately left unmarked: they can mutate but are allowed for
|
|
12
|
-
* subagents and gated by command-arg validation instead.
|
|
12
|
+
* subagents and gated by command-arg validation instead. `readOnlyHint` is
|
|
13
|
+
* independent scheduler metadata and must only follow an implementation audit;
|
|
14
|
+
* the absence of `mutates` does not imply that a tool is read-only.
|
|
13
15
|
*/
|
|
14
16
|
export type PullfrogTool = Tool<any, any> & {
|
|
15
17
|
mutates?: boolean;
|
package/dist/models.d.ts
CHANGED
|
@@ -28,6 +28,9 @@ export interface ModelAlias {
|
|
|
28
28
|
provider: string;
|
|
29
29
|
/** human-readable name shown in dropdowns */
|
|
30
30
|
displayName: string;
|
|
31
|
+
/** optional one-line picker sub-label clarifying what the alias is (e.g.
|
|
32
|
+
* gpt-pro = "Maximum reasoning effort"). undefined for most aliases. */
|
|
33
|
+
description: string | undefined;
|
|
31
34
|
/** concrete models.dev specifier, e.g. "anthropic/claude-opus-4-6". sentinel for routing entries — never passed to a CLI directly. */
|
|
32
35
|
resolve: string;
|
|
33
36
|
/** full models.dev specifier for the OpenRouter equivalent (undefined for free models and routing entries) */
|
|
@@ -48,12 +51,14 @@ export interface ModelAlias {
|
|
|
48
51
|
* use as its lens-fanout subagent. e.g. claude-opus → "claude-sonnet". */
|
|
49
52
|
subagentModel: string | undefined;
|
|
50
53
|
/** hide from selectable lists (UI dropdowns, CLI pickers). does NOT affect
|
|
51
|
-
* resolution — for that use `fallback`. used
|
|
52
|
-
* (e.g.
|
|
54
|
+
* resolution — for that use `fallback`. used to keep a redundant alias out of
|
|
55
|
+
* pickers (e.g. the free `minimax-m2.5-free` duplicate). */
|
|
53
56
|
hidden: boolean;
|
|
54
57
|
}
|
|
55
58
|
interface ModelDef {
|
|
56
59
|
displayName: string;
|
|
60
|
+
/** optional one-line picker sub-label (e.g. "Maximum reasoning effort"). */
|
|
61
|
+
description?: string;
|
|
57
62
|
/** concrete models.dev specifier, e.g. "anthropic/claude-opus-4-6" */
|
|
58
63
|
resolve: string;
|
|
59
64
|
/** full models.dev specifier for the OpenRouter equivalent, e.g. "openrouter/anthropic/claude-opus-4.6" */
|
package/dist/toolState.d.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RestEndpointMethodTypes } from "@octokit/rest";
|
|
2
|
+
import type { ToolContext } from "../mcp/server.ts";
|
|
3
|
+
type PullFile = RestEndpointMethodTypes["pulls"]["listFiles"]["response"]["data"][number];
|
|
4
|
+
type CreateChangeImpactParams = {
|
|
5
|
+
files: PullFile[];
|
|
6
|
+
pullNumber: number;
|
|
7
|
+
baseSha: string;
|
|
8
|
+
headSha: string;
|
|
9
|
+
};
|
|
10
|
+
type ChangeImpactResult = {
|
|
11
|
+
path: string;
|
|
12
|
+
candidateCount: number;
|
|
13
|
+
renderedAtomCount: number;
|
|
14
|
+
referenceCount: number;
|
|
15
|
+
bytes: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function createChangeImpactArtifact(ctx: ToolContext, params: CreateChangeImpactParams): Promise<ChangeImpactResult>;
|
|
18
|
+
export {};
|
|
@@ -31,7 +31,6 @@ export type DiffCoverageState = {
|
|
|
31
31
|
tocEntries: DiffTocEntry[];
|
|
32
32
|
coveredRanges: DiffLineRange[];
|
|
33
33
|
coveragePreflightRan: boolean;
|
|
34
|
-
lastBreakdown?: string | undefined;
|
|
35
34
|
};
|
|
36
35
|
export declare function countLines(params: {
|
|
37
36
|
content: string;
|
|
@@ -54,10 +53,6 @@ export declare function recordDiffReadFromToolUse(params: {
|
|
|
54
53
|
export declare function getDiffCoverageBreakdown(params: {
|
|
55
54
|
state: DiffCoverageState;
|
|
56
55
|
}): DiffCoverageBreakdown;
|
|
57
|
-
export declare function renderDiffCoverageBreakdown(params: {
|
|
58
|
-
diffPath: string;
|
|
59
|
-
breakdown: DiffCoverageBreakdown;
|
|
60
|
-
}): string;
|
|
61
56
|
export declare function countLinesInRanges(params: {
|
|
62
57
|
ranges: DiffLineRange[];
|
|
63
58
|
}): number;
|