pullfrog 0.1.66 → 0.1.68
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 +72 -149
- package/dist/cli.mjs +461 -126
- package/dist/effort.d.ts +10 -0
- package/dist/external.d.ts +9 -1
- package/dist/index.js +345 -63
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal.js +219 -2
- package/dist/models.d.ts +2 -0
- package/dist/toolState.d.ts +1 -1
- package/dist/utils/apiKeys.d.ts +34 -0
- package/dist/utils/billingErrors.d.ts +1 -2
- package/dist/utils/buildPullfrogFooter.d.ts +4 -1
- package/dist/utils/payload.d.ts +1 -0
- package/dist/utils/providerErrors.d.ts +8 -0
- package/dist/utils/proxy.d.ts +24 -0
- package/dist/utils/runContext.d.ts +7 -0
- package/dist/utils/runContextData.d.ts +9 -0
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -525,15 +525,15 @@ var require_file_command = __commonJS({
|
|
|
525
525
|
}
|
|
526
526
|
exports.issueFileCommand = issueFileCommand;
|
|
527
527
|
function prepareKeyValueMessage(key, value2) {
|
|
528
|
-
const
|
|
528
|
+
const delimiter3 = `ghadelimiter_${crypto5.randomUUID()}`;
|
|
529
529
|
const convertedValue = (0, utils_1.toCommandValue)(value2);
|
|
530
|
-
if (key.includes(
|
|
531
|
-
throw new Error(`Unexpected input: name should not contain the delimiter "${
|
|
530
|
+
if (key.includes(delimiter3)) {
|
|
531
|
+
throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter3}"`);
|
|
532
532
|
}
|
|
533
|
-
if (convertedValue.includes(
|
|
534
|
-
throw new Error(`Unexpected input: value should not contain the delimiter "${
|
|
533
|
+
if (convertedValue.includes(delimiter3)) {
|
|
534
|
+
throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter3}"`);
|
|
535
535
|
}
|
|
536
|
-
return `${key}<<${
|
|
536
|
+
return `${key}<<${delimiter3}${os2.EOL}${convertedValue}${os2.EOL}${delimiter3}`;
|
|
537
537
|
}
|
|
538
538
|
exports.prepareKeyValueMessage = prepareKeyValueMessage;
|
|
539
539
|
}
|
|
@@ -11973,10 +11973,10 @@ var require_headers = __commonJS({
|
|
|
11973
11973
|
const lowercaseName = name.toLowerCase();
|
|
11974
11974
|
const exists = this[kHeadersMap].get(lowercaseName);
|
|
11975
11975
|
if (exists) {
|
|
11976
|
-
const
|
|
11976
|
+
const delimiter3 = lowercaseName === "cookie" ? "; " : ", ";
|
|
11977
11977
|
this[kHeadersMap].set(lowercaseName, {
|
|
11978
11978
|
name: exists.name,
|
|
11979
|
-
value: `${exists.value}${
|
|
11979
|
+
value: `${exists.value}${delimiter3}${value2}`
|
|
11980
11980
|
});
|
|
11981
11981
|
} else {
|
|
11982
11982
|
this[kHeadersMap].set(lowercaseName, { name, value: value2 });
|
|
@@ -46981,10 +46981,10 @@ var require_headers2 = __commonJS({
|
|
|
46981
46981
|
const lowercaseName = isLowerCase ? name : name.toLowerCase();
|
|
46982
46982
|
const exists = this.headersMap.get(lowercaseName);
|
|
46983
46983
|
if (exists) {
|
|
46984
|
-
const
|
|
46984
|
+
const delimiter3 = lowercaseName === "cookie" ? "; " : ", ";
|
|
46985
46985
|
this.headersMap.set(lowercaseName, {
|
|
46986
46986
|
name: exists.name,
|
|
46987
|
-
value: `${exists.value}${
|
|
46987
|
+
value: `${exists.value}${delimiter3}${value2}`
|
|
46988
46988
|
});
|
|
46989
46989
|
} else {
|
|
46990
46990
|
this.headersMap.set(lowercaseName, { name, value: value2 });
|
|
@@ -59293,8 +59293,8 @@ var init_regexes = __esm({
|
|
|
59293
59293
|
_emoji = `^[\\p{Extended_Pictographic}\\p{Emoji_Component}]+$`;
|
|
59294
59294
|
ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
59295
59295
|
ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
59296
|
-
mac = (
|
|
59297
|
-
const escapedDelim = escapeRegex(
|
|
59296
|
+
mac = (delimiter3) => {
|
|
59297
|
+
const escapedDelim = escapeRegex(delimiter3 ?? ":");
|
|
59298
59298
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
59299
59299
|
};
|
|
59300
59300
|
cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -102436,10 +102436,10 @@ var require_turndown_cjs = __commonJS({
|
|
|
102436
102436
|
if (!content) return "";
|
|
102437
102437
|
content = content.replace(/\r?\n|\r/g, " ");
|
|
102438
102438
|
var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? " " : "";
|
|
102439
|
-
var
|
|
102439
|
+
var delimiter3 = "`";
|
|
102440
102440
|
var matches = content.match(/`+/gm) || [];
|
|
102441
|
-
while (matches.indexOf(
|
|
102442
|
-
return
|
|
102441
|
+
while (matches.indexOf(delimiter3) !== -1) delimiter3 = delimiter3 + "`";
|
|
102442
|
+
return delimiter3 + extraSpace + content + extraSpace + delimiter3;
|
|
102443
102443
|
}
|
|
102444
102444
|
};
|
|
102445
102445
|
rules.image = {
|
|
@@ -104189,8 +104189,8 @@ var require_common = __commonJS({
|
|
|
104189
104189
|
}
|
|
104190
104190
|
return debug4;
|
|
104191
104191
|
}
|
|
104192
|
-
function extend3(namespace,
|
|
104193
|
-
const newDebug = createDebug(this.namespace + (typeof
|
|
104192
|
+
function extend3(namespace, delimiter3) {
|
|
104193
|
+
const newDebug = createDebug(this.namespace + (typeof delimiter3 === "undefined" ? ":" : delimiter3) + namespace);
|
|
104194
104194
|
newDebug.log = this.log;
|
|
104195
104195
|
return newDebug;
|
|
104196
104196
|
}
|
|
@@ -108809,9 +108809,9 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
|
108809
108809
|
|
|
108810
108810
|
// utils/codexAuth.ts
|
|
108811
108811
|
import { spawn } from "node:child_process";
|
|
108812
|
-
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
108812
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
108813
108813
|
import { tmpdir } from "node:os";
|
|
108814
|
-
import { join } from "node:path";
|
|
108814
|
+
import { delimiter, join } from "node:path";
|
|
108815
108815
|
|
|
108816
108816
|
// utils/oauthShared.ts
|
|
108817
108817
|
var OAuthInvalidGrantError = class extends Error {
|
|
@@ -108960,11 +108960,60 @@ async function mintCodexAuth(options) {
|
|
|
108960
108960
|
}
|
|
108961
108961
|
}
|
|
108962
108962
|
var SIGTERM_GRACE_MS = 5e3;
|
|
108963
|
+
var DEVICE_AUTH_ARGS = ["login", "--device-auth"];
|
|
108964
|
+
var DEFAULT_PATHEXT = ".COM;.EXE;.BAT;.CMD";
|
|
108965
|
+
function envValue(env2, name) {
|
|
108966
|
+
if (env2[name] !== void 0) return env2[name];
|
|
108967
|
+
const key = Object.keys(env2).find((candidate) => candidate.toUpperCase() === name.toUpperCase());
|
|
108968
|
+
return key === void 0 ? void 0 : env2[key];
|
|
108969
|
+
}
|
|
108970
|
+
function commandProcessor(env2) {
|
|
108971
|
+
return envValue(env2, "ComSpec") ?? join(envValue(env2, "SystemRoot") ?? "C:\\Windows", "system32", "cmd.exe");
|
|
108972
|
+
}
|
|
108973
|
+
function resolveSpawnTarget(params) {
|
|
108974
|
+
if (process.platform !== "win32") {
|
|
108975
|
+
return { file: params.command, args: params.args, wrapped: false };
|
|
108976
|
+
}
|
|
108977
|
+
const extensions2 = (envValue(params.env, "PATHEXT") ?? DEFAULT_PATHEXT).split(";").filter(Boolean);
|
|
108978
|
+
for (const directory of (envValue(params.env, "PATH") ?? "").split(delimiter).filter(Boolean)) {
|
|
108979
|
+
for (const extension of extensions2) {
|
|
108980
|
+
const candidate = join(directory, `${params.command}${extension.toLowerCase()}`);
|
|
108981
|
+
if (!existsSync(candidate)) continue;
|
|
108982
|
+
if (!/\.(cmd|bat)$/i.test(candidate)) {
|
|
108983
|
+
return { file: candidate, args: params.args, wrapped: false };
|
|
108984
|
+
}
|
|
108985
|
+
const command = [`"${candidate}"`, ...params.args].join(" ");
|
|
108986
|
+
return {
|
|
108987
|
+
file: commandProcessor(params.env),
|
|
108988
|
+
args: ["/d", "/s", "/c", `"${command}"`],
|
|
108989
|
+
wrapped: true
|
|
108990
|
+
};
|
|
108991
|
+
}
|
|
108992
|
+
}
|
|
108993
|
+
return null;
|
|
108994
|
+
}
|
|
108995
|
+
function codexNotFoundMessage(env2) {
|
|
108996
|
+
const install = "install it with `npm i -g @openai/codex` or see https://developers.openai.com/codex/cli for other install options.";
|
|
108997
|
+
if (process.platform !== "win32") return `codex CLI not found on PATH. ${install}`;
|
|
108998
|
+
const extensions2 = (envValue(env2, "PATHEXT") ?? DEFAULT_PATHEXT).split(";").filter(Boolean).join(" ");
|
|
108999
|
+
return `codex CLI not found on PATH (searched every PATH entry for codex with ${extensions2}). a working \`codex --version\` in a shell does not prove Node can spawn it. ${install}`;
|
|
109000
|
+
}
|
|
108963
109001
|
function runDeviceAuth(input2) {
|
|
108964
109002
|
return new Promise((resolve3, reject) => {
|
|
108965
|
-
const
|
|
109003
|
+
const target = resolveSpawnTarget({
|
|
109004
|
+
command: "codex",
|
|
109005
|
+
args: DEVICE_AUTH_ARGS,
|
|
109006
|
+
env: process.env
|
|
109007
|
+
});
|
|
109008
|
+
if (!target) {
|
|
109009
|
+
reject(new Error(codexNotFoundMessage(process.env)));
|
|
109010
|
+
return;
|
|
109011
|
+
}
|
|
109012
|
+
const child = spawn(target.file, target.args, {
|
|
108966
109013
|
env: { ...process.env, CODEX_HOME: input2.codexHome },
|
|
108967
|
-
stdio: ["ignore", input2.childStdio, input2.childStdio]
|
|
109014
|
+
stdio: ["ignore", input2.childStdio, input2.childStdio],
|
|
109015
|
+
windowsVerbatimArguments: target.wrapped,
|
|
109016
|
+
windowsHide: true
|
|
108968
109017
|
});
|
|
108969
109018
|
if (input2.childStdio === "pipe") {
|
|
108970
109019
|
const onLine = input2.onChildLine ?? (() => {
|
|
@@ -108976,6 +109025,10 @@ function runDeviceAuth(input2) {
|
|
|
108976
109025
|
let timedOut = false;
|
|
108977
109026
|
const timeoutTimer = setTimeout(() => {
|
|
108978
109027
|
timedOut = true;
|
|
109028
|
+
if (target.wrapped && child.pid) {
|
|
109029
|
+
spawn("taskkill", ["/pid", String(child.pid), "/t", "/f"], { stdio: "ignore" });
|
|
109030
|
+
return;
|
|
109031
|
+
}
|
|
108979
109032
|
child.kill("SIGTERM");
|
|
108980
109033
|
killTimer = setTimeout(() => child.kill("SIGKILL"), SIGTERM_GRACE_MS);
|
|
108981
109034
|
}, input2.timeoutMs);
|
|
@@ -108983,7 +109036,7 @@ function runDeviceAuth(input2) {
|
|
|
108983
109036
|
clearTimeout(timeoutTimer);
|
|
108984
109037
|
if (killTimer) clearTimeout(killTimer);
|
|
108985
109038
|
const errno = err;
|
|
108986
|
-
const message = errno.code === "ENOENT" ?
|
|
109039
|
+
const message = errno.code === "ENOENT" ? codexNotFoundMessage(process.env) : `failed to spawn codex: ${errno.message}`;
|
|
108987
109040
|
reject(new Error(message));
|
|
108988
109041
|
});
|
|
108989
109042
|
child.on("close", (code, signal) => {
|
|
@@ -109797,7 +109850,7 @@ var import_arg2 = __toESM(require_arg(), 1);
|
|
|
109797
109850
|
import { dirname as dirname6 } from "node:path";
|
|
109798
109851
|
|
|
109799
109852
|
// main.ts
|
|
109800
|
-
import { existsSync as
|
|
109853
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2 } from "node:fs";
|
|
109801
109854
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
109802
109855
|
import { join as join28 } from "node:path";
|
|
109803
109856
|
|
|
@@ -110155,6 +110208,7 @@ import { performance as performance5 } from "node:perf_hooks";
|
|
|
110155
110208
|
|
|
110156
110209
|
// effort.ts
|
|
110157
110210
|
var DEFAULT_EFFORT_POSITION = 0.5;
|
|
110211
|
+
var SUBSIDY_RUNG = "high";
|
|
110158
110212
|
var EFFORT_ALIASES = {
|
|
110159
110213
|
low: 0,
|
|
110160
110214
|
medium: 0.25,
|
|
@@ -110479,6 +110533,69 @@ var providers = {
|
|
|
110479
110533
|
}
|
|
110480
110534
|
}
|
|
110481
110535
|
}),
|
|
110536
|
+
// the same models as `moonshotai` above, billed against a Kimi membership
|
|
110537
|
+
// instead of a Moonshot API balance — a separate endpoint, separate model
|
|
110538
|
+
// ids and a separate key, which is why it is a provider rather than a second
|
|
110539
|
+
// `envVars` entry. no provider injection is needed: models.dev carries
|
|
110540
|
+
// `kimi-for-coding` (api `https://api.kimi.com/coding/v1`, npm
|
|
110541
|
+
// `@ai-sdk/anthropic`) and opencode's env loop enables it from a bare
|
|
110542
|
+
// `KIMI_API_KEY`, verified against our pinned opencode-ai@1.18.5 — all four
|
|
110543
|
+
// ids list in `opencode models` and a run reaches Kimi's own auth check.
|
|
110544
|
+
//
|
|
110545
|
+
// NO `openRouterResolve` ON PURPOSE. OpenRouter cannot serve a Kimi
|
|
110546
|
+
// membership, so a Router path here would silently bill the wallet for
|
|
110547
|
+
// Moonshot pay-as-you-go under a slug picked for the opposite reason. The
|
|
110548
|
+
// absence is load-bearing: `isCardGatedModel` reads it as "not Router-
|
|
110549
|
+
// resolvable", `decideModelAccess` answers an explicit pick with the
|
|
110550
|
+
// `router` copy ("add your own provider key"), and run-context clamps a
|
|
110551
|
+
// keyless Router pick to the default subsidy model with `noRouterPath`.
|
|
110552
|
+
"kimi-for-coding": provider({
|
|
110553
|
+
// "Kimi Code" is the product name on kimi.com/code and in the console the
|
|
110554
|
+
// key is minted from. The provider KEY has to stay `kimi-for-coding` — it
|
|
110555
|
+
// is models.dev's id, so it is what `enabled_providers` and every
|
|
110556
|
+
// `resolve` prefix must spell.
|
|
110557
|
+
displayName: "Kimi Code",
|
|
110558
|
+
envVars: ["KIMI_API_KEY"],
|
|
110559
|
+
models: {
|
|
110560
|
+
// the tier each model needs is in `description` because Kimi answers an
|
|
110561
|
+
// out-of-tier request with 401 — indistinguishable from a bad key by
|
|
110562
|
+
// status alone, and only `isKimiPlanTierError` tells them apart after the
|
|
110563
|
+
// fact. saying it in the picker is the half that stops the run happening.
|
|
110564
|
+
"kimi-k3": {
|
|
110565
|
+
displayName: "Kimi K3",
|
|
110566
|
+
description: "1M context, but only on Allegretto and above \xB7 Moderato caps it at 256K",
|
|
110567
|
+
resolve: "kimi-for-coding/k3",
|
|
110568
|
+
effort: ["low", "high", "max"],
|
|
110569
|
+
subagentModel: "kimi-k2"
|
|
110570
|
+
},
|
|
110571
|
+
// `preferred` sits on the 256K variant rather than the 1M flagship, which
|
|
110572
|
+
// inverts the usual "top tier wins" rule for a reason specific to Kimi:
|
|
110573
|
+
// below Allegretto the two are the SAME 256K ceiling and `k3` charges
|
|
110574
|
+
// roughly double the quota for it, so on the median tier the flagship is
|
|
110575
|
+
// strictly dominated rather than merely pricier. This flag seeds the
|
|
110576
|
+
// onboarding pick (`getRecommendedSlug`) and wins key-only auto-select
|
|
110577
|
+
// (`autoSelectModel`), which are exactly the two moments nobody has
|
|
110578
|
+
// chosen yet.
|
|
110579
|
+
"kimi-k3-256k": {
|
|
110580
|
+
displayName: "Kimi K3 256K",
|
|
110581
|
+
description: "Same model at 256K for ~half the quota \xB7 Moderato or above",
|
|
110582
|
+
resolve: "kimi-for-coding/k3-256k",
|
|
110583
|
+
effort: ["low", "high", "max"],
|
|
110584
|
+
preferred: true,
|
|
110585
|
+
subagentModel: "kimi-k2"
|
|
110586
|
+
},
|
|
110587
|
+
"kimi-k2": {
|
|
110588
|
+
displayName: "Kimi K2",
|
|
110589
|
+
description: "Included in every Kimi membership tier",
|
|
110590
|
+
resolve: "kimi-for-coding/kimi-for-coding"
|
|
110591
|
+
},
|
|
110592
|
+
"kimi-k2-highspeed": {
|
|
110593
|
+
displayName: "Kimi K2 HighSpeed",
|
|
110594
|
+
description: "~6x output speed for ~3x quota \xB7 needs Allegretto or above",
|
|
110595
|
+
resolve: "kimi-for-coding/kimi-for-coding-highspeed"
|
|
110596
|
+
}
|
|
110597
|
+
}
|
|
110598
|
+
}),
|
|
110482
110599
|
opencode: provider({
|
|
110483
110600
|
displayName: "OpenCode Zen",
|
|
110484
110601
|
envVars: ["OPENCODE_API_KEY"],
|
|
@@ -110495,6 +110612,15 @@ var providers = {
|
|
|
110495
110612
|
// the model does cost nothing.
|
|
110496
110613
|
isFree: true
|
|
110497
110614
|
},
|
|
110615
|
+
// Zen meters Fable like any other model, so this route reaches it without
|
|
110616
|
+
// the Anthropic access grant `anthropic/claude-fable` still needs.
|
|
110617
|
+
"claude-fable": {
|
|
110618
|
+
displayName: "Claude Fable",
|
|
110619
|
+
resolve: "opencode/claude-fable-5-1",
|
|
110620
|
+
effort: ["low", "medium", "high", "xhigh", "max"],
|
|
110621
|
+
openRouterResolve: "openrouter/~anthropic/claude-fable-latest",
|
|
110622
|
+
subagentModel: "claude-sonnet"
|
|
110623
|
+
},
|
|
110498
110624
|
"claude-opus": {
|
|
110499
110625
|
displayName: "Claude Opus",
|
|
110500
110626
|
resolve: "opencode/claude-opus-5",
|
|
@@ -110608,6 +110734,17 @@ var providers = {
|
|
|
110608
110734
|
effort: ["minimal", "low", "medium", "high"],
|
|
110609
110735
|
openRouterResolve: "openrouter/google/gemini-3.6-flash"
|
|
110610
110736
|
},
|
|
110737
|
+
// Zen serves K3, but rule 7 can only move a mirror when its upstream moves,
|
|
110738
|
+
// so the K3 generation could never reach this block by bumping `kimi-k2`.
|
|
110739
|
+
"kimi-k3": {
|
|
110740
|
+
displayName: "Kimi K3",
|
|
110741
|
+
resolve: "opencode/kimi-k3",
|
|
110742
|
+
// Zen publishes a single rung for K3 where OpenRouter publishes three.
|
|
110743
|
+
effort: ["max"],
|
|
110744
|
+
openRouterEffort: ["low", "high", "max"],
|
|
110745
|
+
openRouterResolve: "openrouter/moonshotai/kimi-k3",
|
|
110746
|
+
subagentModel: "kimi-k2"
|
|
110747
|
+
},
|
|
110611
110748
|
"kimi-k2": {
|
|
110612
110749
|
displayName: "Kimi K2",
|
|
110613
110750
|
// k2.7-code is UNDEPLOYED on Zen — still listed in /zen/v1/models, but
|
|
@@ -110619,25 +110756,58 @@ var providers = {
|
|
|
110619
110756
|
resolve: "opencode/kimi-k2.6",
|
|
110620
110757
|
openRouterResolve: "openrouter/moonshotai/kimi-k2.7-code"
|
|
110621
110758
|
},
|
|
110759
|
+
// M3 is its own line beside M2, not a bump of it — same reason `kimi-k3`
|
|
110760
|
+
// sits beside `kimi-k2` rather than replacing it.
|
|
110761
|
+
"minimax-m3": {
|
|
110762
|
+
displayName: "MiniMax M3",
|
|
110763
|
+
resolve: "opencode/minimax-m3",
|
|
110764
|
+
openRouterResolve: "openrouter/minimax/minimax-m3"
|
|
110765
|
+
},
|
|
110622
110766
|
// slug pins the m2 line for DB stability; resolve tracks the current m2.7.
|
|
110623
110767
|
"minimax-m2.5": {
|
|
110624
110768
|
displayName: "MiniMax M2",
|
|
110625
110769
|
resolve: "opencode/minimax-m2.7",
|
|
110626
110770
|
openRouterResolve: "openrouter/minimax/minimax-m2.7"
|
|
110627
110771
|
},
|
|
110772
|
+
// Z.ai and xAI reach Zen subscribers only here — before this, `opencode-go`
|
|
110773
|
+
// was the catalog's only GLM route, and Grok had no Zen route at all.
|
|
110774
|
+
glm: {
|
|
110775
|
+
displayName: "GLM",
|
|
110776
|
+
resolve: "opencode/glm-5.2",
|
|
110777
|
+
effort: ["high", "max"],
|
|
110778
|
+
openRouterEffort: ["high", "xhigh"],
|
|
110779
|
+
openRouterResolve: "openrouter/z-ai/glm-5.2"
|
|
110780
|
+
},
|
|
110781
|
+
grok: {
|
|
110782
|
+
displayName: "Grok",
|
|
110783
|
+
resolve: "opencode/grok-4.6",
|
|
110784
|
+
effort: ["low", "medium", "high", "xhigh"],
|
|
110785
|
+
openRouterResolve: "openrouter/x-ai/grok-4.6"
|
|
110786
|
+
},
|
|
110628
110787
|
"gpt-5-nano": {
|
|
110629
110788
|
displayName: "GPT Nano",
|
|
110630
110789
|
resolve: "opencode/gpt-5-nano",
|
|
110631
110790
|
effort: ["minimal", "low", "medium", "high"],
|
|
110632
110791
|
openRouterResolve: "openrouter/openai/gpt-5-nano"
|
|
110633
110792
|
},
|
|
110793
|
+
// Zen's live free MiMo, and the second free row in a menu that big-pickle
|
|
110794
|
+
// was alone in since `mimo-v2-pro-free` lost its model.
|
|
110795
|
+
mimo: {
|
|
110796
|
+
displayName: "MiMo",
|
|
110797
|
+
resolve: "opencode/mimo-v2.5-free",
|
|
110798
|
+
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
110799
|
+
// see the big-pickle note above (#1077).
|
|
110800
|
+
isFree: true
|
|
110801
|
+
},
|
|
110634
110802
|
"mimo-v2-pro-free": {
|
|
110635
110803
|
displayName: "MiMo V2 Pro",
|
|
110636
110804
|
resolve: "opencode/mimo-v2-pro-free",
|
|
110637
110805
|
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
110638
110806
|
// see the big-pickle note above (#1077).
|
|
110639
110807
|
isFree: true,
|
|
110640
|
-
|
|
110808
|
+
// the model id Zen dropped; land a stored MiMo pick back on MiMo rather
|
|
110809
|
+
// than on the unrelated model it had to settle for while none was live.
|
|
110810
|
+
fallback: "opencode/mimo"
|
|
110641
110811
|
},
|
|
110642
110812
|
"minimax-m2.5-free": {
|
|
110643
110813
|
displayName: "MiniMax M2",
|
|
@@ -110732,6 +110902,16 @@ var providers = {
|
|
|
110732
110902
|
resolve: "opencode-go/qwen3.7-plus",
|
|
110733
110903
|
openRouterResolve: "openrouter/qwen/qwen3.7-plus"
|
|
110734
110904
|
},
|
|
110905
|
+
// the cheap rung Alibaba added under Plus (0.15/0.47 against 0.5/3), and
|
|
110906
|
+
// the only model either OpenCode plan has added since this block was written.
|
|
110907
|
+
"qwen-flash": {
|
|
110908
|
+
displayName: "Qwen Flash",
|
|
110909
|
+
resolve: "opencode-go/qwen3.8-flash",
|
|
110910
|
+
effort: ["low", "medium", "xhigh"],
|
|
110911
|
+
// the Go route publishes rungs where OpenRouter publishes none.
|
|
110912
|
+
openRouterEffort: [],
|
|
110913
|
+
openRouterResolve: "openrouter/qwen/qwen3.8-flash"
|
|
110914
|
+
},
|
|
110735
110915
|
// MiniMax — parity with opencode/* and openrouter/*; the m2 slug pins the
|
|
110736
110916
|
// line for DB stability while the resolve tracks the current m2.7.
|
|
110737
110917
|
"minimax-m3": {
|
|
@@ -111031,6 +111211,80 @@ var providers = {
|
|
|
111031
111211
|
openRouterResolve: "openrouter/minimax/minimax-m3"
|
|
111032
111212
|
}
|
|
111033
111213
|
}
|
|
111214
|
+
}),
|
|
111215
|
+
vercel: provider({
|
|
111216
|
+
// Vercel AI Gateway — one key serves every model it fronts. model IDs use
|
|
111217
|
+
// the models.dev `vercel` catalog's own naming (dotted versions, e.g.
|
|
111218
|
+
// `anthropic/claude-opus-5`, `zai/glm-5.3`), and effort ladders mirror that
|
|
111219
|
+
// catalog's entries, not the upstream vendor's. deliberately no
|
|
111220
|
+
// `openRouterResolve`: a gateway pick is BYOK-only — silently rerouting it
|
|
111221
|
+
// over the Router proxy would bill the wallet for traffic the user pointed
|
|
111222
|
+
// at their own gateway.
|
|
111223
|
+
displayName: "Vercel AI Gateway",
|
|
111224
|
+
envVars: ["AI_GATEWAY_API_KEY"],
|
|
111225
|
+
models: {
|
|
111226
|
+
"claude-opus": {
|
|
111227
|
+
displayName: "Claude Opus",
|
|
111228
|
+
resolve: "vercel/anthropic/claude-opus-5",
|
|
111229
|
+
effort: ["low", "medium", "high", "xhigh", "max"],
|
|
111230
|
+
preferred: true,
|
|
111231
|
+
subagentModel: "claude-sonnet"
|
|
111232
|
+
},
|
|
111233
|
+
"claude-sonnet": {
|
|
111234
|
+
displayName: "Claude Sonnet",
|
|
111235
|
+
resolve: "vercel/anthropic/claude-sonnet-5",
|
|
111236
|
+
effort: ["low", "medium", "high", "xhigh"]
|
|
111237
|
+
},
|
|
111238
|
+
"claude-haiku": {
|
|
111239
|
+
displayName: "Claude Haiku",
|
|
111240
|
+
resolve: "vercel/anthropic/claude-haiku-4.5"
|
|
111241
|
+
},
|
|
111242
|
+
"gpt-sol": {
|
|
111243
|
+
displayName: "GPT Sol",
|
|
111244
|
+
resolve: "vercel/openai/gpt-5.6-sol",
|
|
111245
|
+
effort: ["none", "low", "medium", "high", "xhigh", "max"],
|
|
111246
|
+
subagentModel: "gpt-terra"
|
|
111247
|
+
},
|
|
111248
|
+
"gpt-terra": {
|
|
111249
|
+
displayName: "GPT Terra",
|
|
111250
|
+
resolve: "vercel/openai/gpt-5.6-terra",
|
|
111251
|
+
effort: ["none", "low", "medium", "high", "xhigh", "max"]
|
|
111252
|
+
},
|
|
111253
|
+
"gpt-luna": {
|
|
111254
|
+
displayName: "GPT Luna",
|
|
111255
|
+
resolve: "vercel/openai/gpt-5.6-luna",
|
|
111256
|
+
effort: ["none", "low", "medium", "high", "xhigh", "max"]
|
|
111257
|
+
},
|
|
111258
|
+
"gemini-pro": {
|
|
111259
|
+
displayName: "Gemini Pro",
|
|
111260
|
+
resolve: "vercel/google/gemini-3.1-pro-preview",
|
|
111261
|
+
effort: ["low", "medium", "high"]
|
|
111262
|
+
},
|
|
111263
|
+
"gemini-flash": {
|
|
111264
|
+
displayName: "Gemini Flash",
|
|
111265
|
+
resolve: "vercel/google/gemini-3.6-flash",
|
|
111266
|
+
effort: ["minimal", "low", "medium", "high"]
|
|
111267
|
+
},
|
|
111268
|
+
"deepseek-pro": {
|
|
111269
|
+
displayName: "DeepSeek Pro",
|
|
111270
|
+
resolve: "vercel/deepseek/deepseek-v4-pro-0813",
|
|
111271
|
+
effort: ["high", "xhigh"]
|
|
111272
|
+
},
|
|
111273
|
+
"deepseek-flash": {
|
|
111274
|
+
displayName: "DeepSeek Flash",
|
|
111275
|
+
resolve: "vercel/deepseek/deepseek-v4-flash",
|
|
111276
|
+
effort: ["high", "xhigh"]
|
|
111277
|
+
},
|
|
111278
|
+
glm: {
|
|
111279
|
+
displayName: "GLM",
|
|
111280
|
+
resolve: "vercel/zai/glm-5.3",
|
|
111281
|
+
effort: ["low", "high", "max"]
|
|
111282
|
+
},
|
|
111283
|
+
"kimi-k3": {
|
|
111284
|
+
displayName: "Kimi K3",
|
|
111285
|
+
resolve: "vercel/moonshotai/kimi-k3"
|
|
111286
|
+
}
|
|
111287
|
+
}
|
|
111034
111288
|
})
|
|
111035
111289
|
};
|
|
111036
111290
|
function parseModel(slug2) {
|
|
@@ -111458,9 +111712,9 @@ function logTokenTable(t2) {
|
|
|
111458
111712
|
}
|
|
111459
111713
|
|
|
111460
111714
|
// utils/globals.ts
|
|
111461
|
-
import { existsSync } from "node:fs";
|
|
111715
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
111462
111716
|
var isGitHubActions = !!process.env.GITHUB_ACTIONS;
|
|
111463
|
-
var isInsideDocker =
|
|
111717
|
+
var isInsideDocker = existsSync2("/.dockerenv");
|
|
111464
111718
|
|
|
111465
111719
|
// utils/log.ts
|
|
111466
111720
|
var logContext = new AsyncLocalStorage();
|
|
@@ -111688,7 +111942,7 @@ function formatUsageSummary(entries) {
|
|
|
111688
111942
|
|
|
111689
111943
|
// utils/install.ts
|
|
111690
111944
|
import { spawnSync } from "node:child_process";
|
|
111691
|
-
import { chmodSync, createWriteStream, existsSync as
|
|
111945
|
+
import { chmodSync, createWriteStream, existsSync as existsSync3, mkdirSync } from "node:fs";
|
|
111692
111946
|
import { join as join2 } from "node:path";
|
|
111693
111947
|
import { pipeline } from "node:stream/promises";
|
|
111694
111948
|
async function installFromNpmTarball(params) {
|
|
@@ -111697,7 +111951,7 @@ async function installFromNpmTarball(params) {
|
|
|
111697
111951
|
const packageRoot = join2(tempDir, `npm-${params.packageName.replace(/[^a-z0-9]+/gi, "-")}`);
|
|
111698
111952
|
const extractedDir = join2(packageRoot, "package");
|
|
111699
111953
|
const cliPath = join2(extractedDir, params.executablePath);
|
|
111700
|
-
if (
|
|
111954
|
+
if (existsSync3(cliPath)) {
|
|
111701
111955
|
log2.debug(`\xBB using cached binary at ${cliPath}`);
|
|
111702
111956
|
return cliPath;
|
|
111703
111957
|
}
|
|
@@ -111771,7 +112025,7 @@ async function installFromNpmTarball(params) {
|
|
|
111771
112025
|
}
|
|
111772
112026
|
log2.debug(`\xBB dependencies installed`);
|
|
111773
112027
|
}
|
|
111774
|
-
if (!
|
|
112028
|
+
if (!existsSync3(cliPath)) {
|
|
111775
112029
|
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
111776
112030
|
}
|
|
111777
112031
|
chmodSync(cliPath, 493);
|
|
@@ -111782,6 +112036,7 @@ async function installFromNpmTarball(params) {
|
|
|
111782
112036
|
// utils/providerErrors.ts
|
|
111783
112037
|
var PROVIDER_BILLING_EXHAUSTED_LABEL = "provider billing exhausted";
|
|
111784
112038
|
var PROVIDER_NO_ENDPOINTS_LABEL = "provider no routable endpoints";
|
|
112039
|
+
var PROVIDER_USAGE_LIMIT_LABEL = "provider usage limit reached";
|
|
111785
112040
|
var statusKey = `\\b(?:status[_ ]?code|http[_ ]?status|status)["']?\\s*[:=]\\s*["']?`;
|
|
111786
112041
|
var ANTHROPIC_SPEND_CAP_PATTERN = /reached your specified API usage limits\.?(?:\s*You will regain access on ([^"\n]+?)\.)?/i;
|
|
111787
112042
|
function findAnthropicSpendCap(text) {
|
|
@@ -111827,6 +112082,14 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
111827
112082
|
// the wallet-shaped patterns above reach, and its 400 sits nowhere near a
|
|
111828
112083
|
// `status:` key either — so the whole message was dropped on the floor (#1208).
|
|
111829
112084
|
{ regex: ANTHROPIC_SPEND_CAP_PATTERN, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
112085
|
+
// OpenCode Zen / Codex-subscription cap: `AI_APICallError: The usage limit has
|
|
112086
|
+
// been reached`. Its noun is "usage limit" with no "rate", no status code and
|
|
112087
|
+
// no wallet wording, so every pattern here missed it and `lastProviderError`
|
|
112088
|
+
// stayed unset — which suppresses nothing, so the run was reported as "The
|
|
112089
|
+
// model produced no output at all … usually transient; re-running often
|
|
112090
|
+
// succeeds" while the same log held nine of these. Measured on a live account
|
|
112091
|
+
// whose ChatGPT subscription was capped.
|
|
112092
|
+
{ regex: /\bthe usage limit has been reached\b/i, label: PROVIDER_USAGE_LIMIT_LABEL },
|
|
111830
112093
|
// the OpenRouter shapes `isRouterKeylimitExhaustedError` matches. on a Router
|
|
111831
112094
|
// run those mean the PULLFROG wallet is empty and `renderRunError` returns a
|
|
111832
112095
|
// `BillingError` before ever reaching this list; on a BYOK run the very same
|
|
@@ -111957,7 +112220,7 @@ function ossEffortFloor(ctx) {
|
|
|
111957
112220
|
const alias = resolveRunAlias(ctx);
|
|
111958
112221
|
const published = alias?.openRouterEffort ?? alias?.effort;
|
|
111959
112222
|
if (!published) return 0;
|
|
111960
|
-
return rungPosition({ rung:
|
|
112223
|
+
return rungPosition({ rung: SUBSIDY_RUNG, published }) ?? 0;
|
|
111961
112224
|
}
|
|
111962
112225
|
function resolveRunEffort(ctx) {
|
|
111963
112226
|
const configured = ctx.payload.effort !== void 0;
|
|
@@ -111978,7 +112241,7 @@ function resolveRunEffort(ctx) {
|
|
|
111978
112241
|
|
|
111979
112242
|
// utils/skills.ts
|
|
111980
112243
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
111981
|
-
import { existsSync as
|
|
112244
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
111982
112245
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
111983
112246
|
import { dirname, join as join3 } from "node:path";
|
|
111984
112247
|
import { fileURLToPath } from "node:url";
|
|
@@ -111989,7 +112252,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
111989
112252
|
// package.json
|
|
111990
112253
|
var package_default = {
|
|
111991
112254
|
name: "pullfrog",
|
|
111992
|
-
version: "0.1.
|
|
112255
|
+
version: "0.1.68",
|
|
111993
112256
|
type: "module",
|
|
111994
112257
|
bin: {
|
|
111995
112258
|
pullfrog: "dist/cli.mjs",
|
|
@@ -112118,7 +112381,7 @@ function resolveSkillPath(name) {
|
|
|
112118
112381
|
join3(here, "skills", name, "SKILL.md")
|
|
112119
112382
|
];
|
|
112120
112383
|
for (const candidate of candidates) {
|
|
112121
|
-
if (
|
|
112384
|
+
if (existsSync4(candidate)) return candidate;
|
|
112122
112385
|
}
|
|
112123
112386
|
throw new Error(`bundled skill not found: ${name} (looked in ${candidates.join(", ")})`);
|
|
112124
112387
|
}
|
|
@@ -114159,13 +114422,13 @@ var claude = agent({
|
|
|
114159
114422
|
|
|
114160
114423
|
// agents/codex.ts
|
|
114161
114424
|
var core2 = __toESM(require_core(), 1);
|
|
114162
|
-
import { existsSync as
|
|
114425
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
114163
114426
|
import { join as join7 } from "node:path";
|
|
114164
114427
|
import { performance as performance6 } from "node:perf_hooks";
|
|
114165
114428
|
|
|
114166
114429
|
// utils/codexHome.ts
|
|
114167
114430
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
114168
|
-
import { existsSync as
|
|
114431
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
114169
114432
|
import { homedir as homedir2, userInfo } from "node:os";
|
|
114170
114433
|
import { join as join6 } from "node:path";
|
|
114171
114434
|
var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
|
|
@@ -114214,7 +114477,7 @@ function installCodexAuth() {
|
|
|
114214
114477
|
}
|
|
114215
114478
|
function writeOpenCodeAuthEntry(params) {
|
|
114216
114479
|
let existing = {};
|
|
114217
|
-
if (
|
|
114480
|
+
if (existsSync5(params.authPath)) {
|
|
114218
114481
|
try {
|
|
114219
114482
|
const parsed2 = JSON.parse(readFileSync3(params.authPath, "utf8"));
|
|
114220
114483
|
if (parsed2 && typeof parsed2 === "object") existing = parsed2;
|
|
@@ -114531,7 +114794,7 @@ var APPROVAL_MODE_KEY = "default_tools_approval_mode";
|
|
|
114531
114794
|
var APPROVE_TOOLS = `${APPROVAL_MODE_KEY} = "approve"`;
|
|
114532
114795
|
function repoMcpApprovals(repoDir) {
|
|
114533
114796
|
const path4 = join7(repoDir, ".codex", "config.toml");
|
|
114534
|
-
if (!
|
|
114797
|
+
if (!existsSync6(path4)) return [];
|
|
114535
114798
|
const out = [];
|
|
114536
114799
|
let section = [];
|
|
114537
114800
|
let isServerTable = false;
|
|
@@ -178940,7 +179203,7 @@ var pbkdf2Async = promisify(pbkdf2);
|
|
|
178940
179203
|
|
|
178941
179204
|
// utils/browser.ts
|
|
178942
179205
|
import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
|
|
178943
|
-
import { existsSync as
|
|
179206
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
178944
179207
|
import { dirname as dirname2 } from "node:path";
|
|
178945
179208
|
var CHROME_PATHS = ["/usr/bin/google-chrome-stable"];
|
|
178946
179209
|
var systemChromePath;
|
|
@@ -178949,7 +179212,7 @@ function findSystemChromePath() {
|
|
|
178949
179212
|
return systemChromePath || void 0;
|
|
178950
179213
|
}
|
|
178951
179214
|
for (const p of CHROME_PATHS) {
|
|
178952
|
-
if (
|
|
179215
|
+
if (existsSync7(p)) {
|
|
178953
179216
|
systemChromePath = p;
|
|
178954
179217
|
log2.info(`found system chrome: ${p}`);
|
|
178955
179218
|
return p;
|
|
@@ -182620,7 +182883,7 @@ var describeExpressionOptions = {
|
|
|
182620
182883
|
};
|
|
182621
182884
|
var expressBranches = (expressions) => describeBranches(expressions, describeExpressionOptions);
|
|
182622
182885
|
var describeBranches = (descriptions, opts) => {
|
|
182623
|
-
const
|
|
182886
|
+
const delimiter3 = opts?.delimiter ?? ", ";
|
|
182624
182887
|
const finalDelimiter = opts?.finalDelimiter ?? " or ";
|
|
182625
182888
|
if (descriptions.length === 0)
|
|
182626
182889
|
return "never";
|
|
@@ -182631,7 +182894,7 @@ var describeBranches = (descriptions, opts) => {
|
|
|
182631
182894
|
const seen = {};
|
|
182632
182895
|
const unique = descriptions.filter((s) => seen[s] ? false : seen[s] = true);
|
|
182633
182896
|
const last = unique.pop();
|
|
182634
|
-
return `${unique.join(
|
|
182897
|
+
return `${unique.join(delimiter3)}${unique.length ? finalDelimiter : ""}${last}`;
|
|
182635
182898
|
};
|
|
182636
182899
|
var intersectBranches = (l2, r2, ctx) => {
|
|
182637
182900
|
const batchesByR = r2.map(() => []);
|
|
@@ -193349,7 +193612,7 @@ function isValidUnquotedKey(key) {
|
|
|
193349
193612
|
function isIdentifierSegment(key) {
|
|
193350
193613
|
return /^[A-Z_]\w*$/i.test(key);
|
|
193351
193614
|
}
|
|
193352
|
-
function isSafeUnquoted(value2,
|
|
193615
|
+
function isSafeUnquoted(value2, delimiter3 = DEFAULT_DELIMITER) {
|
|
193353
193616
|
if (!value2) return false;
|
|
193354
193617
|
if (value2 !== value2.trim()) return false;
|
|
193355
193618
|
if (isBooleanOrNullLiteral(value2) || isNumericLike(value2)) return false;
|
|
@@ -193357,7 +193620,7 @@ function isSafeUnquoted(value2, delimiter2 = DEFAULT_DELIMITER) {
|
|
|
193357
193620
|
if (value2.includes('"') || value2.includes("\\")) return false;
|
|
193358
193621
|
if (/[[\]{}]/.test(value2)) return false;
|
|
193359
193622
|
if (/[\n\r\t]/.test(value2)) return false;
|
|
193360
|
-
if (value2.includes(
|
|
193623
|
+
if (value2.includes(delimiter3)) return false;
|
|
193361
193624
|
if (value2.startsWith(LIST_ITEM_MARKER)) return false;
|
|
193362
193625
|
return true;
|
|
193363
193626
|
}
|
|
@@ -193408,33 +193671,33 @@ function collectSingleKeyChain(startKey, startValue, maxDepth) {
|
|
|
193408
193671
|
function buildFoldedKey(segments) {
|
|
193409
193672
|
return segments.join(DOT);
|
|
193410
193673
|
}
|
|
193411
|
-
function encodePrimitive(value2,
|
|
193674
|
+
function encodePrimitive(value2, delimiter3) {
|
|
193412
193675
|
if (value2 === null) return NULL_LITERAL;
|
|
193413
193676
|
if (typeof value2 === "boolean") return String(value2);
|
|
193414
193677
|
if (typeof value2 === "number") return String(value2);
|
|
193415
|
-
return encodeStringLiteral(value2,
|
|
193678
|
+
return encodeStringLiteral(value2, delimiter3);
|
|
193416
193679
|
}
|
|
193417
|
-
function encodeStringLiteral(value2,
|
|
193418
|
-
if (isSafeUnquoted(value2,
|
|
193680
|
+
function encodeStringLiteral(value2, delimiter3 = DEFAULT_DELIMITER) {
|
|
193681
|
+
if (isSafeUnquoted(value2, delimiter3)) return value2;
|
|
193419
193682
|
return `${DOUBLE_QUOTE}${escapeString(value2)}${DOUBLE_QUOTE}`;
|
|
193420
193683
|
}
|
|
193421
193684
|
function encodeKey(key) {
|
|
193422
193685
|
if (isValidUnquotedKey(key)) return key;
|
|
193423
193686
|
return `${DOUBLE_QUOTE}${escapeString(key)}${DOUBLE_QUOTE}`;
|
|
193424
193687
|
}
|
|
193425
|
-
function encodeAndJoinPrimitives(values,
|
|
193426
|
-
return values.map((v) => encodePrimitive(v,
|
|
193688
|
+
function encodeAndJoinPrimitives(values, delimiter3 = DEFAULT_DELIMITER) {
|
|
193689
|
+
return values.map((v) => encodePrimitive(v, delimiter3)).join(delimiter3);
|
|
193427
193690
|
}
|
|
193428
193691
|
function formatHeader(length, options) {
|
|
193429
193692
|
const key = options?.key;
|
|
193430
193693
|
const fields = options?.fields;
|
|
193431
|
-
const
|
|
193694
|
+
const delimiter3 = options?.delimiter ?? COMMA2;
|
|
193432
193695
|
let header = "";
|
|
193433
193696
|
if (key) header += encodeKey(key);
|
|
193434
|
-
header += `[${length}${
|
|
193697
|
+
header += `[${length}${delimiter3 !== DEFAULT_DELIMITER ? delimiter3 : ""}]`;
|
|
193435
193698
|
if (fields) {
|
|
193436
193699
|
const quotedFields = fields.map((f) => encodeKey(f));
|
|
193437
|
-
header += `{${quotedFields.join(
|
|
193700
|
+
header += `{${quotedFields.join(delimiter3)}}`;
|
|
193438
193701
|
}
|
|
193439
193702
|
header += ":";
|
|
193440
193703
|
return header;
|
|
@@ -193527,12 +193790,12 @@ function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) {
|
|
|
193527
193790
|
yield indentedListItem(depth + 1, arrayLine, options.indent);
|
|
193528
193791
|
}
|
|
193529
193792
|
}
|
|
193530
|
-
function encodeInlineArrayLine(values,
|
|
193793
|
+
function encodeInlineArrayLine(values, delimiter3, prefix) {
|
|
193531
193794
|
const header = formatHeader(values.length, {
|
|
193532
193795
|
key: prefix,
|
|
193533
|
-
delimiter:
|
|
193796
|
+
delimiter: delimiter3
|
|
193534
193797
|
});
|
|
193535
|
-
const joinedValue = encodeAndJoinPrimitives(values,
|
|
193798
|
+
const joinedValue = encodeAndJoinPrimitives(values, delimiter3);
|
|
193536
193799
|
if (values.length === 0) return header;
|
|
193537
193800
|
return `${header} ${joinedValue}`;
|
|
193538
193801
|
}
|
|
@@ -194600,6 +194863,9 @@ function formatModelLabel(params) {
|
|
|
194600
194863
|
if (params.fallbackFrom) {
|
|
194601
194864
|
return `${base} (credentials for ${providerDisplayName(params.fallbackFrom)} were rejected by the provider)`;
|
|
194602
194865
|
}
|
|
194866
|
+
if (params.clamped?.reason === "trial") {
|
|
194867
|
+
return `${base} (free trial)`;
|
|
194868
|
+
}
|
|
194603
194869
|
if (params.clamped) {
|
|
194604
194870
|
const target = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
|
|
194605
194871
|
return params.clamped.reason === "card" ? `${base} (${target} needs a [card on file](https://docs.pullfrog.com/models))` : `${base} (${target} needs a [provider key](https://docs.pullfrog.com/models) \u2014 no Router support yet)`;
|
|
@@ -194609,6 +194875,15 @@ function formatModelLabel(params) {
|
|
|
194609
194875
|
}
|
|
194610
194876
|
return base;
|
|
194611
194877
|
}
|
|
194878
|
+
function buildTrialDisclosure(owner) {
|
|
194879
|
+
const consoleUrl2 = owner ? `https://pullfrog.com/console/${owner}` : "https://pullfrog.com/console";
|
|
194880
|
+
return [
|
|
194881
|
+
"---",
|
|
194882
|
+
"",
|
|
194883
|
+
"> [!IMPORTANT]",
|
|
194884
|
+
`> **This run used the free trial model.** \`DeepSeek Flash\` is fast and cheap \u2014 expect lighter work than a frontier model. [Connect a subscription or API key \u2192](${consoleUrl2})`
|
|
194885
|
+
].join("\n");
|
|
194886
|
+
}
|
|
194612
194887
|
function buildPullfrogFooter(params) {
|
|
194613
194888
|
const parts = [];
|
|
194614
194889
|
if (params.shaPinned) {
|
|
@@ -194641,10 +194916,13 @@ function buildPullfrogFooter(params) {
|
|
|
194641
194916
|
);
|
|
194642
194917
|
}
|
|
194643
194918
|
const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
|
|
194919
|
+
const disclosure = params.clamped?.reason === "trial" ? `${buildTrialDisclosure(params.owner)}
|
|
194920
|
+
|
|
194921
|
+
` : "";
|
|
194644
194922
|
return `
|
|
194645
194923
|
|
|
194646
194924
|
${PULLFROG_DIVIDER}
|
|
194647
|
-
<sup>${FROG_LOGO} \uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
|
|
194925
|
+
${disclosure}<sup>${FROG_LOGO} \uFF5C ${allParts.join(" \uFF5C ")}</sup>`;
|
|
194648
194926
|
}
|
|
194649
194927
|
function stripExistingFooter(body) {
|
|
194650
194928
|
const dividerIndex = body.indexOf(PULLFROG_DIVIDER);
|
|
@@ -194798,7 +195076,8 @@ function buildCommentFooter(ctx, customParts) {
|
|
|
194798
195076
|
clamped: ctx.toolState.modelClamped,
|
|
194799
195077
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
194800
195078
|
shaPinned: ctx.toolState.shaPinned,
|
|
194801
|
-
oss: ctx.oss
|
|
195079
|
+
oss: ctx.oss,
|
|
195080
|
+
owner: ctx.repo.owner
|
|
194802
195081
|
});
|
|
194803
195082
|
}
|
|
194804
195083
|
function buildImplementPlanLink(ctx, issueNumber, commentId) {
|
|
@@ -195797,7 +196076,8 @@ async function createAndSubmitWithFooter(ctx, params, opts) {
|
|
|
195797
196076
|
clamped: ctx.toolState.modelClamped,
|
|
195798
196077
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
195799
196078
|
shaPinned: ctx.toolState.shaPinned,
|
|
195800
|
-
oss: ctx.oss
|
|
196079
|
+
oss: ctx.oss,
|
|
196080
|
+
owner: ctx.repo.owner
|
|
195801
196081
|
});
|
|
195802
196082
|
return await ctx.octokit.rest.pulls.submitReview({
|
|
195803
196083
|
owner: params.owner,
|
|
@@ -196951,14 +197231,14 @@ function ReopenCurrentTool(ctx) {
|
|
|
196951
197231
|
import { performance as performance9 } from "node:perf_hooks";
|
|
196952
197232
|
|
|
196953
197233
|
// prep/installNodeDependencies.ts
|
|
196954
|
-
import { existsSync as
|
|
197234
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
196955
197235
|
import { join as join19 } from "node:path";
|
|
196956
197236
|
|
|
196957
197237
|
// utils/packageManager.ts
|
|
196958
197238
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
196959
|
-
import { existsSync as
|
|
197239
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
196960
197240
|
import { mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
196961
|
-
import { delimiter, join as join18 } from "node:path";
|
|
197241
|
+
import { delimiter as delimiter2, join as join18 } from "node:path";
|
|
196962
197242
|
var SUPPORTED_NAMES = ["npm", "pnpm", "yarn", "bun"];
|
|
196963
197243
|
var COREPACK_MANAGED = ["pnpm", "yarn"];
|
|
196964
197244
|
function isSupported(name) {
|
|
@@ -196997,7 +197277,7 @@ function parseDevEnginesField(field) {
|
|
|
196997
197277
|
}
|
|
196998
197278
|
async function resolvePackageManagerSpec(cwd) {
|
|
196999
197279
|
const pkgPath = join18(cwd, "package.json");
|
|
197000
|
-
if (!
|
|
197280
|
+
if (!existsSync8(pkgPath)) return null;
|
|
197001
197281
|
let pkg;
|
|
197002
197282
|
try {
|
|
197003
197283
|
pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
|
|
@@ -197085,7 +197365,7 @@ async function ensurePackageManager(params) {
|
|
|
197085
197365
|
);
|
|
197086
197366
|
return false;
|
|
197087
197367
|
}
|
|
197088
|
-
process.env.PATH = `${params.binDir}${
|
|
197368
|
+
process.env.PATH = `${params.binDir}${delimiter2}${process.env.PATH ?? ""}`;
|
|
197089
197369
|
const prepare = await runCorepack(["prepare", `${spec.name}@${spec.version}`, "--activate"]);
|
|
197090
197370
|
if (prepare.exitCode !== 0) {
|
|
197091
197371
|
log2.warning(
|
|
@@ -197152,7 +197432,7 @@ var installNodeDependencies = {
|
|
|
197152
197432
|
name: "installNodeDependencies",
|
|
197153
197433
|
shouldRun: () => {
|
|
197154
197434
|
const packageJsonPath = join19(process.cwd(), "package.json");
|
|
197155
|
-
return
|
|
197435
|
+
return existsSync9(packageJsonPath);
|
|
197156
197436
|
},
|
|
197157
197437
|
run: async (options) => {
|
|
197158
197438
|
const declared = await resolvePackageManagerSpec(process.cwd());
|
|
@@ -197246,14 +197526,14 @@ ${errorMessage}`]
|
|
|
197246
197526
|
};
|
|
197247
197527
|
|
|
197248
197528
|
// prep/installPythonDependencies.ts
|
|
197249
|
-
import { existsSync as
|
|
197529
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6 } from "node:fs";
|
|
197250
197530
|
import { join as join20 } from "node:path";
|
|
197251
197531
|
function declaresBuildSystem(path4) {
|
|
197252
197532
|
return /^\s*\[\s*build-system\s*\]/m.test(readFileSync6(path4, "utf8"));
|
|
197253
197533
|
}
|
|
197254
197534
|
function configApplies(config3, cwd) {
|
|
197255
197535
|
const path4 = join20(cwd, config3.file);
|
|
197256
|
-
return
|
|
197536
|
+
return existsSync10(path4) && (config3.applies?.(path4) ?? true);
|
|
197257
197537
|
}
|
|
197258
197538
|
var PYTHON_CONFIGS = [
|
|
197259
197539
|
{
|
|
@@ -198558,7 +198838,8 @@ function buildPrBodyWithFooter(ctx, body) {
|
|
|
198558
198838
|
clamped: ctx.toolState.modelClamped,
|
|
198559
198839
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
198560
198840
|
shaPinned: ctx.toolState.shaPinned,
|
|
198561
|
-
oss: ctx.oss
|
|
198841
|
+
oss: ctx.oss,
|
|
198842
|
+
owner: ctx.repo.owner
|
|
198562
198843
|
});
|
|
198563
198844
|
const bodyWithoutFooter = stripExistingFooter(fixDoubleEscapedString(body));
|
|
198564
198845
|
return `${bodyWithoutFooter}${footer}`;
|
|
@@ -199865,10 +200146,12 @@ function isByokSetupError(text) {
|
|
|
199865
200146
|
var SECRETS_UNAVAILABLE_MARKER = "couldn't load your Pullfrog secrets";
|
|
199866
200147
|
var ROUTER_UNFUNDED_MARKER = "your Pullfrog Router balance is empty";
|
|
199867
200148
|
var CREDENTIAL_REJECTED_MARKER = "was rejected by its provider";
|
|
199868
|
-
|
|
199869
|
-
|
|
199870
|
-
|
|
199871
|
-
|
|
200149
|
+
var NoUsableCredentialError = class extends Error {
|
|
200150
|
+
};
|
|
200151
|
+
function throwKeyError(params) {
|
|
200152
|
+
if (params.secretsUnavailable) throw new Error(buildSecretsUnavailableError(params));
|
|
200153
|
+
if (params.routerUnfunded) throw new NoUsableCredentialError(buildRouterUnfundedError(params));
|
|
200154
|
+
throw new NoUsableCredentialError(buildMissingApiKeyError(params));
|
|
199872
200155
|
}
|
|
199873
200156
|
function buildRouterUnfundedError(params) {
|
|
199874
200157
|
const billingUrl = `${getApiUrl()}/console/${params.owner}#billing`;
|
|
@@ -200067,61 +200350,55 @@ function validateAgentApiKey(params) {
|
|
|
200067
200350
|
validateVertexSetup({ owner: params.owner, name: params.name });
|
|
200068
200351
|
return;
|
|
200069
200352
|
}
|
|
200070
|
-
|
|
200071
|
-
|
|
200353
|
+
if (process.env[BEDROCK_MODEL_ID_ENV]?.trim() === params.model) {
|
|
200354
|
+
validateBedrockSetup({ owner: params.owner, name: params.name });
|
|
200355
|
+
return;
|
|
200356
|
+
}
|
|
200072
200357
|
}
|
|
200073
200358
|
if (params.agent.name === "opencode") {
|
|
200074
200359
|
if (params.authorized.has(params.model)) return;
|
|
200075
200360
|
const reason = getModelsFailure();
|
|
200076
200361
|
if (reason) throw new Error(reason);
|
|
200077
200362
|
if (getModelEnvVars(params.model).some(hasEnvVar2)) return;
|
|
200078
|
-
|
|
200079
|
-
buildKeyError({
|
|
200080
|
-
owner: params.owner,
|
|
200081
|
-
name: params.name,
|
|
200082
|
-
model: params.model,
|
|
200083
|
-
secretsUnavailable: params.secretsUnavailable,
|
|
200084
|
-
routerUnfunded: params.routerUnfunded
|
|
200085
|
-
})
|
|
200086
|
-
);
|
|
200087
|
-
}
|
|
200088
|
-
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200089
|
-
throw new Error(
|
|
200090
|
-
buildKeyError({
|
|
200363
|
+
throwKeyError({
|
|
200091
200364
|
owner: params.owner,
|
|
200092
200365
|
name: params.name,
|
|
200093
200366
|
model: params.model,
|
|
200094
200367
|
secretsUnavailable: params.secretsUnavailable,
|
|
200095
200368
|
routerUnfunded: params.routerUnfunded
|
|
200096
|
-
})
|
|
200097
|
-
|
|
200369
|
+
});
|
|
200370
|
+
}
|
|
200371
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200372
|
+
throwKeyError({
|
|
200373
|
+
owner: params.owner,
|
|
200374
|
+
name: params.name,
|
|
200375
|
+
model: params.model,
|
|
200376
|
+
secretsUnavailable: params.secretsUnavailable,
|
|
200377
|
+
routerUnfunded: params.routerUnfunded
|
|
200378
|
+
});
|
|
200098
200379
|
}
|
|
200099
200380
|
if (params.agent.name === "opencode") {
|
|
200100
200381
|
if ([...params.authorized].some(modelHasRuntimeAuth)) return;
|
|
200101
200382
|
const reason = getModelsFailure();
|
|
200102
200383
|
if (reason) throw new Error(reason);
|
|
200103
|
-
|
|
200104
|
-
buildKeyError({
|
|
200105
|
-
owner: params.owner,
|
|
200106
|
-
name: params.name,
|
|
200107
|
-
secretsUnavailable: params.secretsUnavailable,
|
|
200108
|
-
routerUnfunded: params.routerUnfunded
|
|
200109
|
-
})
|
|
200110
|
-
);
|
|
200111
|
-
}
|
|
200112
|
-
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200113
|
-
throw new Error(
|
|
200114
|
-
buildKeyError({
|
|
200384
|
+
throwKeyError({
|
|
200115
200385
|
owner: params.owner,
|
|
200116
200386
|
name: params.name,
|
|
200117
200387
|
secretsUnavailable: params.secretsUnavailable,
|
|
200118
200388
|
routerUnfunded: params.routerUnfunded
|
|
200119
|
-
})
|
|
200120
|
-
|
|
200389
|
+
});
|
|
200390
|
+
}
|
|
200391
|
+
if (hasSingleProviderAuth(params.agent.name)) return;
|
|
200392
|
+
throwKeyError({
|
|
200393
|
+
owner: params.owner,
|
|
200394
|
+
name: params.name,
|
|
200395
|
+
secretsUnavailable: params.secretsUnavailable,
|
|
200396
|
+
routerUnfunded: params.routerUnfunded
|
|
200397
|
+
});
|
|
200121
200398
|
}
|
|
200122
200399
|
function isApiKeyAuthError(text) {
|
|
200123
200400
|
if (!text) return false;
|
|
200124
|
-
return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /Incorrect API key provided/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isMalformedKeyError(text) || isClaudeSubscriptionDisabledError(text) || isClaudeSessionLimitError(text) || isOAuthCredentialExpiredError(text);
|
|
200401
|
+
return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /Incorrect API key provided/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isMalformedKeyError(text) || isClaudeSubscriptionDisabledError(text) || isKimiPlanTierError(text) || isClaudeSessionLimitError(text) || isOAuthCredentialExpiredError(text);
|
|
200125
200402
|
}
|
|
200126
200403
|
function isOAuthCredentialExpiredError(text) {
|
|
200127
200404
|
return (
|
|
@@ -200142,6 +200419,9 @@ function isMalformedKeyError(text) {
|
|
|
200142
200419
|
function isClaudeSubscriptionDisabledError(text) {
|
|
200143
200420
|
return /disabled Claude subscription access/i.test(text);
|
|
200144
200421
|
}
|
|
200422
|
+
function isKimiPlanTierError(text) {
|
|
200423
|
+
return /Your current (?:subscription does not have access to|plan supports only)\b/i.test(text);
|
|
200424
|
+
}
|
|
200145
200425
|
var CLAUDE_SESSION_LIMIT_PATTERN = /hit your (?:session|weekly|five-hour|Opus|Sonnet|Haiku)\s+limit(?:\s*·\s*resets\s+([^"\n]+))?/i;
|
|
200146
200426
|
function isClaudeSessionLimitError(text) {
|
|
200147
200427
|
return CLAUDE_SESSION_LIMIT_PATTERN.test(text);
|
|
@@ -200215,6 +200495,13 @@ function formatApiKeyErrorSummary(params) {
|
|
|
200215
200495
|
`[Add repo secret \u2192](${githubSecretsUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
200216
200496
|
].join("\n");
|
|
200217
200497
|
}
|
|
200498
|
+
if (isKimiPlanTierError(params.raw)) {
|
|
200499
|
+
return [
|
|
200500
|
+
"**Your Kimi membership doesn't include the model this run asked for.** Kimi K3 needs a Moderato plan or above, and K3's 1M context and Kimi K2 HighSpeed need Allegretto or above. Upgrade the membership, or switch this repo to **Kimi K2**, which every tier includes.",
|
|
200501
|
+
"",
|
|
200502
|
+
`[Kimi plans \u2192](https://www.kimi.com/membership/pricing) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/kimi-code) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
200503
|
+
].join("\n");
|
|
200504
|
+
}
|
|
200218
200505
|
if (isOAuthCredentialExpiredError(params.raw)) {
|
|
200219
200506
|
return [
|
|
200220
200507
|
`**Your provider OAuth credential has expired or been revoked.** Re-authenticate the provider connection (e.g. \`pullfrog auth claude\` / \`pullfrog auth codex\` / \`pullfrog auth grok\`), then re-trigger the run.`,
|
|
@@ -200232,9 +200519,9 @@ function formatApiKeyErrorSummary(params) {
|
|
|
200232
200519
|
].join("\n");
|
|
200233
200520
|
}
|
|
200234
200521
|
return [
|
|
200235
|
-
`**Your LLM provider API key was rejected.** Rotate the key in your provider dashboard, then update the
|
|
200522
|
+
`**Your LLM provider API key was rejected.** Rotate the key in your provider dashboard, then update the copy Pullfrog uses \u2014 wherever you saved it.`,
|
|
200236
200523
|
"",
|
|
200237
|
-
`[
|
|
200524
|
+
`[Pullfrog secrets \u2192](${getApiUrl()}/console/${params.owner}) \xB7 [Repo secrets \u2192](${githubSecretsUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
200238
200525
|
].join("\n");
|
|
200239
200526
|
}
|
|
200240
200527
|
|
|
@@ -201460,6 +201747,9 @@ var DebugInput = type.enumerated("disabled", "enabled");
|
|
|
201460
201747
|
var JsonPayload = type({
|
|
201461
201748
|
"~pullfrog": "true",
|
|
201462
201749
|
version: "string",
|
|
201750
|
+
// the server's run type, forwarded verbatim to run-context. optional so a
|
|
201751
|
+
// payload from an older server build still parses against a newer action.
|
|
201752
|
+
"type?": "string | undefined",
|
|
201463
201753
|
"model?": "string | undefined",
|
|
201464
201754
|
"modelExplicit?": "boolean | undefined",
|
|
201465
201755
|
"effort?": "number | string | undefined",
|
|
@@ -201945,7 +202235,8 @@ ${ctx.error}` : ctx.error;
|
|
|
201945
202235
|
clamped: ctx.toolState.modelClamped,
|
|
201946
202236
|
unselectedProxyDefault: ctx.toolState.unselectedProxyDefault,
|
|
201947
202237
|
shaPinned: ctx.toolState.shaPinned,
|
|
201948
|
-
oss: ctx.toolState.oss
|
|
202238
|
+
oss: ctx.toolState.oss,
|
|
202239
|
+
owner: repoContext.owner
|
|
201949
202240
|
});
|
|
201950
202241
|
const body = `${formattedError}${footer}`;
|
|
201951
202242
|
const comment = ctx.toolState.progressComment;
|
|
@@ -202028,7 +202319,7 @@ async function mintProxyKey(ctx) {
|
|
|
202028
202319
|
}
|
|
202029
202320
|
}
|
|
202030
202321
|
async function buildProxyTokenHeaders(ctx) {
|
|
202031
|
-
const fundingSource = ctx.
|
|
202322
|
+
const fundingSource = ctx.fundingSource;
|
|
202032
202323
|
if (ctx.oidcCredentials) {
|
|
202033
202324
|
const creds = ctx.oidcCredentials;
|
|
202034
202325
|
const oidcToken = await op(() => fetchIdTokenFromStash(creds), {
|
|
@@ -202060,7 +202351,7 @@ async function resolveProxyModel(ctx) {
|
|
|
202060
202351
|
const key = await mintProxyKey({
|
|
202061
202352
|
oidcCredentials: ctx.oidcCredentials,
|
|
202062
202353
|
repo: ctx.repo,
|
|
202063
|
-
|
|
202354
|
+
fundingSource: ctx.oss ? "oss" : "router"
|
|
202064
202355
|
});
|
|
202065
202356
|
if (!key) return;
|
|
202066
202357
|
process.env.OPENROUTER_API_KEY = key;
|
|
@@ -202132,6 +202423,26 @@ async function runProxyResolution(ctx) {
|
|
|
202132
202423
|
throw error62;
|
|
202133
202424
|
}
|
|
202134
202425
|
}
|
|
202426
|
+
async function resolveTrialFallback(ctx) {
|
|
202427
|
+
if (process.env.PULLFROG_MODEL?.trim()) return false;
|
|
202428
|
+
if (!ctx.oidcCredentials && !isLocalApiUrl()) return false;
|
|
202429
|
+
const key = await mintProxyKey({
|
|
202430
|
+
oidcCredentials: ctx.oidcCredentials,
|
|
202431
|
+
repo: ctx.repo,
|
|
202432
|
+
fundingSource: "trial"
|
|
202433
|
+
});
|
|
202434
|
+
if (!key) return false;
|
|
202435
|
+
process.env.OPENROUTER_API_KEY = key;
|
|
202436
|
+
core9.setSecret(key);
|
|
202437
|
+
ctx.payload.proxyModel = DEFAULT_PROXY_MODEL;
|
|
202438
|
+
ctx.toolState.model = DEFAULT_PROXY_MODEL;
|
|
202439
|
+
ctx.toolState.modelClamped = {
|
|
202440
|
+
from: ctx.configuredModel ?? DEFAULT_PROXY_MODEL,
|
|
202441
|
+
reason: "trial"
|
|
202442
|
+
};
|
|
202443
|
+
log2.info(`\xBB proxy: trial \u2192 ${DEFAULT_PROXY_MODEL}`);
|
|
202444
|
+
return true;
|
|
202445
|
+
}
|
|
202135
202446
|
|
|
202136
202447
|
// utils/prSummary.ts
|
|
202137
202448
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
@@ -202309,8 +202620,9 @@ async function fetchRunContext(params) {
|
|
|
202309
202620
|
if (params.oidcToken) {
|
|
202310
202621
|
headers["X-GitHub-OIDC-Token"] = params.oidcToken;
|
|
202311
202622
|
}
|
|
202623
|
+
const query = params.runType ? `?type=${encodeURIComponent(params.runType)}` : "";
|
|
202312
202624
|
const response = await apiFetch({
|
|
202313
|
-
path: `/api/repo/${params.repoContext.owner}/${params.repoContext.name}/run-context`,
|
|
202625
|
+
path: `/api/repo/${params.repoContext.owner}/${params.repoContext.name}/run-context${query}`,
|
|
202314
202626
|
headers,
|
|
202315
202627
|
signal: controller.signal
|
|
202316
202628
|
});
|
|
@@ -202347,7 +202659,8 @@ async function fetchRunContext(params) {
|
|
|
202347
202659
|
proxyModel: data.proxyModel,
|
|
202348
202660
|
dbSecrets: data.dbSecrets,
|
|
202349
202661
|
secretsUnavailable: data.secretsUnavailable,
|
|
202350
|
-
routerUnfunded: data.routerUnfunded
|
|
202662
|
+
routerUnfunded: data.routerUnfunded,
|
|
202663
|
+
trialFallback: data.trialFallback
|
|
202351
202664
|
};
|
|
202352
202665
|
} catch {
|
|
202353
202666
|
clearTimeout(timeoutId);
|
|
@@ -202388,7 +202701,7 @@ async function resolveRunContextData(params) {
|
|
|
202388
202701
|
retries: [100, 500],
|
|
202389
202702
|
bail: (error62) => !isTransientOctokitError(error62)
|
|
202390
202703
|
})(),
|
|
202391
|
-
fetchRunContext({ token: params.token, repoContext, oidcToken })
|
|
202704
|
+
fetchRunContext({ token: params.token, repoContext, oidcToken, runType: params.runType })
|
|
202392
202705
|
]);
|
|
202393
202706
|
return {
|
|
202394
202707
|
repo: {
|
|
@@ -202406,7 +202719,8 @@ async function resolveRunContextData(params) {
|
|
|
202406
202719
|
// a failed mint on a runner that should have been able to mint is the same
|
|
202407
202720
|
// outcome as the server-side failure: the run never sees stored secrets.
|
|
202408
202721
|
secretsUnavailable: runContext.secretsUnavailable || !!process.env.ACTIONS_ID_TOKEN_REQUEST_URL && oidcToken === void 0,
|
|
202409
|
-
routerUnfunded: runContext.routerUnfunded
|
|
202722
|
+
routerUnfunded: runContext.routerUnfunded,
|
|
202723
|
+
trialFallback: runContext.trialFallback
|
|
202410
202724
|
};
|
|
202411
202725
|
}
|
|
202412
202726
|
|
|
@@ -203486,7 +203800,11 @@ async function main() {
|
|
|
203486
203800
|
resolveGit();
|
|
203487
203801
|
const jobToken = getJobToken();
|
|
203488
203802
|
const initialOctokit = createOctokit(jobToken);
|
|
203489
|
-
const runContext = await resolveRunContextData({
|
|
203803
|
+
const runContext = await resolveRunContextData({
|
|
203804
|
+
octokit: initialOctokit,
|
|
203805
|
+
token: jobToken,
|
|
203806
|
+
runType: typeof resolvedPromptInput === "string" ? void 0 : resolvedPromptInput.type
|
|
203807
|
+
});
|
|
203490
203808
|
timer.checkpoint("runContextData");
|
|
203491
203809
|
const payload = resolvePayload(resolvedPromptInput, runContext.repoSettings);
|
|
203492
203810
|
const toolState = initToolState({
|
|
@@ -203667,7 +203985,7 @@ async function main() {
|
|
|
203667
203985
|
}
|
|
203668
203986
|
const resolvedModel = credentials.kind === "fellBack" ? credentials.replacement : configuredModel;
|
|
203669
203987
|
vertexCredentials = materializeVertexCredentials({ model: resolvedModel });
|
|
203670
|
-
|
|
203988
|
+
let agent2 = resolveAgent({
|
|
203671
203989
|
model: resolvedModel,
|
|
203672
203990
|
proxyModel: payload.proxyModel,
|
|
203673
203991
|
// the account opt-in and the canary arm are both admissions to codex, so
|
|
@@ -203679,15 +203997,32 @@ async function main() {
|
|
|
203679
203997
|
const effectiveModel = payload.proxyModel ?? resolvedModel ?? payload.model;
|
|
203680
203998
|
toolState.model = effectiveModel;
|
|
203681
203999
|
if (!payload.proxyModel) {
|
|
203682
|
-
|
|
203683
|
-
|
|
203684
|
-
|
|
203685
|
-
|
|
203686
|
-
|
|
203687
|
-
|
|
203688
|
-
|
|
203689
|
-
|
|
203690
|
-
|
|
204000
|
+
try {
|
|
204001
|
+
validateAgentApiKey({
|
|
204002
|
+
agent: agent2,
|
|
204003
|
+
model: effectiveModel,
|
|
204004
|
+
authorized: getAuthorizedModels(),
|
|
204005
|
+
owner: runContext.repo.owner,
|
|
204006
|
+
name: runContext.repo.name,
|
|
204007
|
+
secretsUnavailable: runContext.secretsUnavailable,
|
|
204008
|
+
routerUnfunded: runContext.routerUnfunded
|
|
204009
|
+
});
|
|
204010
|
+
} catch (missingKey) {
|
|
204011
|
+
const funded = runContext.trialFallback && missingKey instanceof NoUsableCredentialError ? await resolveTrialFallback({
|
|
204012
|
+
payload,
|
|
204013
|
+
configuredModel: effectiveModel,
|
|
204014
|
+
oidcCredentials,
|
|
204015
|
+
repo: runContext.repo,
|
|
204016
|
+
toolState
|
|
204017
|
+
}) : false;
|
|
204018
|
+
if (!funded) throw missingKey;
|
|
204019
|
+
agent2 = resolveAgent({
|
|
204020
|
+
model: resolvedModel,
|
|
204021
|
+
proxyModel: payload.proxyModel,
|
|
204022
|
+
codexAgent: runContext.repoSettings.codexAgent || payload.codexArm === true
|
|
204023
|
+
});
|
|
204024
|
+
toolState.agent = agent2.name;
|
|
204025
|
+
}
|
|
203691
204026
|
}
|
|
203692
204027
|
await setupGit({
|
|
203693
204028
|
gitToken: tokenRef.gitToken,
|
|
@@ -203860,7 +204195,7 @@ ${instructions.user}` : null,
|
|
|
203860
204195
|
});
|
|
203861
204196
|
if (agentId === "opencode") {
|
|
203862
204197
|
const pluginDir = join28(process.cwd(), ".opencode", "plugin");
|
|
203863
|
-
const hasPlugins =
|
|
204198
|
+
const hasPlugins = existsSync11(pluginDir) && readdirSync2(pluginDir).some((f) => /\.[jt]sx?$/.test(f));
|
|
203864
204199
|
if (hasPlugins && toolState.dependencyInstallation?.promise) {
|
|
203865
204200
|
log2.info(
|
|
203866
204201
|
"\xBB .opencode/plugin/ detected \u2014 awaiting dependency installation before agent start"
|
|
@@ -204597,7 +204932,7 @@ function resolveTarget(repo) {
|
|
|
204597
204932
|
return { owner: match3[1], repo: match3[2] };
|
|
204598
204933
|
}
|
|
204599
204934
|
function cliVersion() {
|
|
204600
|
-
const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.
|
|
204935
|
+
const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.68");
|
|
204601
204936
|
if (!parts) return "0.0.0";
|
|
204602
204937
|
return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
|
|
204603
204938
|
}
|
|
@@ -204764,7 +205099,7 @@ async function runCli5(input2) {
|
|
|
204764
205099
|
}
|
|
204765
205100
|
|
|
204766
205101
|
// cli.ts
|
|
204767
|
-
var VERSION10 = "0.1.
|
|
205102
|
+
var VERSION10 = "0.1.68";
|
|
204768
205103
|
var bin = basename2(process.argv[1] || "");
|
|
204769
205104
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
204770
205105
|
var rawArgs = process.argv.slice(2);
|