pullfrog 0.1.31 → 0.1.33
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 +17 -1
- package/dist/cli.mjs +594 -213
- package/dist/index.js +593 -212
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal.js +37 -10
- package/dist/mcp/review.d.ts +41 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/toolState.d.ts +4 -0
- package/dist/utils/agent.d.ts +3 -1
- package/dist/utils/autoMerge.d.ts +37 -0
- package/dist/utils/checksGate.d.ts +45 -0
- package/dist/utils/isTransientNetworkError.d.ts +9 -0
- package/dist/utils/payload.d.ts +10 -1
- package/dist/utils/runContext.d.ts +1 -0
- package/dist/utils/statusChecks.d.ts +25 -0
- package/dist/yes/index.d.ts +26 -0
- package/dist/yes.js +38 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99818,15 +99818,20 @@ var providers = {
|
|
|
99818
99818
|
displayName: "Anthropic",
|
|
99819
99819
|
envVars: ["ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"],
|
|
99820
99820
|
models: {
|
|
99821
|
-
// claude-fable-5 is
|
|
99822
|
-
//
|
|
99823
|
-
//
|
|
99824
|
-
//
|
|
99825
|
-
//
|
|
99821
|
+
// claude-fable-5 is selectable but not recommended/auto-selected — it's
|
|
99822
|
+
// moving to usage-credits-only billing and isn't broadly available yet, so
|
|
99823
|
+
// opus stays the universally-available flagship, the AUTO_INTELLIGENT tier
|
|
99824
|
+
// target, and the recommended pick. an explicit fable pick hits the real
|
|
99825
|
+
// API and is access-gated: it errors for accounts without access today and
|
|
99826
|
+
// just works once usage credits are live — no silent opus fallback, the
|
|
99827
|
+
// API is the source of truth (#959).
|
|
99826
99828
|
"claude-fable": {
|
|
99827
99829
|
displayName: "Claude Fable",
|
|
99828
99830
|
resolve: "anthropic/claude-fable-5",
|
|
99829
|
-
|
|
99831
|
+
// rolling alias: models.dev's OpenRouter mirror lags brand-new pinned
|
|
99832
|
+
// versions (claude-fable-5 isn't indexed yet), so track ~…-latest to
|
|
99833
|
+
// stay catalog-valid and auto-follow version bumps.
|
|
99834
|
+
openRouterResolve: "openrouter/~anthropic/claude-fable-latest",
|
|
99830
99835
|
subagentModel: "claude-sonnet"
|
|
99831
99836
|
},
|
|
99832
99837
|
"claude-opus": {
|
|
@@ -99838,8 +99843,8 @@ var providers = {
|
|
|
99838
99843
|
},
|
|
99839
99844
|
"claude-sonnet": {
|
|
99840
99845
|
displayName: "Claude Sonnet",
|
|
99841
|
-
resolve: "anthropic/claude-sonnet-
|
|
99842
|
-
openRouterResolve: "openrouter/anthropic/claude-sonnet-
|
|
99846
|
+
resolve: "anthropic/claude-sonnet-5",
|
|
99847
|
+
openRouterResolve: "openrouter/anthropic/claude-sonnet-5"
|
|
99843
99848
|
},
|
|
99844
99849
|
"claude-haiku": {
|
|
99845
99850
|
displayName: "Claude Haiku",
|
|
@@ -100017,8 +100022,8 @@ var providers = {
|
|
|
100017
100022
|
},
|
|
100018
100023
|
"claude-sonnet": {
|
|
100019
100024
|
displayName: "Claude Sonnet",
|
|
100020
|
-
resolve: "opencode/claude-sonnet-
|
|
100021
|
-
openRouterResolve: "openrouter/anthropic/claude-sonnet-
|
|
100025
|
+
resolve: "opencode/claude-sonnet-5",
|
|
100026
|
+
openRouterResolve: "openrouter/anthropic/claude-sonnet-5"
|
|
100022
100027
|
},
|
|
100023
100028
|
"claude-haiku": {
|
|
100024
100029
|
displayName: "Claude Haiku",
|
|
@@ -101036,7 +101041,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
101036
101041
|
// package.json
|
|
101037
101042
|
var package_default = {
|
|
101038
101043
|
name: "pullfrog",
|
|
101039
|
-
version: "0.1.
|
|
101044
|
+
version: "0.1.33",
|
|
101040
101045
|
type: "module",
|
|
101041
101046
|
bin: {
|
|
101042
101047
|
pullfrog: "dist/cli.mjs",
|
|
@@ -102775,7 +102780,7 @@ function buildAgentsJson() {
|
|
|
102775
102780
|
[REVIEWER_AGENT_NAME]: {
|
|
102776
102781
|
description: "Read-only review subagent for lens-based code review (correctness, security, billing-subsystem, etc.). Reads only \u2014 no writes, no state-changing shell or MCP calls, no nested subagent dispatch.",
|
|
102777
102782
|
prompt: REVIEWER_SYSTEM_PROMPT,
|
|
102778
|
-
model: "claude-sonnet-
|
|
102783
|
+
model: "claude-sonnet-5"
|
|
102779
102784
|
}
|
|
102780
102785
|
};
|
|
102781
102786
|
return JSON.stringify(agents2);
|
|
@@ -150952,6 +150957,34 @@ function getCacheKeyString(value2) {
|
|
|
150952
150957
|
);
|
|
150953
150958
|
}
|
|
150954
150959
|
}
|
|
150960
|
+
var DEFAULT_RETRY_AFTER_CAP_MS = 2e4;
|
|
150961
|
+
function getErrorResponseHeaders(error49) {
|
|
150962
|
+
if (error49 === null || typeof error49 !== "object") return void 0;
|
|
150963
|
+
const response = error49.response;
|
|
150964
|
+
if (response === null || typeof response !== "object") return void 0;
|
|
150965
|
+
const headers = response.headers;
|
|
150966
|
+
if (headers === null || typeof headers !== "object") return void 0;
|
|
150967
|
+
return headers;
|
|
150968
|
+
}
|
|
150969
|
+
function retryAfterMs(error49) {
|
|
150970
|
+
const headers = getErrorResponseHeaders(error49);
|
|
150971
|
+
if (!headers) return void 0;
|
|
150972
|
+
const retryAfter = headers["retry-after"];
|
|
150973
|
+
if (typeof retryAfter === "string" && retryAfter.trim() !== "") {
|
|
150974
|
+
const seconds = Number(retryAfter);
|
|
150975
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
150976
|
+
const dateMs = Date.parse(retryAfter);
|
|
150977
|
+
if (!Number.isNaN(dateMs)) return Math.max(0, dateMs - Date.now());
|
|
150978
|
+
}
|
|
150979
|
+
if (headers["x-ratelimit-remaining"] === "0") {
|
|
150980
|
+
const reset = headers["x-ratelimit-reset"];
|
|
150981
|
+
if (typeof reset === "string" && reset.trim() !== "") {
|
|
150982
|
+
const resetEpoch = Number(reset);
|
|
150983
|
+
if (Number.isFinite(resetEpoch)) return Math.max(0, resetEpoch * 1e3 - Date.now());
|
|
150984
|
+
}
|
|
150985
|
+
}
|
|
150986
|
+
return void 0;
|
|
150987
|
+
}
|
|
150955
150988
|
function validateSchema(schema2, value2) {
|
|
150956
150989
|
const result = schema2["~standard"].validate(value2);
|
|
150957
150990
|
if (result instanceof Promise) {
|
|
@@ -151089,7 +151122,15 @@ function _op(fn2, options) {
|
|
|
151089
151122
|
log2.info({ key, error: error49, attempt });
|
|
151090
151123
|
}
|
|
151091
151124
|
} else {
|
|
151092
|
-
|
|
151125
|
+
let delay2 = retries[attempt];
|
|
151126
|
+
if (options.retryAfter) {
|
|
151127
|
+
const extract = options.retryAfter === true ? retryAfterMs : options.retryAfter;
|
|
151128
|
+
const hint = extract(error49);
|
|
151129
|
+
if (hint !== void 0) {
|
|
151130
|
+
const cap = options.retryAfterCap ?? DEFAULT_RETRY_AFTER_CAP_MS;
|
|
151131
|
+
delay2 = Math.max(delay2, Math.min(cap, hint));
|
|
151132
|
+
}
|
|
151133
|
+
}
|
|
151093
151134
|
if (namePrefix) {
|
|
151094
151135
|
log2.info(
|
|
151095
151136
|
`${namePrefix}attempt ${attempt + 1}/${retries.length + 1} failed, retrying in ${delay2}ms`
|
|
@@ -156818,6 +156859,12 @@ function isTransientNetworkError(error49, extraPatterns = []) {
|
|
|
156818
156859
|
const patterns = ["fetch failed", "ECONNRESET", "ETIMEDOUT", ...extraPatterns];
|
|
156819
156860
|
return patterns.some((p) => error49.message.includes(p));
|
|
156820
156861
|
}
|
|
156862
|
+
function isTransientOctokitError(error49) {
|
|
156863
|
+
if (error49 !== null && typeof error49 === "object" && "status" in error49 && typeof error49.status === "number") {
|
|
156864
|
+
return error49.status >= 500;
|
|
156865
|
+
}
|
|
156866
|
+
return isTransientNetworkError(error49);
|
|
156867
|
+
}
|
|
156821
156868
|
|
|
156822
156869
|
// utils/patchWorkflowRunFields.ts
|
|
156823
156870
|
var STRING_KEYS = [
|
|
@@ -156911,6 +156958,195 @@ function aggregateUsage(entries) {
|
|
|
156911
156958
|
return out;
|
|
156912
156959
|
}
|
|
156913
156960
|
|
|
156961
|
+
// utils/payload.ts
|
|
156962
|
+
var core4 = __toESM(require_core(), 1);
|
|
156963
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
156964
|
+
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
156965
|
+
|
|
156966
|
+
// utils/versioning.ts
|
|
156967
|
+
var import_semver2 = __toESM(require_semver2(), 1);
|
|
156968
|
+
var COMPATIBILITY_POLICY = "non-breaking";
|
|
156969
|
+
function validateCompatibility(payloadVersion, actionVersion) {
|
|
156970
|
+
const payloadSemVer = import_semver2.default.parse(payloadVersion);
|
|
156971
|
+
if (!payloadSemVer)
|
|
156972
|
+
throw new Error(`Payload version ${payloadVersion} is not a valid semantic version.`);
|
|
156973
|
+
const major = payloadSemVer.major;
|
|
156974
|
+
const minor = payloadSemVer.minor;
|
|
156975
|
+
const patch = payloadSemVer.patch;
|
|
156976
|
+
const compatibilityRange = COMPATIBILITY_POLICY === "same-features" ? `^${major}.${minor}.${major === 0 ? patch : 0}` : `^${major}.${major === 0 ? minor : 0}.${major === 0 ? "x" : 0}`;
|
|
156977
|
+
if (!import_semver2.default.satisfies(actionVersion, compatibilityRange)) {
|
|
156978
|
+
throw new Error(
|
|
156979
|
+
`Payload version ${payloadVersion} is incompatible with action version ${actionVersion}. Please update your workflow to use at least ${import_semver2.default.minVersion(compatibilityRange)} version of the action.`
|
|
156980
|
+
);
|
|
156981
|
+
}
|
|
156982
|
+
}
|
|
156983
|
+
|
|
156984
|
+
// utils/payload.ts
|
|
156985
|
+
var ShellPermissionInput = type.enumerated("disabled", "restricted", "enabled");
|
|
156986
|
+
var PushPermissionInput = type.enumerated("disabled", "restricted", "enabled");
|
|
156987
|
+
var StatusChecksInput = type.enumerated("disabled", "enabled");
|
|
156988
|
+
var JsonPayload = type({
|
|
156989
|
+
"~pullfrog": "true",
|
|
156990
|
+
version: "string",
|
|
156991
|
+
"model?": "string | undefined",
|
|
156992
|
+
"modelExplicit?": "boolean | undefined",
|
|
156993
|
+
prompt: "string",
|
|
156994
|
+
"triggerer?": "string | undefined",
|
|
156995
|
+
"baseInstructions?": "string | undefined",
|
|
156996
|
+
"eventInstructions?": "string",
|
|
156997
|
+
"previousRunsNote?": "string",
|
|
156998
|
+
"event?": "object",
|
|
156999
|
+
"xrepo?": type({
|
|
157000
|
+
mode: "'all' | 'explicit'",
|
|
157001
|
+
read: "string[]",
|
|
157002
|
+
write: "string[]",
|
|
157003
|
+
// optional so a payload from an older server build (pre-`unavailable`)
|
|
157004
|
+
// still parses against a newer action across a rolling deploy.
|
|
157005
|
+
"unavailable?": "string[]"
|
|
157006
|
+
}).or("undefined"),
|
|
157007
|
+
"timeout?": "string | undefined",
|
|
157008
|
+
"progressComment?": type({
|
|
157009
|
+
id: "string",
|
|
157010
|
+
type: "'issue' | 'review'"
|
|
157011
|
+
}).or("undefined"),
|
|
157012
|
+
"generateSummary?": "boolean | undefined"
|
|
157013
|
+
});
|
|
157014
|
+
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
157015
|
+
function isCollaborator(event) {
|
|
157016
|
+
const perm = event.authorPermission;
|
|
157017
|
+
return perm !== void 0 && COLLABORATOR_PERMISSIONS.includes(perm);
|
|
157018
|
+
}
|
|
157019
|
+
var Inputs = type({
|
|
157020
|
+
"prompt?": type.string.or("undefined"),
|
|
157021
|
+
"prompt_file?": type.string.or("undefined"),
|
|
157022
|
+
"model?": type.string.or("undefined"),
|
|
157023
|
+
"timeout?": type.string.or("undefined"),
|
|
157024
|
+
"push?": PushPermissionInput.or("undefined"),
|
|
157025
|
+
"shell?": ShellPermissionInput.or("undefined"),
|
|
157026
|
+
"status_checks?": StatusChecksInput.or("undefined"),
|
|
157027
|
+
"cwd?": type.string.or("undefined"),
|
|
157028
|
+
"output_schema?": type.string.or("undefined")
|
|
157029
|
+
});
|
|
157030
|
+
function isPayloadEvent(value2) {
|
|
157031
|
+
return typeof value2 === "object" && value2 !== null && "trigger" in value2;
|
|
157032
|
+
}
|
|
157033
|
+
function resolveCwd(cwd) {
|
|
157034
|
+
const workspace = process.env.GITHUB_WORKSPACE;
|
|
157035
|
+
if (!cwd) return workspace;
|
|
157036
|
+
if (isAbsolute2(cwd)) return cwd;
|
|
157037
|
+
return workspace ? resolve2(workspace, cwd) : cwd;
|
|
157038
|
+
}
|
|
157039
|
+
function resolvePromptInput() {
|
|
157040
|
+
const promptInput = core4.getInput("prompt");
|
|
157041
|
+
const promptFile = core4.getInput("prompt_file");
|
|
157042
|
+
if (promptInput && promptFile) {
|
|
157043
|
+
throw new Error("set exactly one of 'prompt' or 'prompt_file' inputs, not both.");
|
|
157044
|
+
}
|
|
157045
|
+
if (promptFile) {
|
|
157046
|
+
return resolvePromptFile(promptFile);
|
|
157047
|
+
}
|
|
157048
|
+
if (!promptInput) {
|
|
157049
|
+
throw new Error("one of 'prompt' or 'prompt_file' inputs is required.");
|
|
157050
|
+
}
|
|
157051
|
+
let parsed2;
|
|
157052
|
+
try {
|
|
157053
|
+
parsed2 = JSON.parse(promptInput);
|
|
157054
|
+
} catch {
|
|
157055
|
+
return promptInput;
|
|
157056
|
+
}
|
|
157057
|
+
if (!parsed2 || typeof parsed2 !== "object" || !("~pullfrog" in parsed2)) {
|
|
157058
|
+
return promptInput;
|
|
157059
|
+
}
|
|
157060
|
+
const jsonPayload = JsonPayload.assert(parsed2);
|
|
157061
|
+
validateCompatibility(jsonPayload.version, package_default.version);
|
|
157062
|
+
return jsonPayload;
|
|
157063
|
+
}
|
|
157064
|
+
function resolvePromptFile(input) {
|
|
157065
|
+
const workspace = process.env.GITHUB_WORKSPACE;
|
|
157066
|
+
const path4 = isAbsolute2(input) ? input : workspace ? resolve2(workspace, input) : resolve2(input);
|
|
157067
|
+
const content = readFileSync3(path4, "utf-8");
|
|
157068
|
+
if (!content.trim()) {
|
|
157069
|
+
throw new Error(`prompt_file ${JSON.stringify(input)} is empty.`);
|
|
157070
|
+
}
|
|
157071
|
+
return content;
|
|
157072
|
+
}
|
|
157073
|
+
function resolveNonPromptInputs() {
|
|
157074
|
+
return Inputs.omit("prompt", "prompt_file").assert({
|
|
157075
|
+
model: core4.getInput("model") || void 0,
|
|
157076
|
+
timeout: core4.getInput("timeout") || void 0,
|
|
157077
|
+
cwd: core4.getInput("cwd") || void 0,
|
|
157078
|
+
push: core4.getInput("push") || void 0,
|
|
157079
|
+
shell: core4.getInput("shell") || void 0,
|
|
157080
|
+
status_checks: core4.getInput("status_checks") || void 0
|
|
157081
|
+
});
|
|
157082
|
+
}
|
|
157083
|
+
var isPullfrog = (actor) => {
|
|
157084
|
+
actor = actor?.replace("[bot]", "");
|
|
157085
|
+
return !!actor && (actor === "pullfrog" || actor === "pullfrogdev");
|
|
157086
|
+
};
|
|
157087
|
+
function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
157088
|
+
const [prompt, jsonPayload] = typeof resolvedPromptInput !== "string" ? [resolvedPromptInput.prompt, resolvedPromptInput] : [resolvedPromptInput, void 0];
|
|
157089
|
+
const inputs = resolveNonPromptInputs();
|
|
157090
|
+
const rawEvent = jsonPayload?.event;
|
|
157091
|
+
const event = isPayloadEvent(rawEvent) ? rawEvent : { trigger: "unknown" };
|
|
157092
|
+
const model = jsonPayload?.model ?? inputs.model ?? repoSettings.model ?? void 0;
|
|
157093
|
+
const isNonCollaborator = !isCollaborator(event);
|
|
157094
|
+
const repoShell = repoSettings.shell ?? "restricted";
|
|
157095
|
+
const inputShell = inputs.shell;
|
|
157096
|
+
let resolvedShell = repoShell;
|
|
157097
|
+
if (inputShell === "disabled") {
|
|
157098
|
+
resolvedShell = "disabled";
|
|
157099
|
+
} else if (inputShell === "restricted" && resolvedShell === "enabled") {
|
|
157100
|
+
resolvedShell = "restricted";
|
|
157101
|
+
}
|
|
157102
|
+
if (isNonCollaborator && resolvedShell === "enabled") {
|
|
157103
|
+
resolvedShell = "restricted";
|
|
157104
|
+
}
|
|
157105
|
+
return {
|
|
157106
|
+
"~pullfrog": true,
|
|
157107
|
+
version: jsonPayload?.version ?? package_default.version,
|
|
157108
|
+
model,
|
|
157109
|
+
// explicit only when the model came from a per-run override flag (carried on
|
|
157110
|
+
// the JSON payload). a GHA `model` input or the repo default is not explicit.
|
|
157111
|
+
modelExplicit: jsonPayload?.modelExplicit ?? false,
|
|
157112
|
+
prompt,
|
|
157113
|
+
triggerer: jsonPayload?.triggerer ?? // it's not a common use case but GITHUB_ACTOR can be a user when the workflow is manually triggered by a user through GitHub Actions UI
|
|
157114
|
+
(!isPullfrog(process.env.GITHUB_ACTOR) ? process.env.GITHUB_ACTOR : void 0),
|
|
157115
|
+
baseInstructions: jsonPayload?.baseInstructions,
|
|
157116
|
+
eventInstructions: jsonPayload?.eventInstructions,
|
|
157117
|
+
previousRunsNote: jsonPayload?.previousRunsNote,
|
|
157118
|
+
event,
|
|
157119
|
+
xrepo: jsonPayload?.xrepo,
|
|
157120
|
+
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
157121
|
+
cwd: resolveCwd(inputs.cwd),
|
|
157122
|
+
progressComment: jsonPayload?.progressComment,
|
|
157123
|
+
generateSummary: jsonPayload?.generateSummary,
|
|
157124
|
+
// permissions: inputs > repoSettings > fallbacks
|
|
157125
|
+
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
157126
|
+
shell: resolvedShell,
|
|
157127
|
+
// opt-in commit-status check-runs (branch protection). workflow-level
|
|
157128
|
+
// static input, off unless the repo's pullfrog.yml sets status_checks: enabled.
|
|
157129
|
+
statusChecks: inputs.status_checks === "enabled",
|
|
157130
|
+
// set by proxy logic in main.ts when routing through OpenRouter
|
|
157131
|
+
proxyModel: void 0
|
|
157132
|
+
};
|
|
157133
|
+
}
|
|
157134
|
+
function resolveOutputSchema() {
|
|
157135
|
+
const raw2 = core4.getInput("output_schema");
|
|
157136
|
+
if (!raw2) return void 0;
|
|
157137
|
+
let parsed2;
|
|
157138
|
+
try {
|
|
157139
|
+
parsed2 = JSON.parse(raw2);
|
|
157140
|
+
} catch {
|
|
157141
|
+
throw new Error(`invalid output_schema: not valid JSON`);
|
|
157142
|
+
}
|
|
157143
|
+
if (!parsed2 || typeof parsed2 !== "object" || Array.isArray(parsed2)) {
|
|
157144
|
+
throw new Error(`invalid output_schema: must be a JSON object`);
|
|
157145
|
+
}
|
|
157146
|
+
log.info("\xBB structured output schema provided \u2014 output will be required");
|
|
157147
|
+
return parsed2;
|
|
157148
|
+
}
|
|
157149
|
+
|
|
156914
157150
|
// mcp/comment.ts
|
|
156915
157151
|
function isNotFoundError(error49) {
|
|
156916
157152
|
return error49 instanceof Error && error49.message.includes("Not Found");
|
|
@@ -157332,6 +157568,81 @@ async function buildCommentableMap(ctx, pullNumber) {
|
|
|
157332
157568
|
}
|
|
157333
157569
|
return map2;
|
|
157334
157570
|
}
|
|
157571
|
+
var OUTSTANDING_THREADS_QUERY = `
|
|
157572
|
+
query ($owner: String!, $name: String!, $prNumber: Int!, $cursor: String) {
|
|
157573
|
+
repository(owner: $owner, name: $name) {
|
|
157574
|
+
pullRequest(number: $prNumber) {
|
|
157575
|
+
reviewThreads(first: 100, after: $cursor) {
|
|
157576
|
+
pageInfo { hasNextPage endCursor }
|
|
157577
|
+
nodes {
|
|
157578
|
+
isResolved
|
|
157579
|
+
comments(first: 1) { nodes { author { login } } }
|
|
157580
|
+
}
|
|
157581
|
+
}
|
|
157582
|
+
}
|
|
157583
|
+
}
|
|
157584
|
+
}
|
|
157585
|
+
`;
|
|
157586
|
+
async function countOutstandingPullfrogThreads(ctx, pullNumber) {
|
|
157587
|
+
let count = 0;
|
|
157588
|
+
let cursor = null;
|
|
157589
|
+
for (let page = 0; page < 50; page += 1) {
|
|
157590
|
+
const response = await ctx.octokit.graphql(
|
|
157591
|
+
OUTSTANDING_THREADS_QUERY,
|
|
157592
|
+
{ owner: ctx.repo.owner, name: ctx.repo.name, prNumber: pullNumber, cursor }
|
|
157593
|
+
);
|
|
157594
|
+
const conn = response.repository?.pullRequest?.reviewThreads;
|
|
157595
|
+
for (const thread of conn?.nodes ?? []) {
|
|
157596
|
+
if (!thread || thread.isResolved) continue;
|
|
157597
|
+
const root = thread.comments?.nodes?.find((c) => c != null);
|
|
157598
|
+
if (root && isPullfrog(root.author?.login)) count += 1;
|
|
157599
|
+
}
|
|
157600
|
+
if (!conn?.pageInfo.hasNextPage) break;
|
|
157601
|
+
cursor = conn.pageInfo.endCursor;
|
|
157602
|
+
}
|
|
157603
|
+
return count;
|
|
157604
|
+
}
|
|
157605
|
+
async function approveAfterFix(ctx) {
|
|
157606
|
+
if (ctx.payload.event.trigger !== "fix_review") return;
|
|
157607
|
+
if (!ctx.prApproveEnabled) return;
|
|
157608
|
+
if (ctx.toolState.approval) return;
|
|
157609
|
+
const pullNumber = ctx.payload.event.issue_number;
|
|
157610
|
+
if (typeof pullNumber !== "number") return;
|
|
157611
|
+
const outstanding = await countOutstandingPullfrogThreads(ctx, pullNumber);
|
|
157612
|
+
if (outstanding > 0) {
|
|
157613
|
+
log.info(
|
|
157614
|
+
`skipping fix auto-approval: ${outstanding} unresolved Pullfrog review thread(s) still open on #${pullNumber}`
|
|
157615
|
+
);
|
|
157616
|
+
return;
|
|
157617
|
+
}
|
|
157618
|
+
const pr = await ctx.octokit.rest.pulls.get({
|
|
157619
|
+
owner: ctx.repo.owner,
|
|
157620
|
+
repo: ctx.repo.name,
|
|
157621
|
+
pull_number: pullNumber
|
|
157622
|
+
});
|
|
157623
|
+
if (pr.data.state !== "open") return;
|
|
157624
|
+
const headSha = pr.data.head.sha;
|
|
157625
|
+
const selfAuthored = isPullfrog(pr.data.user?.login);
|
|
157626
|
+
const summary2 = ctx.toolState.lastProgressBody?.trim();
|
|
157627
|
+
const body = "> \u2705 Pullfrog addressed all of its review feedback on this PR.\n\n" + (summary2 || "all Pullfrog-raised review threads are resolved \u2014 no outstanding findings remain.");
|
|
157628
|
+
const params = {
|
|
157629
|
+
owner: ctx.repo.owner,
|
|
157630
|
+
repo: ctx.repo.name,
|
|
157631
|
+
pull_number: pullNumber,
|
|
157632
|
+
event: selfAuthored ? "COMMENT" : "APPROVE",
|
|
157633
|
+
commit_id: headSha
|
|
157634
|
+
};
|
|
157635
|
+
const result = await createAndSubmitWithFooter(ctx, params, {
|
|
157636
|
+
body,
|
|
157637
|
+
approved: true,
|
|
157638
|
+
hasComments: false
|
|
157639
|
+
});
|
|
157640
|
+
ctx.toolState.approval = { wouldApprove: true, sha: headSha };
|
|
157641
|
+
log.info(`\xBB auto-approved #${pullNumber} after fix run (review ${result.data.id})`);
|
|
157642
|
+
await deleteProgressComment(ctx).catch((err) => {
|
|
157643
|
+
log.debug(`progress comment cleanup after fix auto-approval failed: ${err}`);
|
|
157644
|
+
});
|
|
157645
|
+
}
|
|
157335
157646
|
function validateInlineComments(comments, map2) {
|
|
157336
157647
|
const valid = [];
|
|
157337
157648
|
const dropped = [];
|
|
@@ -157422,7 +157733,7 @@ var CreatePullRequestReview = type({
|
|
|
157422
157733
|
"1-2 sentence high-level summary with urgency level, critical callouts, and feedback about code outside the diff. Specific feedback on diff lines goes in 'comments' array."
|
|
157423
157734
|
).optional(),
|
|
157424
157735
|
approved: type.boolean.describe(
|
|
157425
|
-
"Set to true to submit as an approval. Use for `> \u2705 No new issues found.` reviews where the PR is mergeable as-is and nothing in the body warrants code changes \u2014 approving also suppresses the Fix-button footer affordance so users don't dispatch a fix run on non-actionable feedback. Reserve approved: false for `> \u2139\uFE0F ...` (minor suggestions inline), `> [!IMPORTANT]` (recommended changes), and `> [!CAUTION]` (critical) reviews. Defaults to false (comment-only review). Mutually exclusive with request_changes."
|
|
157736
|
+
"Set to true to submit as an approval. Use for `> \u2705 No new issues found.` reviews where the PR is mergeable as-is and nothing in the body warrants code changes \u2014 approving also suppresses the Fix-button footer affordance so users don't dispatch a fix run on non-actionable feedback. Reserve approved: false for `> \u2139\uFE0F ...` (minor suggestions inline), `> [!IMPORTANT]` (recommended changes), and `> [!CAUTION]` (critical) reviews. Defaults to false (comment-only review). Mutually exclusive with request_changes. Approval is REJECTED while any unresolved Pullfrog review thread remains open on the PR (not just the latest commit's diff): resolve the threads the current code addresses (reply + resolve_review_thread) first, or submit a non-approving review if a real issue remains."
|
|
157426
157737
|
).optional(),
|
|
157427
157738
|
request_changes: type.boolean.describe(
|
|
157428
157739
|
"Set to true to submit a blocking REQUEST_CHANGES review \u2014 the PR cannot merge until the requested changes are made and the review is dismissed or re-reviewed. Reserve for changes you consider required, not optional suggestions. Mutually exclusive with approved; a contentless request (no body and no comments) is skipped."
|
|
@@ -157480,21 +157791,49 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
157480
157791
|
reviewId: dup.reviewId
|
|
157481
157792
|
};
|
|
157482
157793
|
}
|
|
157794
|
+
if (approved) {
|
|
157795
|
+
const outstanding = await countOutstandingPullfrogThreads(ctx, pull_number);
|
|
157796
|
+
if (outstanding > 0) {
|
|
157797
|
+
const listRef = formatMcpToolRef(ctx.agentId, "get_review_comments");
|
|
157798
|
+
const resolveRef2 = formatMcpToolRef(ctx.agentId, "resolve_review_thread");
|
|
157799
|
+
throw new Error(
|
|
157800
|
+
`cannot approve: ${outstanding} unresolved Pullfrog review thread(s) still open on this PR. approval requires every prior Pullfrog finding to be resolved, not just the latest commits to be clean. inspect them with \`${listRef}\`; for each thread the current code genuinely addresses, reply then call \`${resolveRef2}\`, and retry this approval. if any thread is a real outstanding issue, do NOT approve \u2014 submit a non-approving review (omit \`approved\`) that covers it instead.`
|
|
157801
|
+
);
|
|
157802
|
+
}
|
|
157803
|
+
}
|
|
157804
|
+
const prSnapshot = (await ctx.octokit.rest.pulls.get({
|
|
157805
|
+
owner: ctx.repo.owner,
|
|
157806
|
+
repo: ctx.repo.name,
|
|
157807
|
+
pull_number
|
|
157808
|
+
})).data;
|
|
157809
|
+
const selfAuthored = isPullfrog(prSnapshot.user?.login);
|
|
157810
|
+
ctx.toolState.approval = { wouldApprove: approved === true, sha: primary.checkoutSha };
|
|
157483
157811
|
const skip = reviewSkipDecision({
|
|
157484
157812
|
approved: approved ?? false,
|
|
157485
157813
|
requestChanges: request_changes ?? false,
|
|
157486
157814
|
body,
|
|
157487
157815
|
hasComments: comments.length > 0,
|
|
157488
|
-
|
|
157816
|
+
// a self-authored approve downgrades to COMMENT (GitHub blocks a
|
|
157817
|
+
// self-APPROVE), so treat it as non-binding here — an empty self-
|
|
157818
|
+
// approve is then skipped (the verdict is still recorded above)
|
|
157819
|
+
// instead of POSTing an empty COMMENT that GitHub 422s.
|
|
157820
|
+
prApproveEnabled: ctx.prApproveEnabled && !selfAuthored
|
|
157489
157821
|
});
|
|
157490
157822
|
if (skip) {
|
|
157491
157823
|
log.info(`skipping review submission: ${skip.reason}`);
|
|
157492
157824
|
return { success: true, skipped: true, reason: skip.reason };
|
|
157493
157825
|
}
|
|
157494
157826
|
let event = approved ? "APPROVE" : request_changes ? "REQUEST_CHANGES" : "COMMENT";
|
|
157495
|
-
if (
|
|
157496
|
-
|
|
157497
|
-
|
|
157827
|
+
if (event === "APPROVE" || event === "REQUEST_CHANGES") {
|
|
157828
|
+
if (!ctx.prApproveEnabled) {
|
|
157829
|
+
log.info(`prApproveEnabled is disabled \u2014 downgrading ${event} to COMMENT`);
|
|
157830
|
+
event = "COMMENT";
|
|
157831
|
+
} else if (selfAuthored) {
|
|
157832
|
+
log.info(
|
|
157833
|
+
`self-authored PR \u2014 downgrading binding ${event} to COMMENT (verdict recorded internally)`
|
|
157834
|
+
);
|
|
157835
|
+
event = "COMMENT";
|
|
157836
|
+
}
|
|
157498
157837
|
}
|
|
157499
157838
|
const params = {
|
|
157500
157839
|
owner: ctx.repo.owner,
|
|
@@ -157506,12 +157845,7 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
157506
157845
|
if (commit_id) {
|
|
157507
157846
|
params.commit_id = commit_id;
|
|
157508
157847
|
} else {
|
|
157509
|
-
|
|
157510
|
-
owner: ctx.repo.owner,
|
|
157511
|
-
repo: ctx.repo.name,
|
|
157512
|
-
pull_number
|
|
157513
|
-
});
|
|
157514
|
-
latestHeadSha = pr.data.head.sha;
|
|
157848
|
+
latestHeadSha = prSnapshot.head.sha;
|
|
157515
157849
|
params.commit_id = primary.checkoutSha ?? latestHeadSha;
|
|
157516
157850
|
if (primary.checkoutSha && latestHeadSha !== primary.checkoutSha) {
|
|
157517
157851
|
log.info(
|
|
@@ -157579,6 +157913,7 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
157579
157913
|
}
|
|
157580
157914
|
)();
|
|
157581
157915
|
} catch (err) {
|
|
157916
|
+
if (ctx.toolState.approval) ctx.toolState.approval.wouldApprove = false;
|
|
157582
157917
|
if (isTransientReviewError(err)) {
|
|
157583
157918
|
const rawMsg2 = err instanceof Error ? err.message : String(err);
|
|
157584
157919
|
throw new Error(
|
|
@@ -157613,6 +157948,7 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
157613
157948
|
nodeId: reviewNodeId,
|
|
157614
157949
|
reviewedSha: actuallyReviewedSha
|
|
157615
157950
|
};
|
|
157951
|
+
if (ctx.toolState.approval) ctx.toolState.approval.sha = actuallyReviewedSha;
|
|
157616
157952
|
ctx.toolState.wasUpdated = true;
|
|
157617
157953
|
await deleteProgressComment(ctx).catch((err) => {
|
|
157618
157954
|
log.debug(`progress comment cleanup after review failed: ${err}`);
|
|
@@ -159034,7 +159370,7 @@ function isMetadataYarnClassic(metadataPath) {
|
|
|
159034
159370
|
}
|
|
159035
159371
|
|
|
159036
159372
|
// utils/packageManager.ts
|
|
159037
|
-
var
|
|
159373
|
+
var import_semver3 = __toESM(require_semver2(), 1);
|
|
159038
159374
|
import { existsSync as existsSync5 } from "node:fs";
|
|
159039
159375
|
import { mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
159040
159376
|
import { delimiter, join as join15 } from "node:path";
|
|
@@ -159056,7 +159392,7 @@ function parsePackageManagerField(value2) {
|
|
|
159056
159392
|
return {
|
|
159057
159393
|
name,
|
|
159058
159394
|
version: version3,
|
|
159059
|
-
concrete:
|
|
159395
|
+
concrete: import_semver3.default.valid(version3) !== null,
|
|
159060
159396
|
source: "packageManager"
|
|
159061
159397
|
};
|
|
159062
159398
|
}
|
|
@@ -159070,7 +159406,7 @@ function parseDevEnginesField(field) {
|
|
|
159070
159406
|
return {
|
|
159071
159407
|
name: field.name,
|
|
159072
159408
|
version: version3,
|
|
159073
|
-
concrete:
|
|
159409
|
+
concrete: import_semver3.default.valid(version3) !== null,
|
|
159074
159410
|
source: "devEngines"
|
|
159075
159411
|
};
|
|
159076
159412
|
}
|
|
@@ -159104,7 +159440,7 @@ async function resolvePackageManagerSpec(cwd) {
|
|
|
159104
159440
|
}
|
|
159105
159441
|
return devSpec;
|
|
159106
159442
|
}
|
|
159107
|
-
if (pmSpec.concrete &&
|
|
159443
|
+
if (pmSpec.concrete && import_semver3.default.satisfies(pmSpec.version, devSpec.version)) {
|
|
159108
159444
|
return pmSpec;
|
|
159109
159445
|
}
|
|
159110
159446
|
if (pmSpec.concrete) {
|
|
@@ -159316,8 +159652,15 @@ ${errorMessage}`]
|
|
|
159316
159652
|
};
|
|
159317
159653
|
|
|
159318
159654
|
// prep/installPythonDependencies.ts
|
|
159319
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
159655
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
|
|
159320
159656
|
import { join as join17 } from "node:path";
|
|
159657
|
+
function declaresBuildSystem(path4) {
|
|
159658
|
+
return /^\s*\[\s*build-system\s*\]/m.test(readFileSync4(path4, "utf8"));
|
|
159659
|
+
}
|
|
159660
|
+
function configApplies(config3, cwd) {
|
|
159661
|
+
const path4 = join17(cwd, config3.file);
|
|
159662
|
+
return existsSync7(path4) && (config3.applies?.(path4) ?? true);
|
|
159663
|
+
}
|
|
159321
159664
|
var PYTHON_CONFIGS = [
|
|
159322
159665
|
{
|
|
159323
159666
|
file: "requirements.txt",
|
|
@@ -159327,7 +159670,8 @@ var PYTHON_CONFIGS = [
|
|
|
159327
159670
|
{
|
|
159328
159671
|
file: "pyproject.toml",
|
|
159329
159672
|
tool: "pip",
|
|
159330
|
-
installCmd: ["pip", "install", "."]
|
|
159673
|
+
installCmd: ["pip", "install", "."],
|
|
159674
|
+
applies: declaresBuildSystem
|
|
159331
159675
|
},
|
|
159332
159676
|
{
|
|
159333
159677
|
file: "Pipfile",
|
|
@@ -159389,11 +159733,11 @@ var installPythonDependencies = {
|
|
|
159389
159733
|
return false;
|
|
159390
159734
|
}
|
|
159391
159735
|
const cwd = process.cwd();
|
|
159392
|
-
return PYTHON_CONFIGS.some((config3) =>
|
|
159736
|
+
return PYTHON_CONFIGS.some((config3) => configApplies(config3, cwd));
|
|
159393
159737
|
},
|
|
159394
159738
|
run: async (options) => {
|
|
159395
159739
|
const cwd = process.cwd();
|
|
159396
|
-
const config3 = PYTHON_CONFIGS.find((c) =>
|
|
159740
|
+
const config3 = PYTHON_CONFIGS.find((c) => configApplies(c, cwd));
|
|
159397
159741
|
if (!config3) {
|
|
159398
159742
|
return {
|
|
159399
159743
|
language: "python",
|
|
@@ -161844,12 +162188,17 @@ function resolveModel(ctx) {
|
|
|
161844
162188
|
if (envModel) {
|
|
161845
162189
|
return resolveSlug(envModel) ?? envModel;
|
|
161846
162190
|
}
|
|
161847
|
-
|
|
161848
|
-
|
|
162191
|
+
const slug2 = ctx.slug?.trim();
|
|
162192
|
+
if (slug2) {
|
|
162193
|
+
const resolved = resolveSlug(slug2);
|
|
161849
162194
|
if (resolved) {
|
|
161850
162195
|
return resolved;
|
|
161851
162196
|
}
|
|
161852
|
-
|
|
162197
|
+
if (slug2.includes("/")) {
|
|
162198
|
+
log.info(`\xBB "${slug2}" is not a curated alias \u2014 passing through as a raw model specifier`);
|
|
162199
|
+
return slug2;
|
|
162200
|
+
}
|
|
162201
|
+
log.warning(`\xBB unknown model slug "${slug2}" \u2014 agent will auto-select`);
|
|
161853
162202
|
}
|
|
161854
162203
|
return void 0;
|
|
161855
162204
|
}
|
|
@@ -162412,6 +162761,8 @@ Never use \`sleep\` to wait for commands to complete. Commands run synchronously
|
|
|
162412
162761
|
|
|
162413
162762
|
When posting comments via ${pullfrogMcpName}, write as a professional team member would. Your final comments should be polished and actionable \u2014 do not include intermediate reasoning like "I'll now look at the code" or "Let me respond to the question."
|
|
162414
162763
|
|
|
162764
|
+
Never \`@\`-mention a GitHub username unless that exact handle appears in the user's request or the event context. GitHub already notifies the author and thread participants, so write "the author" or omit it.
|
|
162765
|
+
|
|
162415
162766
|
When embedding images (e.g. uploaded screenshots) in comments or PR bodies, always use markdown image syntax: \`\`. Never paste a naked URL \u2014 it will not render as an image.
|
|
162416
162767
|
|
|
162417
162768
|
### Progress reporting
|
|
@@ -162721,7 +163072,7 @@ function buildModelAccessError(input) {
|
|
|
162721
163072
|
}
|
|
162722
163073
|
|
|
162723
163074
|
// utils/normalizeEnv.ts
|
|
162724
|
-
var
|
|
163075
|
+
var core5 = __toESM(require_core(), 1);
|
|
162725
163076
|
function sanitizeSecret(key, value2) {
|
|
162726
163077
|
const trimmed = value2.trim();
|
|
162727
163078
|
if (trimmed.length === 0) {
|
|
@@ -162735,7 +163086,7 @@ function sanitizeSecret(key, value2) {
|
|
|
162735
163086
|
`\xBB stripped whitespace from ${key} (whitespace in secret values breaks GitHub Actions log masking)`
|
|
162736
163087
|
);
|
|
162737
163088
|
}
|
|
162738
|
-
|
|
163089
|
+
core5.setSecret(trimmed);
|
|
162739
163090
|
return trimmed;
|
|
162740
163091
|
}
|
|
162741
163092
|
function normalizeEnv() {
|
|
@@ -162779,7 +163130,7 @@ function normalizeEnv() {
|
|
|
162779
163130
|
}
|
|
162780
163131
|
|
|
162781
163132
|
// utils/overrides.ts
|
|
162782
|
-
var
|
|
163133
|
+
var core6 = __toESM(require_core(), 1);
|
|
162783
163134
|
var DENIED_OVERRIDE_NAMES = /* @__PURE__ */ new Set([
|
|
162784
163135
|
"GITHUB_TOKEN",
|
|
162785
163136
|
"GH_TOKEN",
|
|
@@ -162825,7 +163176,7 @@ function applyOverrides(params) {
|
|
|
162825
163176
|
denied.push(key);
|
|
162826
163177
|
continue;
|
|
162827
163178
|
}
|
|
162828
|
-
if (value2.length > 0)
|
|
163179
|
+
if (value2.length > 0) core6.setSecret(value2);
|
|
162829
163180
|
params.env[key] = value2;
|
|
162830
163181
|
applied.push(key);
|
|
162831
163182
|
}
|
|
@@ -162833,168 +163184,6 @@ function applyOverrides(params) {
|
|
|
162833
163184
|
return { applied, denied };
|
|
162834
163185
|
}
|
|
162835
163186
|
|
|
162836
|
-
// utils/payload.ts
|
|
162837
|
-
var core6 = __toESM(require_core(), 1);
|
|
162838
|
-
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
162839
|
-
|
|
162840
|
-
// utils/versioning.ts
|
|
162841
|
-
var import_semver3 = __toESM(require_semver2(), 1);
|
|
162842
|
-
var COMPATIBILITY_POLICY = "non-breaking";
|
|
162843
|
-
function validateCompatibility(payloadVersion, actionVersion) {
|
|
162844
|
-
const payloadSemVer = import_semver3.default.parse(payloadVersion);
|
|
162845
|
-
if (!payloadSemVer)
|
|
162846
|
-
throw new Error(`Payload version ${payloadVersion} is not a valid semantic version.`);
|
|
162847
|
-
const major = payloadSemVer.major;
|
|
162848
|
-
const minor = payloadSemVer.minor;
|
|
162849
|
-
const patch = payloadSemVer.patch;
|
|
162850
|
-
const compatibilityRange = COMPATIBILITY_POLICY === "same-features" ? `^${major}.${minor}.${major === 0 ? patch : 0}` : `^${major}.${major === 0 ? minor : 0}.${major === 0 ? "x" : 0}`;
|
|
162851
|
-
if (!import_semver3.default.satisfies(actionVersion, compatibilityRange)) {
|
|
162852
|
-
throw new Error(
|
|
162853
|
-
`Payload version ${payloadVersion} is incompatible with action version ${actionVersion}. Please update your workflow to use at least ${import_semver3.default.minVersion(compatibilityRange)} version of the action.`
|
|
162854
|
-
);
|
|
162855
|
-
}
|
|
162856
|
-
}
|
|
162857
|
-
|
|
162858
|
-
// utils/payload.ts
|
|
162859
|
-
var ShellPermissionInput = type.enumerated("disabled", "restricted", "enabled");
|
|
162860
|
-
var PushPermissionInput = type.enumerated("disabled", "restricted", "enabled");
|
|
162861
|
-
var JsonPayload = type({
|
|
162862
|
-
"~pullfrog": "true",
|
|
162863
|
-
version: "string",
|
|
162864
|
-
"model?": "string | undefined",
|
|
162865
|
-
"modelExplicit?": "boolean | undefined",
|
|
162866
|
-
prompt: "string",
|
|
162867
|
-
"triggerer?": "string | undefined",
|
|
162868
|
-
"baseInstructions?": "string | undefined",
|
|
162869
|
-
"eventInstructions?": "string",
|
|
162870
|
-
"previousRunsNote?": "string",
|
|
162871
|
-
"event?": "object",
|
|
162872
|
-
"xrepo?": type({
|
|
162873
|
-
mode: "'all' | 'explicit'",
|
|
162874
|
-
read: "string[]",
|
|
162875
|
-
write: "string[]",
|
|
162876
|
-
// optional so a payload from an older server build (pre-`unavailable`)
|
|
162877
|
-
// still parses against a newer action across a rolling deploy.
|
|
162878
|
-
"unavailable?": "string[]"
|
|
162879
|
-
}).or("undefined"),
|
|
162880
|
-
"timeout?": "string | undefined",
|
|
162881
|
-
"progressComment?": type({
|
|
162882
|
-
id: "string",
|
|
162883
|
-
type: "'issue' | 'review'"
|
|
162884
|
-
}).or("undefined"),
|
|
162885
|
-
"generateSummary?": "boolean | undefined"
|
|
162886
|
-
});
|
|
162887
|
-
var COLLABORATOR_PERMISSIONS = ["admin", "maintain", "write"];
|
|
162888
|
-
function isCollaborator(event) {
|
|
162889
|
-
const perm = event.authorPermission;
|
|
162890
|
-
return perm !== void 0 && COLLABORATOR_PERMISSIONS.includes(perm);
|
|
162891
|
-
}
|
|
162892
|
-
var Inputs = type({
|
|
162893
|
-
prompt: "string",
|
|
162894
|
-
"model?": type.string.or("undefined"),
|
|
162895
|
-
"timeout?": type.string.or("undefined"),
|
|
162896
|
-
"push?": PushPermissionInput.or("undefined"),
|
|
162897
|
-
"shell?": ShellPermissionInput.or("undefined"),
|
|
162898
|
-
"cwd?": type.string.or("undefined"),
|
|
162899
|
-
"output_schema?": type.string.or("undefined")
|
|
162900
|
-
});
|
|
162901
|
-
function isPayloadEvent(value2) {
|
|
162902
|
-
return typeof value2 === "object" && value2 !== null && "trigger" in value2;
|
|
162903
|
-
}
|
|
162904
|
-
function resolveCwd(cwd) {
|
|
162905
|
-
const workspace = process.env.GITHUB_WORKSPACE;
|
|
162906
|
-
if (!cwd) return workspace;
|
|
162907
|
-
if (isAbsolute2(cwd)) return cwd;
|
|
162908
|
-
return workspace ? resolve2(workspace, cwd) : cwd;
|
|
162909
|
-
}
|
|
162910
|
-
function resolvePromptInput() {
|
|
162911
|
-
const prompt = core6.getInput("prompt", { required: true });
|
|
162912
|
-
let parsed2;
|
|
162913
|
-
try {
|
|
162914
|
-
parsed2 = JSON.parse(prompt);
|
|
162915
|
-
} catch {
|
|
162916
|
-
return prompt;
|
|
162917
|
-
}
|
|
162918
|
-
if (!parsed2 || typeof parsed2 !== "object" || !("~pullfrog" in parsed2)) {
|
|
162919
|
-
return prompt;
|
|
162920
|
-
}
|
|
162921
|
-
const jsonPayload = JsonPayload.assert(parsed2);
|
|
162922
|
-
validateCompatibility(jsonPayload.version, package_default.version);
|
|
162923
|
-
return jsonPayload;
|
|
162924
|
-
}
|
|
162925
|
-
function resolveNonPromptInputs() {
|
|
162926
|
-
return Inputs.omit("prompt").assert({
|
|
162927
|
-
model: core6.getInput("model") || void 0,
|
|
162928
|
-
timeout: core6.getInput("timeout") || void 0,
|
|
162929
|
-
cwd: core6.getInput("cwd") || void 0,
|
|
162930
|
-
push: core6.getInput("push") || void 0,
|
|
162931
|
-
shell: core6.getInput("shell") || void 0
|
|
162932
|
-
});
|
|
162933
|
-
}
|
|
162934
|
-
var isPullfrog = (actor) => {
|
|
162935
|
-
actor = actor?.replace("[bot]", "");
|
|
162936
|
-
return !!actor && (actor === "pullfrog" || actor === "pullfrogdev");
|
|
162937
|
-
};
|
|
162938
|
-
function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
162939
|
-
const [prompt, jsonPayload] = typeof resolvedPromptInput !== "string" ? [resolvedPromptInput.prompt, resolvedPromptInput] : [resolvedPromptInput, void 0];
|
|
162940
|
-
const inputs = resolveNonPromptInputs();
|
|
162941
|
-
const rawEvent = jsonPayload?.event;
|
|
162942
|
-
const event = isPayloadEvent(rawEvent) ? rawEvent : { trigger: "unknown" };
|
|
162943
|
-
const model = jsonPayload?.model ?? inputs.model ?? repoSettings.model ?? void 0;
|
|
162944
|
-
const isNonCollaborator = !isCollaborator(event);
|
|
162945
|
-
const repoShell = repoSettings.shell ?? "restricted";
|
|
162946
|
-
const inputShell = inputs.shell;
|
|
162947
|
-
let resolvedShell = repoShell;
|
|
162948
|
-
if (inputShell === "disabled") {
|
|
162949
|
-
resolvedShell = "disabled";
|
|
162950
|
-
} else if (inputShell === "restricted" && resolvedShell === "enabled") {
|
|
162951
|
-
resolvedShell = "restricted";
|
|
162952
|
-
}
|
|
162953
|
-
if (isNonCollaborator && resolvedShell === "enabled") {
|
|
162954
|
-
resolvedShell = "restricted";
|
|
162955
|
-
}
|
|
162956
|
-
return {
|
|
162957
|
-
"~pullfrog": true,
|
|
162958
|
-
version: jsonPayload?.version ?? package_default.version,
|
|
162959
|
-
model,
|
|
162960
|
-
// explicit only when the model came from a per-run override flag (carried on
|
|
162961
|
-
// the JSON payload). a GHA `model` input or the repo default is not explicit.
|
|
162962
|
-
modelExplicit: jsonPayload?.modelExplicit ?? false,
|
|
162963
|
-
prompt,
|
|
162964
|
-
triggerer: jsonPayload?.triggerer ?? // it's not a common use case but GITHUB_ACTOR can be a user when the workflow is manually triggered by a user through GitHub Actions UI
|
|
162965
|
-
(!isPullfrog(process.env.GITHUB_ACTOR) ? process.env.GITHUB_ACTOR : void 0),
|
|
162966
|
-
baseInstructions: jsonPayload?.baseInstructions,
|
|
162967
|
-
eventInstructions: jsonPayload?.eventInstructions,
|
|
162968
|
-
previousRunsNote: jsonPayload?.previousRunsNote,
|
|
162969
|
-
event,
|
|
162970
|
-
xrepo: jsonPayload?.xrepo,
|
|
162971
|
-
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
162972
|
-
cwd: resolveCwd(inputs.cwd),
|
|
162973
|
-
progressComment: jsonPayload?.progressComment,
|
|
162974
|
-
generateSummary: jsonPayload?.generateSummary,
|
|
162975
|
-
// permissions: inputs > repoSettings > fallbacks
|
|
162976
|
-
push: inputs.push ?? repoSettings.push ?? "restricted",
|
|
162977
|
-
shell: resolvedShell,
|
|
162978
|
-
// set by proxy logic in main.ts when routing through OpenRouter
|
|
162979
|
-
proxyModel: void 0
|
|
162980
|
-
};
|
|
162981
|
-
}
|
|
162982
|
-
function resolveOutputSchema() {
|
|
162983
|
-
const raw2 = core6.getInput("output_schema");
|
|
162984
|
-
if (!raw2) return void 0;
|
|
162985
|
-
let parsed2;
|
|
162986
|
-
try {
|
|
162987
|
-
parsed2 = JSON.parse(raw2);
|
|
162988
|
-
} catch {
|
|
162989
|
-
throw new Error(`invalid output_schema: not valid JSON`);
|
|
162990
|
-
}
|
|
162991
|
-
if (!parsed2 || typeof parsed2 !== "object" || Array.isArray(parsed2)) {
|
|
162992
|
-
throw new Error(`invalid output_schema: must be a JSON object`);
|
|
162993
|
-
}
|
|
162994
|
-
log.info("\xBB structured output schema provided \u2014 output will be required");
|
|
162995
|
-
return parsed2;
|
|
162996
|
-
}
|
|
162997
|
-
|
|
162998
163187
|
// utils/proxy.ts
|
|
162999
163188
|
var core8 = __toESM(require_core(), 1);
|
|
163000
163189
|
|
|
@@ -163145,7 +163334,10 @@ async function resolveTokens(params) {
|
|
|
163145
163334
|
contents: "write",
|
|
163146
163335
|
pull_requests: "write",
|
|
163147
163336
|
issues: "write",
|
|
163148
|
-
|
|
163337
|
+
// write (not read) so the run can post `pullfrog` / `pullfrog-approval`
|
|
163338
|
+
// commit-status check-runs for branch protection. the app already grants
|
|
163339
|
+
// checks:write; this scopes the MCP token up to use it.
|
|
163340
|
+
checks: "write",
|
|
163149
163341
|
actions: "read"
|
|
163150
163342
|
};
|
|
163151
163343
|
const mcpToken = await acquireNewToken({ repos: writeRepos, permissions: mcpPermissions });
|
|
@@ -163254,7 +163446,9 @@ async function resolveTokens(params) {
|
|
|
163254
163446
|
};
|
|
163255
163447
|
const removeSignalHandler = onExitSignal(dispose);
|
|
163256
163448
|
return {
|
|
163257
|
-
gitToken
|
|
163449
|
+
get gitToken() {
|
|
163450
|
+
return currentGitToken;
|
|
163451
|
+
},
|
|
163258
163452
|
mcpToken,
|
|
163259
163453
|
readToken,
|
|
163260
163454
|
refreshGitToken,
|
|
@@ -163607,6 +163801,7 @@ var defaultSettings = {
|
|
|
163607
163801
|
push: "restricted",
|
|
163608
163802
|
shell: "restricted",
|
|
163609
163803
|
prApproveEnabled: false,
|
|
163804
|
+
autoMergeEnabled: false,
|
|
163610
163805
|
signedCommits: false,
|
|
163611
163806
|
modeInstructions: {},
|
|
163612
163807
|
learnings: null,
|
|
@@ -163694,7 +163889,11 @@ async function resolveRunContextData(params) {
|
|
|
163694
163889
|
} catch {
|
|
163695
163890
|
}
|
|
163696
163891
|
const [repoResponse, runContext] = await Promise.all([
|
|
163697
|
-
params.octokit.repos.get({ owner: repoContext.owner, repo: repoContext.name }),
|
|
163892
|
+
op(() => params.octokit.repos.get({ owner: repoContext.owner, repo: repoContext.name }), {
|
|
163893
|
+
name: "repos.get",
|
|
163894
|
+
retries: [100, 500],
|
|
163895
|
+
bail: (error49) => !isTransientOctokitError(error49)
|
|
163896
|
+
})(),
|
|
163698
163897
|
fetchRunContext({ token: params.token, repoContext, oidcToken })
|
|
163699
163898
|
]);
|
|
163700
163899
|
return {
|
|
@@ -163923,6 +164122,108 @@ ${genericBody}`,
|
|
|
163923
164122
|
// utils/runLifecycle.ts
|
|
163924
164123
|
var core10 = __toESM(require_core(), 1);
|
|
163925
164124
|
|
|
164125
|
+
// utils/checksGate.ts
|
|
164126
|
+
var OK_CONCLUSIONS = /* @__PURE__ */ new Set(["success", "neutral", "skipped"]);
|
|
164127
|
+
var PULLFROG_CHECKS = /* @__PURE__ */ new Set(["pullfrog", "pullfrog-approval"]);
|
|
164128
|
+
function checkRunsGate(params) {
|
|
164129
|
+
for (const run of params.checkRuns) {
|
|
164130
|
+
if (PULLFROG_CHECKS.has(run.name.toLowerCase())) continue;
|
|
164131
|
+
if (run.status !== "completed")
|
|
164132
|
+
return { ok: false, reason: `check "${run.name}" ${run.status}` };
|
|
164133
|
+
if (!OK_CONCLUSIONS.has(run.conclusion ?? "")) {
|
|
164134
|
+
return { ok: false, reason: `check "${run.name}" concluded ${run.conclusion}` };
|
|
164135
|
+
}
|
|
164136
|
+
}
|
|
164137
|
+
return { ok: true, reason: "all checks passed" };
|
|
164138
|
+
}
|
|
164139
|
+
function hasVerifiedCheck(params) {
|
|
164140
|
+
return params.checkRuns.some(
|
|
164141
|
+
(r) => !PULLFROG_CHECKS.has(r.name.toLowerCase()) && r.status === "completed"
|
|
164142
|
+
);
|
|
164143
|
+
}
|
|
164144
|
+
|
|
164145
|
+
// utils/autoMerge.ts
|
|
164146
|
+
var NON_MERGEABLE_STATES = /* @__PURE__ */ new Set(["dirty", "behind", "blocked"]);
|
|
164147
|
+
function hasBlockingHumanReview(reviews) {
|
|
164148
|
+
const latestByReviewer = /* @__PURE__ */ new Map();
|
|
164149
|
+
for (const review of reviews) {
|
|
164150
|
+
const login = review.user?.login;
|
|
164151
|
+
if (!login || isPullfrog(login)) continue;
|
|
164152
|
+
if (review.state === "APPROVED" || review.state === "CHANGES_REQUESTED") {
|
|
164153
|
+
latestByReviewer.set(login, review.state);
|
|
164154
|
+
} else if (review.state === "DISMISSED") {
|
|
164155
|
+
latestByReviewer.delete(login);
|
|
164156
|
+
}
|
|
164157
|
+
}
|
|
164158
|
+
for (const state of latestByReviewer.values()) {
|
|
164159
|
+
if (state === "CHANGES_REQUESTED") return true;
|
|
164160
|
+
}
|
|
164161
|
+
return false;
|
|
164162
|
+
}
|
|
164163
|
+
async function autoMergeAfterApprove(ctx) {
|
|
164164
|
+
if (!ctx.autoMergeEnabled) return;
|
|
164165
|
+
if (!ctx.prApproveEnabled) return;
|
|
164166
|
+
const approval = ctx.toolState.approval;
|
|
164167
|
+
if (!approval?.wouldApprove) return;
|
|
164168
|
+
const pullNumber = ctx.payload.event.issue_number;
|
|
164169
|
+
if (typeof pullNumber !== "number") return;
|
|
164170
|
+
const skip = (reason) => log.info(
|
|
164171
|
+
`autoMerge: pr=#${pullNumber} approvalSha=${approval.sha?.slice(0, 7)} \u2192 skipped: ${reason}`
|
|
164172
|
+
);
|
|
164173
|
+
const pr = await ctx.octokit.rest.pulls.get({
|
|
164174
|
+
owner: ctx.repo.owner,
|
|
164175
|
+
repo: ctx.repo.name,
|
|
164176
|
+
pull_number: pullNumber
|
|
164177
|
+
});
|
|
164178
|
+
if (pr.data.state !== "open") return skip("pr not open");
|
|
164179
|
+
if (pr.data.draft) return skip("pr is draft");
|
|
164180
|
+
const headSha = pr.data.head.sha;
|
|
164181
|
+
if (approval.sha !== headSha) return skip(`approval sha != head ${headSha.slice(0, 7)}`);
|
|
164182
|
+
const outstanding = await countOutstandingPullfrogThreads(ctx, pullNumber);
|
|
164183
|
+
if (outstanding > 0) return skip(`${outstanding} unresolved Pullfrog thread(s)`);
|
|
164184
|
+
const reviews = await ctx.octokit.paginate(ctx.octokit.rest.pulls.listReviews, {
|
|
164185
|
+
owner: ctx.repo.owner,
|
|
164186
|
+
repo: ctx.repo.name,
|
|
164187
|
+
pull_number: pullNumber,
|
|
164188
|
+
per_page: 100
|
|
164189
|
+
});
|
|
164190
|
+
if (hasBlockingHumanReview(reviews)) return skip("human changes requested");
|
|
164191
|
+
if (pr.data.mergeable !== true) return skip(`not mergeable (mergeable=${pr.data.mergeable})`);
|
|
164192
|
+
if (pr.data.mergeable_state && NON_MERGEABLE_STATES.has(pr.data.mergeable_state)) {
|
|
164193
|
+
return skip(`mergeable_state=${pr.data.mergeable_state}`);
|
|
164194
|
+
}
|
|
164195
|
+
const checkRuns = await ctx.octokit.paginate(ctx.octokit.rest.checks.listForRef, {
|
|
164196
|
+
owner: ctx.repo.owner,
|
|
164197
|
+
repo: ctx.repo.name,
|
|
164198
|
+
ref: headSha,
|
|
164199
|
+
per_page: 100
|
|
164200
|
+
});
|
|
164201
|
+
const gate = checkRunsGate({ checkRuns });
|
|
164202
|
+
if (!gate.ok) return skip(`ci: ${gate.reason}`);
|
|
164203
|
+
if (!hasVerifiedCheck({ checkRuns })) return skip("no completed external check-run to verify");
|
|
164204
|
+
const merge4 = await ctx.octokit.rest.pulls.merge({
|
|
164205
|
+
owner: ctx.repo.owner,
|
|
164206
|
+
repo: ctx.repo.name,
|
|
164207
|
+
pull_number: pullNumber,
|
|
164208
|
+
sha: headSha,
|
|
164209
|
+
merge_method: "squash",
|
|
164210
|
+
commit_title: `${pr.data.title} (#${pullNumber})`,
|
|
164211
|
+
commit_message: "merged autonomously by Pullfrog after a clean approval."
|
|
164212
|
+
});
|
|
164213
|
+
log.info(
|
|
164214
|
+
`autoMerge: pr=#${pullNumber} approvalSha=${headSha.slice(0, 7)} outstanding=0 \u2192 merged ${merge4.data.sha?.slice(0, 7)}`
|
|
164215
|
+
);
|
|
164216
|
+
await ctx.octokit.rest.issues.createComment({
|
|
164217
|
+
owner: ctx.repo.owner,
|
|
164218
|
+
repo: ctx.repo.name,
|
|
164219
|
+
issue_number: pullNumber,
|
|
164220
|
+
body: addFooter(
|
|
164221
|
+
ctx,
|
|
164222
|
+
"> \u2705 Merged autonomously after Pullfrog approved this PR and resolved all of its own review threads."
|
|
164223
|
+
)
|
|
164224
|
+
}).catch((err) => log.debug(`autoMerge comment failed: ${err}`));
|
|
164225
|
+
}
|
|
164226
|
+
|
|
163926
164227
|
// utils/reviewCleanup.ts
|
|
163927
164228
|
var RE_REVIEW_PREAMBLE = "Incrementally re-review the new commits on this pull request. Use the IncrementalReview mode.";
|
|
163928
164229
|
async function postReviewCleanup(ctx) {
|
|
@@ -163979,13 +164280,20 @@ async function dispatchFollowUpReReview(ctx, reviewedSha) {
|
|
|
163979
164280
|
eventInstructions: RE_REVIEW_PREAMBLE,
|
|
163980
164281
|
event
|
|
163981
164282
|
};
|
|
163982
|
-
await
|
|
163983
|
-
|
|
163984
|
-
|
|
163985
|
-
|
|
163986
|
-
|
|
163987
|
-
|
|
163988
|
-
|
|
164283
|
+
await op(
|
|
164284
|
+
() => ctx.octokit.rest.actions.createWorkflowDispatch({
|
|
164285
|
+
owner: ctx.repo.owner,
|
|
164286
|
+
repo: ctx.repo.name,
|
|
164287
|
+
workflow_id: getCurrentWorkflowFilename(),
|
|
164288
|
+
ref: pr.data.base.repo.default_branch,
|
|
164289
|
+
inputs: { prompt: JSON.stringify(payload) }
|
|
164290
|
+
}),
|
|
164291
|
+
{
|
|
164292
|
+
name: "reReviewDispatch",
|
|
164293
|
+
retries: [500, 2e3],
|
|
164294
|
+
bail: (error49) => !isTransientOctokitError(error49)
|
|
164295
|
+
}
|
|
164296
|
+
)();
|
|
163989
164297
|
}
|
|
163990
164298
|
function getCurrentWorkflowFilename() {
|
|
163991
164299
|
const ref = process.env.GITHUB_WORKFLOW_REF ?? "";
|
|
@@ -163993,6 +164301,62 @@ function getCurrentWorkflowFilename() {
|
|
|
163993
164301
|
return match3?.[1] ?? "pullfrog.yml";
|
|
163994
164302
|
}
|
|
163995
164303
|
|
|
164304
|
+
// utils/statusChecks.ts
|
|
164305
|
+
var COMPLETION_CHECK = "pullfrog";
|
|
164306
|
+
var APPROVAL_CHECK = "pullfrog-approval";
|
|
164307
|
+
async function createCheckRun(ctx, params) {
|
|
164308
|
+
const createParams = {
|
|
164309
|
+
owner: ctx.repo.owner,
|
|
164310
|
+
repo: ctx.repo.name,
|
|
164311
|
+
name: params.name,
|
|
164312
|
+
head_sha: params.headSha,
|
|
164313
|
+
status: "completed",
|
|
164314
|
+
conclusion: params.conclusion,
|
|
164315
|
+
output: { title: params.title, summary: params.summary }
|
|
164316
|
+
};
|
|
164317
|
+
if (ctx.runId) {
|
|
164318
|
+
createParams.details_url = `https://github.com/${ctx.repo.owner}/${ctx.repo.name}/actions/runs/${ctx.runId}`;
|
|
164319
|
+
}
|
|
164320
|
+
await ctx.octokit.rest.checks.create(createParams);
|
|
164321
|
+
log.info(`\xBB posted ${params.name} check (${params.conclusion}) on ${params.headSha.slice(0, 7)}`);
|
|
164322
|
+
}
|
|
164323
|
+
async function reportStatusChecks(ctx, params) {
|
|
164324
|
+
if (!ctx.payload.statusChecks) return;
|
|
164325
|
+
const event = ctx.payload.event;
|
|
164326
|
+
const pullNumber = event.issue_number;
|
|
164327
|
+
if (event.is_pr !== true || typeof pullNumber !== "number") return;
|
|
164328
|
+
let headSha;
|
|
164329
|
+
try {
|
|
164330
|
+
const pr = await ctx.octokit.rest.pulls.get({
|
|
164331
|
+
owner: ctx.repo.owner,
|
|
164332
|
+
repo: ctx.repo.name,
|
|
164333
|
+
pull_number: pullNumber
|
|
164334
|
+
});
|
|
164335
|
+
headSha = pr.data.head.sha;
|
|
164336
|
+
} catch (err) {
|
|
164337
|
+
log.debug(`status checks: failed to resolve PR #${pullNumber} head sha: ${err}`);
|
|
164338
|
+
return;
|
|
164339
|
+
}
|
|
164340
|
+
const completionSha = primaryRepoState(ctx.toolState).checkoutSha ?? headSha;
|
|
164341
|
+
await createCheckRun(ctx, {
|
|
164342
|
+
name: COMPLETION_CHECK,
|
|
164343
|
+
headSha: completionSha,
|
|
164344
|
+
conclusion: params.runSucceeded ? "success" : "failure",
|
|
164345
|
+
title: params.runSucceeded ? "Pullfrog run completed" : "Pullfrog run failed",
|
|
164346
|
+
summary: params.runSucceeded ? "The Pullfrog run finished successfully." : "The Pullfrog run failed or timed out. See the run logs for details."
|
|
164347
|
+
}).catch((err) => log.debug(`status checks: ${COMPLETION_CHECK} post failed: ${err}`));
|
|
164348
|
+
const approval = ctx.toolState.approval;
|
|
164349
|
+
if (params.runSucceeded && approval) {
|
|
164350
|
+
await createCheckRun(ctx, {
|
|
164351
|
+
name: APPROVAL_CHECK,
|
|
164352
|
+
headSha: approval.sha ?? headSha,
|
|
164353
|
+
conclusion: approval.wouldApprove ? "success" : "failure",
|
|
164354
|
+
title: approval.wouldApprove ? "Pullfrog would approve" : "Pullfrog would not approve",
|
|
164355
|
+
summary: approval.wouldApprove ? "Pullfrog has no outstanding review feedback on this PR." : "Pullfrog has outstanding review feedback or requested changes on this PR."
|
|
164356
|
+
}).catch((err) => log.debug(`status checks: ${APPROVAL_CHECK} post failed: ${err}`));
|
|
164357
|
+
}
|
|
164358
|
+
}
|
|
164359
|
+
|
|
163996
164360
|
// utils/runLifecycle.ts
|
|
163997
164361
|
async function persistRunArtifacts(toolContext) {
|
|
163998
164362
|
await postReviewCleanup(toolContext).catch((error49) => {
|
|
@@ -164036,6 +164400,17 @@ async function finalizeSuccessRun(input) {
|
|
|
164036
164400
|
log.info(`::pullfrog-output::${Buffer.from(input.toolState.output).toString("base64")}`);
|
|
164037
164401
|
core10.setOutput("result", input.toolState.output);
|
|
164038
164402
|
}
|
|
164403
|
+
if (input.result.success) {
|
|
164404
|
+
await approveAfterFix(input.toolContext).catch((error49) => {
|
|
164405
|
+
log.debug(`fix auto-approval failed: ${error49}`);
|
|
164406
|
+
});
|
|
164407
|
+
await autoMergeAfterApprove(input.toolContext).catch((error49) => {
|
|
164408
|
+
const raced = typeof error49 === "object" && error49 !== null && "status" in error49 && error49.status === 409;
|
|
164409
|
+
if (raced) log.debug(`auto-merge skipped (head moved): ${error49}`);
|
|
164410
|
+
else log.warning(`auto-merge failed: ${error49}`);
|
|
164411
|
+
});
|
|
164412
|
+
}
|
|
164413
|
+
await reportStatusChecks(input.toolContext, { runSucceeded: input.result.success });
|
|
164039
164414
|
}
|
|
164040
164415
|
async function writeRunErrorOutputs(input) {
|
|
164041
164416
|
try {
|
|
@@ -164462,7 +164837,11 @@ async function main() {
|
|
|
164462
164837
|
get githubInstallationToken() {
|
|
164463
164838
|
return getGitHubInstallationToken();
|
|
164464
164839
|
},
|
|
164465
|
-
|
|
164840
|
+
// live getter, same reason as #891 above — reads the current git token
|
|
164841
|
+
// (canonical rationale on TokenRef.gitToken). see #964.
|
|
164842
|
+
get gitToken() {
|
|
164843
|
+
return tokenRef.gitToken;
|
|
164844
|
+
},
|
|
164466
164845
|
refreshGitToken: tokenRef.refreshGitToken,
|
|
164467
164846
|
readToken: tokenRef.readToken,
|
|
164468
164847
|
xrepo: payload.xrepo,
|
|
@@ -164471,6 +164850,7 @@ async function main() {
|
|
|
164471
164850
|
postCheckoutScript: runContext.repoSettings.postCheckoutScript,
|
|
164472
164851
|
prepushScript: runContext.repoSettings.prepushScript,
|
|
164473
164852
|
prApproveEnabled: runContext.repoSettings.prApproveEnabled,
|
|
164853
|
+
autoMergeEnabled: runContext.repoSettings.autoMergeEnabled,
|
|
164474
164854
|
signedCommits: runContext.repoSettings.signedCommits,
|
|
164475
164855
|
modeInstructions: runContext.repoSettings.modeInstructions,
|
|
164476
164856
|
toolState,
|
|
@@ -164712,6 +165092,7 @@ ${instructions.user}` : null,
|
|
|
164712
165092
|
await writeRunErrorOutputs({ rendered, toolState });
|
|
164713
165093
|
if (toolContext) {
|
|
164714
165094
|
await persistRunArtifacts(toolContext);
|
|
165095
|
+
await reportStatusChecks(toolContext, { runSucceeded: false });
|
|
164715
165096
|
}
|
|
164716
165097
|
return {
|
|
164717
165098
|
success: false,
|