pullfrog 0.1.3 → 0.1.5
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 +26 -16
- package/dist/external.d.ts +7 -0
- package/dist/index.js +25 -15
- package/dist/internal.js +1 -2
- package/dist/mcp/geminiSanitizer.d.ts +15 -4
- package/dist/utils/payload.d.ts +2 -0
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -108238,8 +108238,7 @@ var providers = {
|
|
|
108238
108238
|
"gpt-5-nano": {
|
|
108239
108239
|
displayName: "GPT Nano",
|
|
108240
108240
|
resolve: "opencode/gpt-5-nano",
|
|
108241
|
-
|
|
108242
|
-
isFree: true
|
|
108241
|
+
openRouterResolve: "openrouter/openai/gpt-5-nano"
|
|
108243
108242
|
},
|
|
108244
108243
|
"mimo-v2-pro-free": {
|
|
108245
108244
|
displayName: "MiMo V2 Pro",
|
|
@@ -108468,6 +108467,11 @@ async function apiFetch(options) {
|
|
|
108468
108467
|
if (bypassSecret) {
|
|
108469
108468
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
108470
108469
|
}
|
|
108470
|
+
if (!options.body) {
|
|
108471
|
+
for (const key of Object.keys(headers)) {
|
|
108472
|
+
if (key.toLowerCase() === "content-type") delete headers[key];
|
|
108473
|
+
}
|
|
108474
|
+
}
|
|
108471
108475
|
log.debug(`api fetch: ${options.method ?? "GET"} ${url4.pathname}`);
|
|
108472
108476
|
const init = {
|
|
108473
108477
|
method: options.method ?? "GET",
|
|
@@ -109156,8 +109160,11 @@ function sanitizeToolForGemini(tool2) {
|
|
|
109156
109160
|
}
|
|
109157
109161
|
function isGeminiRouted(ctx) {
|
|
109158
109162
|
const effective = ctx.payload.proxyModel ?? ctx.resolvedModel ?? ctx.payload.model;
|
|
109159
|
-
if (!effective) return
|
|
109160
|
-
|
|
109163
|
+
if (!effective) return true;
|
|
109164
|
+
const normalized = effective.toLowerCase();
|
|
109165
|
+
if (normalized.includes("gemini")) return true;
|
|
109166
|
+
if (!normalized.includes("/")) return true;
|
|
109167
|
+
return false;
|
|
109161
109168
|
}
|
|
109162
109169
|
|
|
109163
109170
|
// mcp/shared.ts
|
|
@@ -142589,7 +142596,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
142589
142596
|
// package.json
|
|
142590
142597
|
var package_default = {
|
|
142591
142598
|
name: "pullfrog",
|
|
142592
|
-
version: "0.1.
|
|
142599
|
+
version: "0.1.5",
|
|
142593
142600
|
type: "module",
|
|
142594
142601
|
bin: {
|
|
142595
142602
|
pullfrog: "dist/cli.mjs",
|
|
@@ -147478,8 +147485,7 @@ function stripProviderPrefix(specifier) {
|
|
|
147478
147485
|
const slashIndex = specifier.indexOf("/");
|
|
147479
147486
|
return slashIndex > 0 ? specifier.slice(slashIndex + 1) : specifier;
|
|
147480
147487
|
}
|
|
147481
|
-
function resolveEffort(
|
|
147482
|
-
if (model?.includes("opus")) return "max";
|
|
147488
|
+
function resolveEffort(_model) {
|
|
147483
147489
|
return "high";
|
|
147484
147490
|
}
|
|
147485
147491
|
function tailLines(text, maxCodeUnits) {
|
|
@@ -152964,6 +152970,7 @@ function buildRuntimeContext(ctx) {
|
|
|
152964
152970
|
"~pullfrog": _2,
|
|
152965
152971
|
prompt: _p,
|
|
152966
152972
|
eventInstructions: _ei,
|
|
152973
|
+
previousRunsNote: _prn,
|
|
152967
152974
|
event: _e2,
|
|
152968
152975
|
...payloadRest
|
|
152969
152976
|
} = ctx.payload;
|
|
@@ -153044,14 +153051,16 @@ In case of conflict between instructions, follow this precedence (highest to low
|
|
|
153044
153051
|
2. User prompt
|
|
153045
153052
|
3. Event-level instructions`;
|
|
153046
153053
|
function buildTaskSection(ctx) {
|
|
153054
|
+
const previousRunsNote = ctx.payload.previousRunsNote?.trim() ?? "";
|
|
153047
153055
|
if (ctx.userQuoted) {
|
|
153056
|
+
const parts = [ctx.userQuoted, previousRunsNote].filter(Boolean);
|
|
153048
153057
|
return `************* YOUR TASK *************
|
|
153049
153058
|
|
|
153050
|
-
${
|
|
153059
|
+
${parts.join("\n\n")}`;
|
|
153051
153060
|
}
|
|
153052
153061
|
const eventInstructions = ctx.payload.eventInstructions ?? "";
|
|
153053
|
-
if (eventInstructions) {
|
|
153054
|
-
const parts = [ctx.eventTitle, eventInstructions].filter(Boolean);
|
|
153062
|
+
if (eventInstructions || previousRunsNote) {
|
|
153063
|
+
const parts = [ctx.eventTitle, eventInstructions, previousRunsNote].filter(Boolean);
|
|
153055
153064
|
return `************* YOUR TASK *************
|
|
153056
153065
|
|
|
153057
153066
|
${parts.join("\n\n")}`;
|
|
@@ -153366,6 +153375,7 @@ var JsonPayload = type({
|
|
|
153366
153375
|
prompt: "string",
|
|
153367
153376
|
"triggerer?": "string | undefined",
|
|
153368
153377
|
"eventInstructions?": "string",
|
|
153378
|
+
"previousRunsNote?": "string",
|
|
153369
153379
|
"event?": "object",
|
|
153370
153380
|
"timeout?": "string | undefined",
|
|
153371
153381
|
"progressComment?": type({
|
|
@@ -153451,6 +153461,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
153451
153461
|
triggerer: jsonPayload?.triggerer ?? // it's not a common use case but GITHUB_ACTOR can be a user when the workflow is manually triggered by a user through GitHub Actions UI
|
|
153452
153462
|
(!isPullfrog(process.env.GITHUB_ACTOR) ? process.env.GITHUB_ACTOR : void 0),
|
|
153453
153463
|
eventInstructions: jsonPayload?.eventInstructions,
|
|
153464
|
+
previousRunsNote: jsonPayload?.previousRunsNote,
|
|
153454
153465
|
event,
|
|
153455
153466
|
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
153456
153467
|
cwd: resolveCwd(inputs.cwd),
|
|
@@ -153632,8 +153643,7 @@ async function fetchRunContext(params) {
|
|
|
153632
153643
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
153633
153644
|
try {
|
|
153634
153645
|
const headers = {
|
|
153635
|
-
Authorization: `Bearer ${params.token}
|
|
153636
|
-
"Content-Type": "application/json"
|
|
153646
|
+
Authorization: `Bearer ${params.token}`
|
|
153637
153647
|
};
|
|
153638
153648
|
if (params.oidcToken) {
|
|
153639
153649
|
headers["X-GitHub-OIDC-Token"] = params.oidcToken;
|
|
@@ -154049,7 +154059,7 @@ function formatBillingErrorSummary(error49, owner) {
|
|
|
154049
154059
|
return [
|
|
154050
154060
|
"**Add a card to start using Pullfrog Router.**",
|
|
154051
154061
|
"",
|
|
154052
|
-
"Router proxies OpenRouter at raw cost \u2014 no platform markup
|
|
154062
|
+
"Router proxies OpenRouter at raw cost \u2014 no platform markup. Add a card and we'll auto-reload your wallet so runs keep flowing.",
|
|
154053
154063
|
"",
|
|
154054
154064
|
`[Add a card \u2192](${billingConsoleUrl(owner, "model-access")})`
|
|
154055
154065
|
].join("\n");
|
|
@@ -154225,12 +154235,12 @@ async function persistLearnings(ctx) {
|
|
|
154225
154235
|
});
|
|
154226
154236
|
if (!response.ok) {
|
|
154227
154237
|
const error49 = await response.text().catch(() => "(no body)");
|
|
154228
|
-
log.
|
|
154238
|
+
log.warning(`learnings persist failed (${response.status}): ${error49}`);
|
|
154229
154239
|
return;
|
|
154230
154240
|
}
|
|
154231
154241
|
log.info("\xBB learnings updated");
|
|
154232
154242
|
} catch (err) {
|
|
154233
|
-
log.
|
|
154243
|
+
log.warning(`learnings persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
154234
154244
|
}
|
|
154235
154245
|
}
|
|
154236
154246
|
async function persistSummary(ctx) {
|
|
@@ -156513,7 +156523,7 @@ async function run2() {
|
|
|
156513
156523
|
}
|
|
156514
156524
|
|
|
156515
156525
|
// cli.ts
|
|
156516
|
-
var VERSION10 = "0.1.
|
|
156526
|
+
var VERSION10 = "0.1.5";
|
|
156517
156527
|
var bin = basename2(process.argv[1] || "");
|
|
156518
156528
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
156519
156529
|
var rawArgs = process.argv.slice(2);
|
package/dist/external.d.ts
CHANGED
|
@@ -201,6 +201,13 @@ export interface WriteablePayload {
|
|
|
201
201
|
triggerer?: string | undefined;
|
|
202
202
|
/** event-level instructions for this trigger type (flag-expanded server-side) */
|
|
203
203
|
eventInstructions?: string | undefined;
|
|
204
|
+
/**
|
|
205
|
+
* system-injected note about prior superseded runs (e.g. when the
|
|
206
|
+
* triggering @pullfrog comment is edited). rendered alongside the user's
|
|
207
|
+
* prompt rather than via eventInstructions so it survives user-prompt
|
|
208
|
+
* precedence.
|
|
209
|
+
*/
|
|
210
|
+
previousRunsNote?: string | undefined;
|
|
204
211
|
/** event data from webhook payload - discriminated union based on trigger field */
|
|
205
212
|
event: PayloadEvent;
|
|
206
213
|
/** timeout for agent run (e.g., "10m", "1h30m") - defaults to "1h" */
|
package/dist/index.js
CHANGED
|
@@ -107955,8 +107955,7 @@ var providers = {
|
|
|
107955
107955
|
"gpt-5-nano": {
|
|
107956
107956
|
displayName: "GPT Nano",
|
|
107957
107957
|
resolve: "opencode/gpt-5-nano",
|
|
107958
|
-
|
|
107959
|
-
isFree: true
|
|
107958
|
+
openRouterResolve: "openrouter/openai/gpt-5-nano"
|
|
107960
107959
|
},
|
|
107961
107960
|
"mimo-v2-pro-free": {
|
|
107962
107961
|
displayName: "MiMo V2 Pro",
|
|
@@ -108185,6 +108184,11 @@ async function apiFetch(options) {
|
|
|
108185
108184
|
if (bypassSecret) {
|
|
108186
108185
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
108187
108186
|
}
|
|
108187
|
+
if (!options.body) {
|
|
108188
|
+
for (const key of Object.keys(headers)) {
|
|
108189
|
+
if (key.toLowerCase() === "content-type") delete headers[key];
|
|
108190
|
+
}
|
|
108191
|
+
}
|
|
108188
108192
|
log.debug(`api fetch: ${options.method ?? "GET"} ${url4.pathname}`);
|
|
108189
108193
|
const init = {
|
|
108190
108194
|
method: options.method ?? "GET",
|
|
@@ -108873,8 +108877,11 @@ function sanitizeToolForGemini(tool2) {
|
|
|
108873
108877
|
}
|
|
108874
108878
|
function isGeminiRouted(ctx) {
|
|
108875
108879
|
const effective = ctx.payload.proxyModel ?? ctx.resolvedModel ?? ctx.payload.model;
|
|
108876
|
-
if (!effective) return
|
|
108877
|
-
|
|
108880
|
+
if (!effective) return true;
|
|
108881
|
+
const normalized = effective.toLowerCase();
|
|
108882
|
+
if (normalized.includes("gemini")) return true;
|
|
108883
|
+
if (!normalized.includes("/")) return true;
|
|
108884
|
+
return false;
|
|
108878
108885
|
}
|
|
108879
108886
|
|
|
108880
108887
|
// mcp/shared.ts
|
|
@@ -142306,7 +142313,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
142306
142313
|
// package.json
|
|
142307
142314
|
var package_default = {
|
|
142308
142315
|
name: "pullfrog",
|
|
142309
|
-
version: "0.1.
|
|
142316
|
+
version: "0.1.5",
|
|
142310
142317
|
type: "module",
|
|
142311
142318
|
bin: {
|
|
142312
142319
|
pullfrog: "dist/cli.mjs",
|
|
@@ -147195,8 +147202,7 @@ function stripProviderPrefix(specifier) {
|
|
|
147195
147202
|
const slashIndex = specifier.indexOf("/");
|
|
147196
147203
|
return slashIndex > 0 ? specifier.slice(slashIndex + 1) : specifier;
|
|
147197
147204
|
}
|
|
147198
|
-
function resolveEffort(
|
|
147199
|
-
if (model?.includes("opus")) return "max";
|
|
147205
|
+
function resolveEffort(_model) {
|
|
147200
147206
|
return "high";
|
|
147201
147207
|
}
|
|
147202
147208
|
function tailLines(text, maxCodeUnits) {
|
|
@@ -152681,6 +152687,7 @@ function buildRuntimeContext(ctx) {
|
|
|
152681
152687
|
"~pullfrog": _,
|
|
152682
152688
|
prompt: _p,
|
|
152683
152689
|
eventInstructions: _ei,
|
|
152690
|
+
previousRunsNote: _prn,
|
|
152684
152691
|
event: _e,
|
|
152685
152692
|
...payloadRest
|
|
152686
152693
|
} = ctx.payload;
|
|
@@ -152761,14 +152768,16 @@ In case of conflict between instructions, follow this precedence (highest to low
|
|
|
152761
152768
|
2. User prompt
|
|
152762
152769
|
3. Event-level instructions`;
|
|
152763
152770
|
function buildTaskSection(ctx) {
|
|
152771
|
+
const previousRunsNote = ctx.payload.previousRunsNote?.trim() ?? "";
|
|
152764
152772
|
if (ctx.userQuoted) {
|
|
152773
|
+
const parts = [ctx.userQuoted, previousRunsNote].filter(Boolean);
|
|
152765
152774
|
return `************* YOUR TASK *************
|
|
152766
152775
|
|
|
152767
|
-
${
|
|
152776
|
+
${parts.join("\n\n")}`;
|
|
152768
152777
|
}
|
|
152769
152778
|
const eventInstructions = ctx.payload.eventInstructions ?? "";
|
|
152770
|
-
if (eventInstructions) {
|
|
152771
|
-
const parts = [ctx.eventTitle, eventInstructions].filter(Boolean);
|
|
152779
|
+
if (eventInstructions || previousRunsNote) {
|
|
152780
|
+
const parts = [ctx.eventTitle, eventInstructions, previousRunsNote].filter(Boolean);
|
|
152772
152781
|
return `************* YOUR TASK *************
|
|
152773
152782
|
|
|
152774
152783
|
${parts.join("\n\n")}`;
|
|
@@ -153083,6 +153092,7 @@ var JsonPayload = type({
|
|
|
153083
153092
|
prompt: "string",
|
|
153084
153093
|
"triggerer?": "string | undefined",
|
|
153085
153094
|
"eventInstructions?": "string",
|
|
153095
|
+
"previousRunsNote?": "string",
|
|
153086
153096
|
"event?": "object",
|
|
153087
153097
|
"timeout?": "string | undefined",
|
|
153088
153098
|
"progressComment?": type({
|
|
@@ -153168,6 +153178,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
|
|
|
153168
153178
|
triggerer: jsonPayload?.triggerer ?? // it's not a common use case but GITHUB_ACTOR can be a user when the workflow is manually triggered by a user through GitHub Actions UI
|
|
153169
153179
|
(!isPullfrog(process.env.GITHUB_ACTOR) ? process.env.GITHUB_ACTOR : void 0),
|
|
153170
153180
|
eventInstructions: jsonPayload?.eventInstructions,
|
|
153181
|
+
previousRunsNote: jsonPayload?.previousRunsNote,
|
|
153171
153182
|
event,
|
|
153172
153183
|
timeout: inputs.timeout ?? jsonPayload?.timeout,
|
|
153173
153184
|
cwd: resolveCwd(inputs.cwd),
|
|
@@ -153349,8 +153360,7 @@ async function fetchRunContext(params) {
|
|
|
153349
153360
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
153350
153361
|
try {
|
|
153351
153362
|
const headers = {
|
|
153352
|
-
Authorization: `Bearer ${params.token}
|
|
153353
|
-
"Content-Type": "application/json"
|
|
153363
|
+
Authorization: `Bearer ${params.token}`
|
|
153354
153364
|
};
|
|
153355
153365
|
if (params.oidcToken) {
|
|
153356
153366
|
headers["X-GitHub-OIDC-Token"] = params.oidcToken;
|
|
@@ -153766,7 +153776,7 @@ function formatBillingErrorSummary(error49, owner) {
|
|
|
153766
153776
|
return [
|
|
153767
153777
|
"**Add a card to start using Pullfrog Router.**",
|
|
153768
153778
|
"",
|
|
153769
|
-
"Router proxies OpenRouter at raw cost \u2014 no platform markup
|
|
153779
|
+
"Router proxies OpenRouter at raw cost \u2014 no platform markup. Add a card and we'll auto-reload your wallet so runs keep flowing.",
|
|
153770
153780
|
"",
|
|
153771
153781
|
`[Add a card \u2192](${billingConsoleUrl(owner, "model-access")})`
|
|
153772
153782
|
].join("\n");
|
|
@@ -153942,12 +153952,12 @@ async function persistLearnings(ctx) {
|
|
|
153942
153952
|
});
|
|
153943
153953
|
if (!response.ok) {
|
|
153944
153954
|
const error49 = await response.text().catch(() => "(no body)");
|
|
153945
|
-
log.
|
|
153955
|
+
log.warning(`learnings persist failed (${response.status}): ${error49}`);
|
|
153946
153956
|
return;
|
|
153947
153957
|
}
|
|
153948
153958
|
log.info("\xBB learnings updated");
|
|
153949
153959
|
} catch (err) {
|
|
153950
|
-
log.
|
|
153960
|
+
log.warning(`learnings persist failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
153951
153961
|
}
|
|
153952
153962
|
}
|
|
153953
153963
|
async function persistSummary(ctx) {
|
package/dist/internal.js
CHANGED
|
@@ -224,8 +224,7 @@ var providers = {
|
|
|
224
224
|
"gpt-5-nano": {
|
|
225
225
|
displayName: "GPT Nano",
|
|
226
226
|
resolve: "opencode/gpt-5-nano",
|
|
227
|
-
|
|
228
|
-
isFree: true
|
|
227
|
+
openRouterResolve: "openrouter/openai/gpt-5-nano"
|
|
229
228
|
},
|
|
230
229
|
"mimo-v2-pro-free": {
|
|
231
230
|
displayName: "MiMo V2 Pro",
|
|
@@ -9,9 +9,20 @@ export declare function sanitizeForGemini(schema: unknown): unknown;
|
|
|
9
9
|
export declare function wrapSchemaForGemini(schema: StandardSchemaV1<any>): StandardSchemaV1<any>;
|
|
10
10
|
export declare function sanitizeToolForGemini<T extends Tool<any, any>>(tool: T): T;
|
|
11
11
|
/**
|
|
12
|
-
* true when the effective upstream model is
|
|
13
|
-
* language API
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* true when the effective upstream model is — or might become — google
|
|
13
|
+
* generative language API traffic. matches:
|
|
14
|
+
* - direct `google/*`, opencode `opencode/gemini-*`, openrouter
|
|
15
|
+
* `openrouter/google/gemini-*` (slug substring "gemini" wins).
|
|
16
|
+
* - any unresolved specifier: `undefined`, `"auto"`, or a slug that
|
|
17
|
+
* didn't map through the alias registry (no `provider/` prefix).
|
|
18
|
+
* these flow through the agent's own auto-select, which may land
|
|
19
|
+
* on gemini *after* the MCP server has already registered tools —
|
|
20
|
+
* at which point sanitization is too late to apply. erring on the
|
|
21
|
+
* side of sanitizing is safe: cases 1 + 2 are universally
|
|
22
|
+
* compatible JSON-Schema normalizations (enum-only → typed string,
|
|
23
|
+
* collapsible const-unions → string enum); case 3 is gemini-
|
|
24
|
+
* specific but only fires on non-collapsible unions, which arktype
|
|
25
|
+
* does not emit for our current tool schemas. see issue #676 for
|
|
26
|
+
* the prod failure that motivated this widening.
|
|
16
27
|
*/
|
|
17
28
|
export declare function isGeminiRouted(ctx: ToolContext): boolean;
|
package/dist/utils/payload.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const JsonPayload: import("arktype/internal/variants/object.ts").
|
|
|
7
7
|
model?: string | undefined;
|
|
8
8
|
triggerer?: string | undefined;
|
|
9
9
|
eventInstructions?: string;
|
|
10
|
+
previousRunsNote?: string;
|
|
10
11
|
event?: object;
|
|
11
12
|
timeout?: string | undefined;
|
|
12
13
|
progressComment?: {
|
|
@@ -34,6 +35,7 @@ export declare function resolvePayload(resolvedPromptInput: ResolvedPromptInput,
|
|
|
34
35
|
prompt: string;
|
|
35
36
|
triggerer: string | undefined;
|
|
36
37
|
eventInstructions: string | undefined;
|
|
38
|
+
previousRunsNote: string | undefined;
|
|
37
39
|
event: PayloadEvent;
|
|
38
40
|
timeout: string | undefined;
|
|
39
41
|
cwd: string | undefined;
|