pullfrog 0.1.83 → 0.1.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +109317 -127190
- package/dist/configuration.d.ts +2 -2
- package/dist/external.d.ts +3 -3
- package/dist/index.js +54591 -58745
- package/dist/internal/index.d.ts +3 -0
- package/dist/internal.js +251 -55
- package/dist/mcp/review.d.ts +0 -14
- package/dist/utils/billingErrors.d.ts +1 -0
- package/dist/utils/codexHome.d.ts +1 -0
- package/dist/utils/credentialPool.d.ts +10 -0
- package/dist/utils/outstandingThreads.d.ts +25 -0
- package/dist/utils/payload.d.ts +2 -2
- package/dist/utils/runContext.d.ts +2 -0
- package/dist/utils/runContextData.d.ts +2 -0
- package/dist/utils/setup.d.ts +8 -2
- package/dist/utils/subscriptionCredentials.d.ts +80 -0
- package/dist/utils/subscriptionProbe.d.ts +22 -0
- package/dist/yes.js +1 -1
- package/package.json +3 -3
package/dist/internal/index.d.ts
CHANGED
|
@@ -20,11 +20,14 @@ export type { ResourceUsage, UsageSummary } from "../utils/github.ts";
|
|
|
20
20
|
export { isPullfrog } from "../utils/isPullfrog.ts";
|
|
21
21
|
export { isLeapingIntoActionCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../utils/leapingComment.ts";
|
|
22
22
|
export { MAX_LEARNINGS_LENGTH, truncateAtLineBoundary } from "../utils/learningsTruncate.ts";
|
|
23
|
+
export { countOutstandingPullfrogThreads } from "../utils/outstandingThreads.ts";
|
|
23
24
|
export type { CreateProgressCommentTarget, ProgressComment, ProgressCommentType, } from "../utils/progressComment.ts";
|
|
24
25
|
export { createLeapingProgressComment, deleteProgressCommentApi, getProgressComment, updateProgressComment, } from "../utils/progressComment.ts";
|
|
25
26
|
export { PROVIDER_DASHBOARDS, type ProviderDashboard } from "../utils/providerDashboards.ts";
|
|
26
27
|
export type { RunStatusCheckConclusion, RunStatusCheckOctokit, } from "../utils/runStatusCheck.ts";
|
|
27
28
|
export { APPROVAL_CHECK_NAME, createRunStatusCheck, finalizeRunStatusCheck, RUN_STATUS_CHECK_NAME, runStatusCheckNeedsFinalizing, } from "../utils/runStatusCheck.ts";
|
|
29
|
+
export * from "../utils/subscriptionCredentials.ts";
|
|
30
|
+
export { probeSubscription, SubscriptionCredentialError, subscriptionIdentity, } from "../utils/subscriptionProbe.ts";
|
|
28
31
|
export { isValidTimeString, parseTimeString, TIMEOUT_DISABLED, } from "../utils/time.ts";
|
|
29
32
|
export type { XaiAuthBody } from "../utils/xaiOAuth.ts";
|
|
30
33
|
export { parseXaiAuthBody, refreshXaiAuthBody, stringifyXaiAuthBody, } from "../utils/xaiOAuth.ts";
|
package/dist/internal.js
CHANGED
|
@@ -8,7 +8,7 @@ var __export = (target, all) => {
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "pullfrog",
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.85",
|
|
12
12
|
cliContractVersion: "1",
|
|
13
13
|
type: "module",
|
|
14
14
|
bin: {
|
|
@@ -44,8 +44,8 @@ var package_default = {
|
|
|
44
44
|
"@octokit/plugin-throttling": "^11.0.3",
|
|
45
45
|
"@octokit/rest": "^22.0.0",
|
|
46
46
|
"@octokit/webhooks-types": "^7.6.1",
|
|
47
|
-
"@openai/codex": "0.
|
|
48
|
-
"@openai/codex-sdk": "0.
|
|
47
|
+
"@openai/codex": "0.157.0",
|
|
48
|
+
"@openai/codex-sdk": "0.157.0",
|
|
49
49
|
"@opencode-ai/sdk": "1.18.29",
|
|
50
50
|
"@standard-schema/spec": "1.1.0",
|
|
51
51
|
"@toon-format/toon": "^1.0.0",
|
|
@@ -14931,22 +14931,14 @@ var providers = {
|
|
|
14931
14931
|
displayName: "Qwen Max",
|
|
14932
14932
|
resolve: "opencode/qwen3.8-max",
|
|
14933
14933
|
openRouterEffort: ["minimal", "low", "medium", "high", "xhigh"],
|
|
14934
|
-
openRouterResolve: "openrouter/qwen/qwen3.8-max-0902"
|
|
14935
|
-
// unlisted until a published `pullfrog` carries this alias (the
|
|
14936
|
-
// merge-vs-publish rule in wiki/models-catalog.md). unhide in the release
|
|
14937
|
-
// that ships it.
|
|
14938
|
-
hidden: true
|
|
14934
|
+
openRouterResolve: "openrouter/qwen/qwen3.8-max-0902"
|
|
14939
14935
|
},
|
|
14940
14936
|
"qwen-flash": {
|
|
14941
14937
|
displayName: "Qwen Flash",
|
|
14942
14938
|
resolve: "opencode/qwen3.8-flash",
|
|
14943
14939
|
effort: ["low", "medium", "xhigh"],
|
|
14944
14940
|
openRouterEffort: [],
|
|
14945
|
-
openRouterResolve: "openrouter/qwen/qwen3.8-flash"
|
|
14946
|
-
// unlisted until a published `pullfrog` carries this alias (the
|
|
14947
|
-
// merge-vs-publish rule in wiki/models-catalog.md). unhide in the release
|
|
14948
|
-
// that ships it.
|
|
14949
|
-
hidden: true
|
|
14941
|
+
openRouterResolve: "openrouter/qwen/qwen3.8-flash"
|
|
14950
14942
|
},
|
|
14951
14943
|
"gpt-5-nano": {
|
|
14952
14944
|
displayName: "GPT Nano",
|
|
@@ -15006,11 +14998,18 @@ var providers = {
|
|
|
15006
14998
|
effort: ["low", "medium", "high", "xhigh", "max"],
|
|
15007
14999
|
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
15008
15000
|
// see the big-pickle note above (#1077).
|
|
15009
|
-
isFree: true
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15001
|
+
isFree: true
|
|
15002
|
+
},
|
|
15003
|
+
// Zen's FREE Meituan preview (listed 2026-09-25). Zen's docs: zero
|
|
15004
|
+
// retention, no training. Go lists the same free id, but one key reaches
|
|
15005
|
+
// both, so the promo gets one row, here with the other free ones.
|
|
15006
|
+
"longcat-preview": {
|
|
15007
|
+
displayName: "LongCat Preview",
|
|
15008
|
+
description: "Meituan preview, free for a limited time",
|
|
15009
|
+
resolve: "opencode/longcat-2.5-preview-free",
|
|
15010
|
+
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
15011
|
+
// see the big-pickle note above (#1077).
|
|
15012
|
+
isFree: true
|
|
15014
15013
|
},
|
|
15015
15014
|
// Zen's live free MiMo, and the second free row in a menu that big-pickle
|
|
15016
15015
|
// was alone in since `mimo-v2-pro-free` lost its model.
|
|
@@ -15645,7 +15644,7 @@ function isRouterTier(value) {
|
|
|
15645
15644
|
}
|
|
15646
15645
|
var PROVIDER_LADDERS = {
|
|
15647
15646
|
anthropic: {
|
|
15648
|
-
minimal: "anthropic/claude-
|
|
15647
|
+
minimal: "anthropic/claude-sonnet",
|
|
15649
15648
|
light: "anthropic/claude-sonnet",
|
|
15650
15649
|
standard: "anthropic/claude-opus",
|
|
15651
15650
|
deep: "anthropic/claude-opus"
|
|
@@ -15963,7 +15962,7 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
15963
15962
|
6. Finalize:
|
|
15964
15963
|
- **only if code changed**, ${finalizeStep} (same push/prepush guidance as Build mode in *SYSTEM*). If push/commit fails, report the exact error and STOP without claiming a fix or resolving its threads.
|
|
15965
15964
|
- reply ONCE per relevant thread via \`${t("reply_to_review_comment")}\`, including when no code changed. The \`comment_id\` is the root comment's numeric \`id=\`, NOT the \`thread=\` value from \`${t("get_review_comments")}\`. The runtime dedupes identical bodies within a session.
|
|
15966
|
-
- resolve a thread via \`${t("resolve_review_thread")}\` (using \`thread=\` as \`thread_id\`) only after its requested fix is fully on the remote,
|
|
15965
|
+
- resolve a thread via \`${t("resolve_review_thread")}\` (using \`thread=\` as \`thread_id\`) only after its requested fix is fully on the remote, the user explicitly asks to resolve it, or it is a Pullfrog finding you agree to withdraw. Leave other discussion-only replies, partial fixes, and disagreements open.
|
|
15967
15966
|
- call \`${t("report_progress")}\` with a brief summary. If your last \`${t("get_review_comments")}\` turned up threads you did not address, name them there \u2014 a review arriving this late is suppressed as a duplicate and nothing else will pick it up.`
|
|
15968
15967
|
},
|
|
15969
15968
|
// Review and IncrementalReview route the minimum reviewfrog specialists
|
|
@@ -16223,35 +16222,25 @@ var modes = computeModes("opencode");
|
|
|
16223
16222
|
|
|
16224
16223
|
// utils/billingErrors.ts
|
|
16225
16224
|
function commercialPaywallBody(params) {
|
|
16226
|
-
|
|
16225
|
+
let action;
|
|
16227
16226
|
switch (params.reason) {
|
|
16228
16227
|
case "commercial":
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
-
"",
|
|
16232
|
-
pitch,
|
|
16233
|
-
"",
|
|
16234
|
-
`[Upgrade now \u2192](${params.url})`
|
|
16235
|
-
].join("\n");
|
|
16228
|
+
action = "upgrade";
|
|
16229
|
+
break;
|
|
16236
16230
|
case "subscription_ended":
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
"",
|
|
16240
|
-
pitch,
|
|
16241
|
-
"",
|
|
16242
|
-
`[Resubscribe \u2192](${params.url})`
|
|
16243
|
-
].join("\n");
|
|
16231
|
+
action = "resubscribe";
|
|
16232
|
+
break;
|
|
16244
16233
|
case "subscription_unpaid":
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
"",
|
|
16248
|
-
"Update the card on file to resume runs.",
|
|
16249
|
-
"",
|
|
16250
|
-
`[Update billing \u2192](${params.url})`
|
|
16251
|
-
].join("\n");
|
|
16234
|
+
action = "update billing";
|
|
16235
|
+
break;
|
|
16252
16236
|
default:
|
|
16253
16237
|
return params.reason;
|
|
16254
16238
|
}
|
|
16239
|
+
return [
|
|
16240
|
+
`**Pullfrog is ${params.freshReply ? "still paused" : "paused"} for ${params.ownerLogin}.**`,
|
|
16241
|
+
"",
|
|
16242
|
+
`An org owner can [${action}](${params.url}) to resume private-repo runs.`
|
|
16243
|
+
].join("\n");
|
|
16255
16244
|
}
|
|
16256
16245
|
|
|
16257
16246
|
// utils/buildPullfrogFooter.ts
|
|
@@ -16590,6 +16579,42 @@ function truncateAtLineBoundary(body, cap) {
|
|
|
16590
16579
|
return head.slice(0, lastNewline);
|
|
16591
16580
|
}
|
|
16592
16581
|
|
|
16582
|
+
// utils/outstandingThreads.ts
|
|
16583
|
+
var OUTSTANDING_THREADS_QUERY = `
|
|
16584
|
+
query ($owner: String!, $name: String!, $prNumber: Int!, $cursor: String) {
|
|
16585
|
+
repository(owner: $owner, name: $name) {
|
|
16586
|
+
pullRequest(number: $prNumber) {
|
|
16587
|
+
reviewThreads(first: 100, after: $cursor) {
|
|
16588
|
+
pageInfo { hasNextPage endCursor }
|
|
16589
|
+
nodes {
|
|
16590
|
+
isResolved
|
|
16591
|
+
comments(first: 1) { nodes { author { login } } }
|
|
16592
|
+
}
|
|
16593
|
+
}
|
|
16594
|
+
}
|
|
16595
|
+
}
|
|
16596
|
+
}
|
|
16597
|
+
`;
|
|
16598
|
+
async function countOutstandingPullfrogThreads(ctx, pullNumber) {
|
|
16599
|
+
let count = 0;
|
|
16600
|
+
let cursor = null;
|
|
16601
|
+
for (let page = 0; page < 50; page += 1) {
|
|
16602
|
+
const response = await ctx.octokit.graphql(
|
|
16603
|
+
OUTSTANDING_THREADS_QUERY,
|
|
16604
|
+
{ owner: ctx.repo.owner, name: ctx.repo.name, prNumber: pullNumber, cursor }
|
|
16605
|
+
);
|
|
16606
|
+
const conn = response.repository?.pullRequest?.reviewThreads;
|
|
16607
|
+
for (const thread of conn?.nodes ?? []) {
|
|
16608
|
+
if (!thread || thread.isResolved) continue;
|
|
16609
|
+
const root = thread.comments?.nodes?.find((c) => c != null);
|
|
16610
|
+
if (root && isPullfrog(root.author?.login)) count += 1;
|
|
16611
|
+
}
|
|
16612
|
+
if (!conn?.pageInfo.hasNextPage) break;
|
|
16613
|
+
cursor = conn.pageInfo.endCursor;
|
|
16614
|
+
}
|
|
16615
|
+
return count;
|
|
16616
|
+
}
|
|
16617
|
+
|
|
16593
16618
|
// utils/progressComment.ts
|
|
16594
16619
|
async function getProgressComment(ctx, comment) {
|
|
16595
16620
|
const result = await (comment.type === "review" ? ctx.octokit.rest.pulls.getReviewComment({
|
|
@@ -16911,19 +16936,47 @@ async function runStatusCheckNeedsFinalizing(params) {
|
|
|
16911
16936
|
}
|
|
16912
16937
|
}
|
|
16913
16938
|
|
|
16914
|
-
// utils/
|
|
16915
|
-
var
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16939
|
+
// utils/subscriptionCredentials.ts
|
|
16940
|
+
var subscriptionNameSchema = external_exports.enum([
|
|
16941
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
16942
|
+
"CODEX_AUTH_JSON",
|
|
16943
|
+
"GROK_AUTH_JSON"
|
|
16944
|
+
]);
|
|
16945
|
+
var subscriptionSchema = external_exports.object({
|
|
16946
|
+
id: external_exports.string(),
|
|
16947
|
+
credentialId: external_exports.string(),
|
|
16948
|
+
name: subscriptionNameSchema,
|
|
16949
|
+
label: external_exports.string(),
|
|
16950
|
+
owner: external_exports.string(),
|
|
16951
|
+
inherited: external_exports.boolean(),
|
|
16952
|
+
shared: external_exports.boolean(),
|
|
16953
|
+
registeredAt: external_exports.string()
|
|
16954
|
+
});
|
|
16955
|
+
var subscriptionListSchema = external_exports.object({
|
|
16956
|
+
subscriptions: external_exports.array(subscriptionSchema),
|
|
16957
|
+
writable: external_exports.boolean()
|
|
16958
|
+
});
|
|
16959
|
+
var subscriptionInputSchema = external_exports.object({
|
|
16960
|
+
name: subscriptionNameSchema,
|
|
16961
|
+
value: external_exports.string().trim().min(1).refine((value) => Buffer.byteLength(value, "utf8") <= 49152),
|
|
16962
|
+
replaceId: external_exports.string().optional()
|
|
16963
|
+
});
|
|
16964
|
+
var credentialCandidateSchema = external_exports.object({
|
|
16965
|
+
id: external_exports.string(),
|
|
16966
|
+
name: external_exports.string(),
|
|
16967
|
+
source: external_exports.enum(["repo", "account", "personal"])
|
|
16968
|
+
});
|
|
16969
|
+
var credentialAccessSchema = external_exports.object({
|
|
16970
|
+
token: external_exports.string(),
|
|
16971
|
+
candidates: external_exports.array(credentialCandidateSchema)
|
|
16972
|
+
});
|
|
16973
|
+
var selectedCredentialSchema = external_exports.object({
|
|
16974
|
+
name: external_exports.string(),
|
|
16975
|
+
value: external_exports.string(),
|
|
16976
|
+
receipt: external_exports.string()
|
|
16977
|
+
});
|
|
16978
|
+
function subscriptionLabel(input) {
|
|
16979
|
+
return input.email ?? `\u2022\u2022\u2022\u2022 ${input.suffix}`;
|
|
16927
16980
|
}
|
|
16928
16981
|
|
|
16929
16982
|
// utils/xaiOAuth.ts
|
|
@@ -16988,6 +17041,137 @@ function stringifyXaiAuthBody(body) {
|
|
|
16988
17041
|
return `${JSON.stringify(body, null, 2)}
|
|
16989
17042
|
`;
|
|
16990
17043
|
}
|
|
17044
|
+
|
|
17045
|
+
// utils/subscriptionProbe.ts
|
|
17046
|
+
var identitySchema = external_exports.object({
|
|
17047
|
+
email: external_exports.string().email().optional(),
|
|
17048
|
+
sub: external_exports.string().optional(),
|
|
17049
|
+
user_id: external_exports.string().optional(),
|
|
17050
|
+
account_id: external_exports.string().optional(),
|
|
17051
|
+
email_verified: external_exports.boolean().optional()
|
|
17052
|
+
});
|
|
17053
|
+
var codexUsageSchema = external_exports.object({
|
|
17054
|
+
rate_limit: external_exports.object({ allowed: external_exports.boolean(), limit_reached: external_exports.boolean() }).optional()
|
|
17055
|
+
});
|
|
17056
|
+
var SubscriptionCredentialError = class extends Error {
|
|
17057
|
+
};
|
|
17058
|
+
async function subscriptionIdentity(input) {
|
|
17059
|
+
const empty = { email: null, subject: null };
|
|
17060
|
+
if (input.name === "CLAUDE_CODE_OAUTH_TOKEN") return empty;
|
|
17061
|
+
const codex = input.name === "CODEX_AUTH_JSON" ? parseCodexAuthBody(input.value) : null;
|
|
17062
|
+
const grok = input.name === "GROK_AUTH_JSON" ? parseXaiAuthBody(input.value) : null;
|
|
17063
|
+
const token = codex?.tokens.access_token ?? grok?.tokens.access_token;
|
|
17064
|
+
if (!token) throw new SubscriptionCredentialError("invalid subscription credential");
|
|
17065
|
+
const response = await readSubscriptionEndpoint({
|
|
17066
|
+
url: codex ? "https://chatgpt.com/backend-api/wham/usage" : "https://auth.x.ai/oauth2/userinfo",
|
|
17067
|
+
token,
|
|
17068
|
+
accountId: codex?.tokens.account_id
|
|
17069
|
+
});
|
|
17070
|
+
if (response?.status === 401)
|
|
17071
|
+
throw new SubscriptionCredentialError("subscription credential was rejected");
|
|
17072
|
+
if (!response?.ok) return empty;
|
|
17073
|
+
const parsed = identitySchema.safeParse(await response.json().catch(() => null));
|
|
17074
|
+
if (!parsed.success) return empty;
|
|
17075
|
+
const subject = parsed.data.sub ?? parsed.data.user_id;
|
|
17076
|
+
return {
|
|
17077
|
+
email: parsed.data.email_verified === false ? null : parsed.data.email ?? null,
|
|
17078
|
+
subject: subject ? `${subject}:${parsed.data.account_id ?? ""}` : null
|
|
17079
|
+
};
|
|
17080
|
+
}
|
|
17081
|
+
async function readSubscriptionEndpoint(input) {
|
|
17082
|
+
const headers = new Headers({ authorization: `Bearer ${input.token}` });
|
|
17083
|
+
if (input.accountId) headers.set("ChatGPT-Account-Id", input.accountId);
|
|
17084
|
+
if (input.grokBilling) headers.set("x-xai-token-auth", "xai-grok-cli");
|
|
17085
|
+
return fetch(input.url, {
|
|
17086
|
+
headers,
|
|
17087
|
+
redirect: "error",
|
|
17088
|
+
signal: AbortSignal.timeout(1e4)
|
|
17089
|
+
}).catch(() => null);
|
|
17090
|
+
}
|
|
17091
|
+
async function probeSubscription(input) {
|
|
17092
|
+
if (input.name === "CLAUDE_CODE_OAUTH_TOKEN") {
|
|
17093
|
+
const result = await preflightClaudeSubscription({ token: input.value, model: input.model });
|
|
17094
|
+
return result.usable ? "usable" : "rejected";
|
|
17095
|
+
}
|
|
17096
|
+
const codex = input.name === "CODEX_AUTH_JSON" ? parseCodexAuthBody(input.value) : null;
|
|
17097
|
+
const grok = input.name === "GROK_AUTH_JSON" ? parseXaiAuthBody(input.value) : null;
|
|
17098
|
+
const auth = codex ?? grok;
|
|
17099
|
+
if (!auth || auth.refresh_rejected_at) return "rejected";
|
|
17100
|
+
if (grok && input.model)
|
|
17101
|
+
return probeInference({
|
|
17102
|
+
name: "XAI_API_KEY",
|
|
17103
|
+
value: grok.tokens.access_token,
|
|
17104
|
+
model: input.model
|
|
17105
|
+
});
|
|
17106
|
+
const response = await readSubscriptionEndpoint({
|
|
17107
|
+
url: codex ? "https://chatgpt.com/backend-api/wham/usage" : "https://cli-chat-proxy.grok.com/v1/billing?format=credits",
|
|
17108
|
+
token: auth.tokens.access_token,
|
|
17109
|
+
accountId: codex?.tokens.account_id,
|
|
17110
|
+
grokBilling: !!grok
|
|
17111
|
+
});
|
|
17112
|
+
if (response?.status === 401) return "rejected";
|
|
17113
|
+
if (!response?.ok) return "unknown";
|
|
17114
|
+
const body = await response.json().catch(() => null);
|
|
17115
|
+
if (codex) {
|
|
17116
|
+
const parsed = codexUsageSchema.safeParse(body);
|
|
17117
|
+
const limit = parsed.success ? parsed.data.rate_limit : void 0;
|
|
17118
|
+
if (!limit) return "unknown";
|
|
17119
|
+
return limit.allowed && !limit.limit_reached ? "usable" : "rejected";
|
|
17120
|
+
}
|
|
17121
|
+
return "unknown";
|
|
17122
|
+
}
|
|
17123
|
+
async function probeInference(input) {
|
|
17124
|
+
const anthropic = input.name === "ANTHROPIC_API_KEY";
|
|
17125
|
+
const openai = input.name === "OPENAI_API_KEY";
|
|
17126
|
+
if (!anthropic && !openai && input.name !== "XAI_API_KEY") {
|
|
17127
|
+
const result = await verifyCredential({ envVar: input.name, value: input.value });
|
|
17128
|
+
return result === "dead" ? "rejected" : result === "alive" ? "usable" : "unknown";
|
|
17129
|
+
}
|
|
17130
|
+
const headers = new Headers({ "content-type": "application/json" });
|
|
17131
|
+
if (anthropic) {
|
|
17132
|
+
headers.set("x-api-key", input.value);
|
|
17133
|
+
headers.set("anthropic-version", "2023-06-01");
|
|
17134
|
+
} else headers.set("authorization", `Bearer ${input.value}`);
|
|
17135
|
+
const response = await fetch(
|
|
17136
|
+
anthropic ? "https://api.anthropic.com/v1/messages" : openai ? "https://api.openai.com/v1/responses" : "https://api.x.ai/v1/chat/completions",
|
|
17137
|
+
{
|
|
17138
|
+
method: "POST",
|
|
17139
|
+
headers,
|
|
17140
|
+
body: JSON.stringify(
|
|
17141
|
+
openai ? { model: input.model, input: "Reply OK.", max_output_tokens: 16, store: false } : {
|
|
17142
|
+
model: input.model,
|
|
17143
|
+
messages: [{ role: "user", content: "Reply OK." }],
|
|
17144
|
+
max_tokens: 1
|
|
17145
|
+
}
|
|
17146
|
+
),
|
|
17147
|
+
redirect: "error",
|
|
17148
|
+
signal: AbortSignal.timeout(1e4)
|
|
17149
|
+
}
|
|
17150
|
+
).catch(() => null);
|
|
17151
|
+
if (response?.status === 400 && input.name === "XAI_API_KEY") {
|
|
17152
|
+
const error48 = external_exports.object({ error: external_exports.string() }).safeParse(await response.json().catch(() => null));
|
|
17153
|
+
return error48.success && error48.data.error.startsWith("Incorrect API key provided.") ? "rejected" : "unknown";
|
|
17154
|
+
}
|
|
17155
|
+
await response?.body?.cancel();
|
|
17156
|
+
if (!response) return "unknown";
|
|
17157
|
+
if (response.ok) return "usable";
|
|
17158
|
+
return [401, 402, 403, 429].includes(response.status) ? "rejected" : "unknown";
|
|
17159
|
+
}
|
|
17160
|
+
|
|
17161
|
+
// utils/time.ts
|
|
17162
|
+
var TIMEOUT_DISABLED = "none";
|
|
17163
|
+
var TIME_STRING_REGEX = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
|
|
17164
|
+
function parseTimeString(input) {
|
|
17165
|
+
const match = input.match(TIME_STRING_REGEX);
|
|
17166
|
+
if (!match || !match[1] && !match[2] && !match[3]) return null;
|
|
17167
|
+
const hours = parseInt(match[1] || "0", 10);
|
|
17168
|
+
const minutes = parseInt(match[2] || "0", 10);
|
|
17169
|
+
const seconds = parseInt(match[3] || "0", 10);
|
|
17170
|
+
return (hours * 3600 + minutes * 60 + seconds) * 1e3;
|
|
17171
|
+
}
|
|
17172
|
+
function isValidTimeString(input) {
|
|
17173
|
+
return parseTimeString(input) !== null;
|
|
17174
|
+
}
|
|
16991
17175
|
export {
|
|
16992
17176
|
APPROVAL_CHECK_NAME,
|
|
16993
17177
|
AUTO_EFFICIENT,
|
|
@@ -17012,6 +17196,7 @@ export {
|
|
|
17012
17196
|
ROUTER_TIERS,
|
|
17013
17197
|
RUN_STATUS_CHECK_NAME,
|
|
17014
17198
|
SUBSIDY_RUNG,
|
|
17199
|
+
SubscriptionCredentialError,
|
|
17015
17200
|
TIMEOUT_DISABLED,
|
|
17016
17201
|
autoLadder,
|
|
17017
17202
|
autoRoutedSlug,
|
|
@@ -17021,8 +17206,11 @@ export {
|
|
|
17021
17206
|
configFields,
|
|
17022
17207
|
configResponseSchema,
|
|
17023
17208
|
configValueSchema,
|
|
17209
|
+
countOutstandingPullfrogThreads,
|
|
17024
17210
|
createLeapingProgressComment,
|
|
17025
17211
|
createRunStatusCheck,
|
|
17212
|
+
credentialAccessSchema,
|
|
17213
|
+
credentialCandidateSchema,
|
|
17026
17214
|
decodeJwtExpMs,
|
|
17027
17215
|
defaultAutoTier,
|
|
17028
17216
|
deleteProgressCommentApi,
|
|
@@ -17056,6 +17244,7 @@ export {
|
|
|
17056
17244
|
parseModel,
|
|
17057
17245
|
parseTimeString,
|
|
17058
17246
|
parseXaiAuthBody,
|
|
17247
|
+
probeSubscription,
|
|
17059
17248
|
providers,
|
|
17060
17249
|
pullfrogMcpName,
|
|
17061
17250
|
refreshCodexAuthBody,
|
|
@@ -17071,9 +17260,16 @@ export {
|
|
|
17071
17260
|
runStatusCheckNeedsFinalizing,
|
|
17072
17261
|
rungLabel,
|
|
17073
17262
|
rungPosition,
|
|
17263
|
+
selectedCredentialSchema,
|
|
17074
17264
|
stringifyCodexAuthBody,
|
|
17075
17265
|
stringifyXaiAuthBody,
|
|
17076
17266
|
stripExistingFooter,
|
|
17267
|
+
subscriptionIdentity,
|
|
17268
|
+
subscriptionInputSchema,
|
|
17269
|
+
subscriptionLabel,
|
|
17270
|
+
subscriptionListSchema,
|
|
17271
|
+
subscriptionNameSchema,
|
|
17272
|
+
subscriptionSchema,
|
|
17077
17273
|
truncateAtLineBoundary,
|
|
17078
17274
|
updateProgressComment,
|
|
17079
17275
|
verifyCredential
|
package/dist/mcp/review.d.ts
CHANGED
|
@@ -23,20 +23,6 @@ export declare const TRANSIENT_REVIEW_RETRY_DELAYS_MS: number[];
|
|
|
23
23
|
*/
|
|
24
24
|
export declare function commentableLinesForFile(patch: string | undefined): CommentableLines;
|
|
25
25
|
export declare function buildCommentableMap(ctx: ToolContext, pullNumber: number): Promise<Map<string, CommentableLines>>;
|
|
26
|
-
/**
|
|
27
|
-
* count unresolved review threads on a PR whose root comment was authored by
|
|
28
|
-
* Pullfrog's bot. this is the full set of open Pullfrog findings on the PR —
|
|
29
|
-
* the basis for both the never-approve-with-outstanding-issues invariant (the
|
|
30
|
-
* approval gate below) and the `pullfrog-approval` status verdict. it is a
|
|
31
|
-
* function of all open findings, NOT just the latest commit's delta.
|
|
32
|
-
*
|
|
33
|
-
* outdated-but-unresolved threads still count — GitHub marks a thread
|
|
34
|
-
* `[OUTDATED]` when the anchor line moved (reformat, rename, force-push), which
|
|
35
|
-
* is not the same as the concern being addressed. human-reviewer threads are
|
|
36
|
-
* excluded: they belong to those reviewers to resolve. walks every page so a
|
|
37
|
-
* long-lived PR with >100 threads can't hide an outstanding finding.
|
|
38
|
-
*/
|
|
39
|
-
export declare function countOutstandingPullfrogThreads(ctx: ToolContext, pullNumber: number): Promise<number>;
|
|
40
26
|
/**
|
|
41
27
|
* proactive approve-when-clean for the Fix-all / Fix-👍s flow (`fix_review`
|
|
42
28
|
* trigger). when such a run completes successfully and every Pullfrog-originated
|
|
@@ -63,6 +63,7 @@ export declare function commercialPaywallBody(params: {
|
|
|
63
63
|
reason: CommercialRefusal;
|
|
64
64
|
ownerLogin: string;
|
|
65
65
|
url: string;
|
|
66
|
+
freshReply?: boolean | undefined;
|
|
66
67
|
}): string;
|
|
67
68
|
/**
|
|
68
69
|
* commercial-gate copy for action runs, linked to the account billing card.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function clearInstalledSubscription(name: "CODEX_AUTH_JSON" | "GROK_AUTH_JSON"): void;
|
|
1
2
|
/** sandbox-hidden home for pullfrog-managed on-disk secrets in CI. bash via
|
|
2
3
|
* MCP shell tmpfs-overlays this path; opencode's internal auth module
|
|
3
4
|
* bypasses external_directory and reaches the real file. mirrors the
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RunContextData } from "./runContextData.ts";
|
|
2
|
+
/** load one subscription per provider for model discovery; keep the pool unflattened. */
|
|
3
|
+
export declare function initializeCredentialPool(ctx: RunContextData, model?: string): Promise<void>;
|
|
4
|
+
export declare function resolvePoolModel(input: {
|
|
5
|
+
codexAgent: boolean;
|
|
6
|
+
}): string | undefined;
|
|
7
|
+
export declare function selectConfiguredCredential(input: {
|
|
8
|
+
ctx: RunContextData;
|
|
9
|
+
model: string | undefined;
|
|
10
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** the slice of a run or webhook context the query needs — shared by the action and the server. */
|
|
2
|
+
export type OutstandingThreadsCtx = {
|
|
3
|
+
octokit: {
|
|
4
|
+
graphql: <T>(query: string, variables: Record<string, unknown>) => Promise<T>;
|
|
5
|
+
};
|
|
6
|
+
repo: {
|
|
7
|
+
owner: string;
|
|
8
|
+
name: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* count unresolved review threads on a PR whose root comment was authored by
|
|
13
|
+
* Pullfrog's bot. this is the full set of open Pullfrog findings on the PR —
|
|
14
|
+
* the basis for both the never-approve-with-outstanding-issues invariant (the
|
|
15
|
+
* approval gate in create_pull_request_review) and the `pullfrog-approval`
|
|
16
|
+
* status verdict. it is a function of all open findings, NOT just the latest
|
|
17
|
+
* commit's delta.
|
|
18
|
+
*
|
|
19
|
+
* outdated-but-unresolved threads still count — GitHub marks a thread
|
|
20
|
+
* `[OUTDATED]` when the anchor line moved (reformat, rename, force-push), which
|
|
21
|
+
* is not the same as the concern being addressed. human-reviewer threads are
|
|
22
|
+
* excluded: they belong to those reviewers to resolve. walks every page so a
|
|
23
|
+
* long-lived PR with >100 threads can't hide an outstanding finding.
|
|
24
|
+
*/
|
|
25
|
+
export declare function countOutstandingPullfrogThreads(ctx: OutstandingThreadsCtx, pullNumber: number): Promise<number>;
|
package/dist/utils/payload.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
|
|
|
11
11
|
tier: "minimal" | "light" | "standard" | "deep";
|
|
12
12
|
stakes: number;
|
|
13
13
|
workload: number;
|
|
14
|
-
source: "scorer" | "heuristic" | "fixed";
|
|
14
|
+
source: "jev" | "scorer" | "heuristic" | "fixed";
|
|
15
15
|
rationale: string;
|
|
16
16
|
} | undefined;
|
|
17
17
|
effort?: string | number | undefined;
|
|
@@ -65,7 +65,7 @@ export declare function resolvePayload(resolvedPromptInput: ResolvedPromptInput,
|
|
|
65
65
|
tier: "minimal" | "light" | "standard" | "deep";
|
|
66
66
|
stakes: number;
|
|
67
67
|
workload: number;
|
|
68
|
-
source: "scorer" | "heuristic" | "fixed";
|
|
68
|
+
source: "jev" | "scorer" | "heuristic" | "fixed";
|
|
69
69
|
rationale: string;
|
|
70
70
|
} | undefined;
|
|
71
71
|
effort: number | undefined;
|
|
@@ -2,6 +2,7 @@ import type { PushPermission, ShellPermission } from "../external.ts";
|
|
|
2
2
|
import type { RouterTier } from "../models.ts";
|
|
3
3
|
import type { CommercialRefusal } from "./billingErrors.ts";
|
|
4
4
|
import type { RepoContext } from "./github.ts";
|
|
5
|
+
import type { CredentialAccess } from "./subscriptionCredentials.ts";
|
|
5
6
|
export interface Mode {
|
|
6
7
|
id: string;
|
|
7
8
|
name: string;
|
|
@@ -57,6 +58,7 @@ export interface RepoSettings {
|
|
|
57
58
|
*/
|
|
58
59
|
export type AccountPlan = "none" | "payg";
|
|
59
60
|
export interface RunContext {
|
|
61
|
+
credentialAccess?: CredentialAccess | undefined;
|
|
60
62
|
settings: RepoSettings;
|
|
61
63
|
apiToken: string;
|
|
62
64
|
oss: boolean;
|
|
@@ -3,7 +3,9 @@ import type { RouterTier } from "../models.ts";
|
|
|
3
3
|
import type { CommercialRefusal } from "./billingErrors.ts";
|
|
4
4
|
import { type OctokitWithPlugins } from "./github.ts";
|
|
5
5
|
import { type AccountPlan, type RepoSettings } from "./runContext.ts";
|
|
6
|
+
import type { CredentialAccess } from "./subscriptionCredentials.ts";
|
|
6
7
|
export interface RunContextData {
|
|
8
|
+
credentialAccess?: CredentialAccess | undefined;
|
|
7
9
|
repo: {
|
|
8
10
|
owner: string;
|
|
9
11
|
name: string;
|
package/dist/utils/setup.d.ts
CHANGED
|
@@ -5,9 +5,15 @@ export interface SetupOptions {
|
|
|
5
5
|
tempDir: string;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Create a shared temp directory for the action
|
|
8
|
+
* Create a shared temp directory for the action, removed when the run's scope
|
|
9
|
+
* exits. a persistent self-hosted runner never wipes `/tmp`, so every run used
|
|
10
|
+
* to leave its tree (the OpenCode install alone is hundreds of MB) until the
|
|
11
|
+
* disk filled and every job on the runner died.
|
|
9
12
|
*/
|
|
10
|
-
export declare function createTempDirectory():
|
|
13
|
+
export declare function createTempDirectory(): {
|
|
14
|
+
path: string;
|
|
15
|
+
[Symbol.dispose]: () => void;
|
|
16
|
+
};
|
|
11
17
|
/**
|
|
12
18
|
* snapshot-and-delete the GHA runner's known credential leak surfaces inside
|
|
13
19
|
* `$RUNNER_TEMP` before the agent spawns. without this, a shell-capable agent
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const subscriptionNameSchema: z.ZodEnum<{
|
|
3
|
+
CLAUDE_CODE_OAUTH_TOKEN: "CLAUDE_CODE_OAUTH_TOKEN";
|
|
4
|
+
CODEX_AUTH_JSON: "CODEX_AUTH_JSON";
|
|
5
|
+
GROK_AUTH_JSON: "GROK_AUTH_JSON";
|
|
6
|
+
}>;
|
|
7
|
+
export type SubscriptionName = z.infer<typeof subscriptionNameSchema>;
|
|
8
|
+
export declare const subscriptionSchema: z.ZodObject<{
|
|
9
|
+
id: z.ZodString;
|
|
10
|
+
credentialId: z.ZodString;
|
|
11
|
+
name: z.ZodEnum<{
|
|
12
|
+
CLAUDE_CODE_OAUTH_TOKEN: "CLAUDE_CODE_OAUTH_TOKEN";
|
|
13
|
+
CODEX_AUTH_JSON: "CODEX_AUTH_JSON";
|
|
14
|
+
GROK_AUTH_JSON: "GROK_AUTH_JSON";
|
|
15
|
+
}>;
|
|
16
|
+
label: z.ZodString;
|
|
17
|
+
owner: z.ZodString;
|
|
18
|
+
inherited: z.ZodBoolean;
|
|
19
|
+
shared: z.ZodBoolean;
|
|
20
|
+
registeredAt: z.ZodString;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export type Subscription = z.infer<typeof subscriptionSchema>;
|
|
23
|
+
export declare const subscriptionListSchema: z.ZodObject<{
|
|
24
|
+
subscriptions: z.ZodArray<z.ZodObject<{
|
|
25
|
+
id: z.ZodString;
|
|
26
|
+
credentialId: z.ZodString;
|
|
27
|
+
name: z.ZodEnum<{
|
|
28
|
+
CLAUDE_CODE_OAUTH_TOKEN: "CLAUDE_CODE_OAUTH_TOKEN";
|
|
29
|
+
CODEX_AUTH_JSON: "CODEX_AUTH_JSON";
|
|
30
|
+
GROK_AUTH_JSON: "GROK_AUTH_JSON";
|
|
31
|
+
}>;
|
|
32
|
+
label: z.ZodString;
|
|
33
|
+
owner: z.ZodString;
|
|
34
|
+
inherited: z.ZodBoolean;
|
|
35
|
+
shared: z.ZodBoolean;
|
|
36
|
+
registeredAt: z.ZodString;
|
|
37
|
+
}, z.core.$strip>>;
|
|
38
|
+
writable: z.ZodBoolean;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
export declare const subscriptionInputSchema: z.ZodObject<{
|
|
41
|
+
name: z.ZodEnum<{
|
|
42
|
+
CLAUDE_CODE_OAUTH_TOKEN: "CLAUDE_CODE_OAUTH_TOKEN";
|
|
43
|
+
CODEX_AUTH_JSON: "CODEX_AUTH_JSON";
|
|
44
|
+
GROK_AUTH_JSON: "GROK_AUTH_JSON";
|
|
45
|
+
}>;
|
|
46
|
+
value: z.ZodString;
|
|
47
|
+
replaceId: z.ZodOptional<z.ZodString>;
|
|
48
|
+
}, z.core.$strip>;
|
|
49
|
+
export declare const credentialCandidateSchema: z.ZodObject<{
|
|
50
|
+
id: z.ZodString;
|
|
51
|
+
name: z.ZodString;
|
|
52
|
+
source: z.ZodEnum<{
|
|
53
|
+
repo: "repo";
|
|
54
|
+
account: "account";
|
|
55
|
+
personal: "personal";
|
|
56
|
+
}>;
|
|
57
|
+
}, z.core.$strip>;
|
|
58
|
+
export type CredentialCandidate = z.infer<typeof credentialCandidateSchema>;
|
|
59
|
+
export declare const credentialAccessSchema: z.ZodObject<{
|
|
60
|
+
token: z.ZodString;
|
|
61
|
+
candidates: z.ZodArray<z.ZodObject<{
|
|
62
|
+
id: z.ZodString;
|
|
63
|
+
name: z.ZodString;
|
|
64
|
+
source: z.ZodEnum<{
|
|
65
|
+
repo: "repo";
|
|
66
|
+
account: "account";
|
|
67
|
+
personal: "personal";
|
|
68
|
+
}>;
|
|
69
|
+
}, z.core.$strip>>;
|
|
70
|
+
}, z.core.$strip>;
|
|
71
|
+
export type CredentialAccess = z.infer<typeof credentialAccessSchema>;
|
|
72
|
+
export declare const selectedCredentialSchema: z.ZodObject<{
|
|
73
|
+
name: z.ZodString;
|
|
74
|
+
value: z.ZodString;
|
|
75
|
+
receipt: z.ZodString;
|
|
76
|
+
}, z.core.$strip>;
|
|
77
|
+
export declare function subscriptionLabel(input: {
|
|
78
|
+
email: string | null;
|
|
79
|
+
suffix: string;
|
|
80
|
+
}): string;
|