pullfrog 0.1.50 → 0.1.52

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.
@@ -3,7 +3,7 @@
3
3
  * Re-exports shared types, values, and utilities needed by the Next.js app.
4
4
  */
5
5
  export type { AuthorPermission, AutoTier, EffortPosition, ModelAlias, ModelProvider, Payload, PayloadEvent, ProviderConfig, PushPermission, ShellPermission, ToolPermission, WriteablePayload, XrepoConfig, } from "../external.ts";
6
- export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isEffortPosition, modelAliases, modelHasStoredAuth, offeredRungs, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, rungLabel, rungPosition, } from "../external.ts";
6
+ export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, modelAliases, modelHasStoredAuth, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, rungLabel, rungPosition, } from "../external.ts";
7
7
  export type { Mode } from "../modes.ts";
8
8
  export { modes } from "../modes.ts";
9
9
  export { commercialPaywallBody } from "../utils/billingErrors.ts";
package/dist/internal.js CHANGED
@@ -100,7 +100,11 @@ var providers = {
100
100
  envVars: ["OPENAI_API_KEY"],
101
101
  managedCredentials: ["CODEX_AUTH_JSON"],
102
102
  models: {
103
- gpt: {
103
+ // Sol/Terra/Luna are OpenAI's durable capability tiers, so they ARE the
104
+ // brand-tier names the slug convention asks for — the pre-5.6 `gpt` /
105
+ // `gpt-pro` / `gpt-mini` slugs are holdovers from the retired GPT / GPT Pro
106
+ // / GPT Mini tiering and are carried below as deprecated aliases.
107
+ "gpt-sol": {
104
108
  displayName: "GPT Sol",
105
109
  resolve: "openai/gpt-5.6-sol",
106
110
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -111,24 +115,23 @@ var providers = {
111
115
  // Sol served at reasoning.mode=pro — same $/token as Sol, just more tokens
112
116
  // burned; not a pricier premium tier. models.dev has no -pro id, so direct-key
113
117
  // (BYOK) resolves to plain Sol; only the Router/OpenRouter path gets sol-pro.
114
- "gpt-pro": {
118
+ "gpt-sol-pro": {
115
119
  displayName: "GPT Sol Pro",
116
120
  description: "Maximum reasoning effort",
117
121
  resolve: "openai/gpt-5.6-sol",
118
122
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
119
123
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
120
- subagentModel: "gpt"
124
+ subagentModel: "gpt-sol"
121
125
  },
122
- // gpt-5.6's balanced mid-tier (Sol/Terra/Luna are durable capability tiers,
123
- // not version bumps). selectable on its own and doubles as `gpt`'s cheaper
124
- // lens-fanout subagent — replaces the old hidden gpt-5.4 subagent target.
126
+ // gpt-5.6's balanced mid-tier. selectable on its own and doubles as Sol's
127
+ // cheaper lens-fanout subagent replaces the old hidden gpt-5.4 target.
125
128
  "gpt-terra": {
126
129
  displayName: "GPT Terra",
127
130
  resolve: "openai/gpt-5.6-terra",
128
131
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
129
132
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
130
133
  },
131
- "gpt-mini": {
134
+ "gpt-luna": {
132
135
  displayName: "GPT Luna",
133
136
  resolve: "openai/gpt-5.6-luna",
134
137
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -143,20 +146,40 @@ var providers = {
143
146
  displayName: "GPT Codex",
144
147
  resolve: "openai/gpt-5.3-codex",
145
148
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
146
- fallback: "openai/gpt"
149
+ fallback: "openai/gpt-sol"
147
150
  },
148
151
  "gpt-codex-mini": {
149
152
  displayName: "GPT Codex Mini",
150
153
  resolve: "openai/gpt-5.1-codex-mini",
151
154
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
152
- fallback: "openai/gpt-mini"
155
+ fallback: "openai/gpt-luna"
156
+ },
157
+ // pre-5.6 tier slugs. the tiers themselves were renamed Sol/Sol Pro/Luna,
158
+ // so these fold forward rather than describing anything that still runs.
159
+ gpt: {
160
+ displayName: "GPT",
161
+ resolve: "openai/gpt-5.6-sol",
162
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
163
+ fallback: "openai/gpt-sol"
164
+ },
165
+ "gpt-pro": {
166
+ displayName: "GPT Pro",
167
+ resolve: "openai/gpt-5.6-sol",
168
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
169
+ fallback: "openai/gpt-sol-pro"
170
+ },
171
+ "gpt-mini": {
172
+ displayName: "GPT Mini",
173
+ resolve: "openai/gpt-5.6-luna",
174
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
175
+ fallback: "openai/gpt-luna"
153
176
  },
154
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
177
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
155
178
  "gpt-5.4": {
156
179
  displayName: "GPT 5.4",
157
180
  resolve: "openai/gpt-5.4",
158
181
  openRouterResolve: "openrouter/openai/gpt-5.4",
159
- fallback: "openai/gpt"
182
+ fallback: "openai/gpt-sol"
160
183
  },
161
184
  o3: {
162
185
  displayName: "O3",
@@ -232,12 +255,20 @@ var providers = {
232
255
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro",
233
256
  preferred: true
234
257
  },
258
+ // DeepSeek upgraded the `deepseek-v4-flash` API model in place to the
259
+ // 0731 release, but OpenRouter forked it into a separate `-0731` id and
260
+ // left the April preview live at a HIGHER price — so the direct
261
+ // `resolve` needs no version and the OpenRouter route must be pinned.
262
+ // 0731 publishes a DIFFERENT OpenRouter ladder to both the April preview
263
+ // and Pro (`high, xhigh`) — it gained a `low` rung and renamed the top to
264
+ // `max`. that makes `low`, not `high`, position 0 on this route, which is
265
+ // why the OSS effort floor in `main.ts` pins the `high` rung by name.
235
266
  "deepseek-flash": {
236
267
  displayName: "DeepSeek Flash",
237
268
  resolve: "deepseek/deepseek-v4-flash",
238
269
  effort: ["high", "max"],
239
- openRouterEffort: ["high", "xhigh"],
240
- openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
270
+ openRouterEffort: ["low", "high", "max"],
271
+ openRouterResolve: "openrouter/deepseek/deepseek-v4-flash-0731"
241
272
  },
242
273
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
243
274
  // upgrade existing users to the v4 family via the fallback chain.
@@ -306,30 +337,30 @@ var providers = {
306
337
  resolve: "opencode/claude-haiku-4-5",
307
338
  openRouterResolve: "openrouter/anthropic/claude-haiku-4.5"
308
339
  },
309
- gpt: {
340
+ "gpt-sol": {
310
341
  displayName: "GPT Sol",
311
342
  resolve: "opencode/gpt-5.6-sol",
312
343
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
313
344
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
314
345
  subagentModel: "gpt-terra"
315
346
  },
316
- // see openai/gpt-pro — Zen has no -pro id, so direct resolves to plain Sol.
317
- "gpt-pro": {
347
+ // see openai/gpt-sol-pro — Zen has no -pro id, so direct resolves to plain Sol.
348
+ "gpt-sol-pro": {
318
349
  displayName: "GPT Sol Pro",
319
350
  description: "Maximum reasoning effort",
320
351
  resolve: "opencode/gpt-5.6-sol",
321
352
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
322
353
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
323
- subagentModel: "gpt"
354
+ subagentModel: "gpt-sol"
324
355
  },
325
- // gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
356
+ // gpt-5.6 balanced mid-tier — selectable + Sol's subagent. see openai above.
326
357
  "gpt-terra": {
327
358
  displayName: "GPT Terra",
328
359
  resolve: "opencode/gpt-5.6-terra",
329
360
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
330
361
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
331
362
  },
332
- "gpt-mini": {
363
+ "gpt-luna": {
333
364
  displayName: "GPT Luna",
334
365
  resolve: "opencode/gpt-5.6-luna",
335
366
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -340,20 +371,39 @@ var providers = {
340
371
  displayName: "GPT Codex",
341
372
  resolve: "opencode/gpt-5.3-codex",
342
373
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
343
- fallback: "opencode/gpt"
374
+ fallback: "opencode/gpt-sol"
344
375
  },
345
376
  "gpt-codex-mini": {
346
377
  displayName: "GPT Codex Mini",
347
378
  resolve: "opencode/gpt-5.1-codex-mini",
348
379
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
349
- fallback: "opencode/gpt-mini"
380
+ fallback: "opencode/gpt-luna"
381
+ },
382
+ // pre-5.6 tier slugs — see openai provider above.
383
+ gpt: {
384
+ displayName: "GPT",
385
+ resolve: "opencode/gpt-5.6-sol",
386
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
387
+ fallback: "opencode/gpt-sol"
388
+ },
389
+ "gpt-pro": {
390
+ displayName: "GPT Pro",
391
+ resolve: "opencode/gpt-5.6-sol",
392
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
393
+ fallback: "opencode/gpt-sol-pro"
394
+ },
395
+ "gpt-mini": {
396
+ displayName: "GPT Mini",
397
+ resolve: "opencode/gpt-5.6-luna",
398
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
399
+ fallback: "opencode/gpt-luna"
350
400
  },
351
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
401
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
352
402
  "gpt-5.4": {
353
403
  displayName: "GPT 5.4",
354
404
  resolve: "opencode/gpt-5.4",
355
405
  openRouterResolve: "openrouter/openai/gpt-5.4",
356
- fallback: "opencode/gpt"
406
+ fallback: "opencode/gpt-sol"
357
407
  },
358
408
  "gemini-pro": {
359
409
  displayName: "Gemini Pro",
@@ -509,30 +559,30 @@ var providers = {
509
559
  // alias): after the Sol/Terra/Luna rename, ~gpt-mini-latest no longer maps
510
560
  // to Luna, so rolling aliases would silently diverge `gpt`/`gpt-mini` from
511
561
  // the chosen tiers across funding paths.
512
- gpt: {
562
+ "gpt-sol": {
513
563
  displayName: "GPT Sol",
514
564
  resolve: "openrouter/openai/gpt-5.6-sol",
515
565
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
516
566
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
517
567
  subagentModel: "gpt-terra"
518
568
  },
519
- // see openai/gpt-pro. openrouter serves sol-pro directly on both routes.
520
- "gpt-pro": {
569
+ // see openai/gpt-sol-pro. openrouter serves sol-pro directly on both routes.
570
+ "gpt-sol-pro": {
521
571
  displayName: "GPT Sol Pro",
522
572
  description: "Maximum reasoning effort",
523
573
  resolve: "openrouter/openai/gpt-5.6-sol-pro",
524
574
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
525
575
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
526
- subagentModel: "gpt"
576
+ subagentModel: "gpt-sol"
527
577
  },
528
- // gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
578
+ // gpt-5.6 balanced mid-tier — selectable + Sol's subagent. see openai above.
529
579
  "gpt-terra": {
530
580
  displayName: "GPT Terra",
531
581
  resolve: "openrouter/openai/gpt-5.6-terra",
532
582
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
533
583
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
534
584
  },
535
- "gpt-mini": {
585
+ "gpt-luna": {
536
586
  displayName: "GPT Luna",
537
587
  resolve: "openrouter/openai/gpt-5.6-luna",
538
588
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -543,20 +593,39 @@ var providers = {
543
593
  displayName: "GPT Codex",
544
594
  resolve: "openrouter/openai/gpt-5.3-codex",
545
595
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
546
- fallback: "openrouter/gpt"
596
+ fallback: "openrouter/gpt-sol"
547
597
  },
548
598
  "gpt-codex-mini": {
549
599
  displayName: "GPT Codex Mini",
550
600
  resolve: "openrouter/openai/gpt-5.1-codex-mini",
551
601
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
552
- fallback: "openrouter/gpt-mini"
602
+ fallback: "openrouter/gpt-luna"
603
+ },
604
+ // pre-5.6 tier slugs — see openai provider above.
605
+ gpt: {
606
+ displayName: "GPT",
607
+ resolve: "openrouter/openai/gpt-5.6-sol",
608
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
609
+ fallback: "openrouter/gpt-sol"
553
610
  },
554
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
611
+ "gpt-pro": {
612
+ displayName: "GPT Pro",
613
+ resolve: "openrouter/openai/gpt-5.6-sol-pro",
614
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
615
+ fallback: "openrouter/gpt-sol-pro"
616
+ },
617
+ "gpt-mini": {
618
+ displayName: "GPT Mini",
619
+ resolve: "openrouter/openai/gpt-5.6-luna",
620
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
621
+ fallback: "openrouter/gpt-luna"
622
+ },
623
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
555
624
  "gpt-5.4": {
556
625
  displayName: "GPT 5.4",
557
626
  resolve: "openrouter/openai/gpt-5.4",
558
627
  openRouterResolve: "openrouter/openai/gpt-5.4",
559
- fallback: "openrouter/gpt"
628
+ fallback: "openrouter/gpt-sol"
560
629
  },
561
630
  "o4-mini": {
562
631
  displayName: "O4 Mini",
@@ -591,9 +660,9 @@ var providers = {
591
660
  },
592
661
  "deepseek-flash": {
593
662
  displayName: "DeepSeek Flash",
594
- resolve: "openrouter/deepseek/deepseek-v4-flash",
595
- effort: ["high", "xhigh"],
596
- openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
663
+ resolve: "openrouter/deepseek/deepseek-v4-flash-0731",
664
+ effort: ["low", "high", "max"],
665
+ openRouterResolve: "openrouter/deepseek/deepseek-v4-flash-0731"
597
666
  },
598
667
  // legacy alias — deepseek retires this on 2026-07-24; transparently
599
668
  // upgrade existing users to the v4 family via the fallback chain.
@@ -688,7 +757,7 @@ var modelAliases = Object.entries(providers).flatMap(
688
757
  var AUTO_EFFICIENT = "auto/efficient";
689
758
  var AUTO_INTELLIGENT = "auto/intelligent";
690
759
  var AUTO_TIER_TARGET = {
691
- [AUTO_EFFICIENT]: "deepseek/deepseek-pro",
760
+ [AUTO_EFFICIENT]: "deepseek/deepseek-flash",
692
761
  [AUTO_INTELLIGENT]: "anthropic/claude-opus"
693
762
  };
694
763
  function isAutoTier(slug) {
@@ -744,6 +813,26 @@ if (!defaultProxyAlias?.openRouterResolve) {
744
813
  }
745
814
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
746
815
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
816
+ var OSS_MODEL_ALLOWLIST = [
817
+ "deepseek/deepseek-flash",
818
+ "deepseek/deepseek-pro",
819
+ "openai/gpt-luna",
820
+ "openrouter/minimax-m2.5",
821
+ "moonshotai/kimi-k2"
822
+ ];
823
+ var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
824
+ var ossAllowedTargets = new Set(
825
+ OSS_MODEL_ALLOWLIST.map((slug) => {
826
+ const target = resolveOpenRouterModel(slug);
827
+ if (!target) throw new Error(`OSS_MODEL_ALLOWLIST: ${slug} has no openRouterResolve`);
828
+ return target;
829
+ })
830
+ );
831
+ function isOssAllowedModel(slug) {
832
+ if (!slug) return false;
833
+ const target = resolveOpenRouterModel(slug);
834
+ return target !== void 0 && ossAllowedTargets.has(target);
835
+ }
747
836
  function getAutoSelectHintModel() {
748
837
  return defaultProxyDisplayName;
749
838
  }
@@ -1197,7 +1286,7 @@ function formatModelLabel(params) {
1197
1286
  const ossBase = `\`${displayName}\` (free via [Pullfrog for OSS](https://pullfrog.com/for-oss))`;
1198
1287
  if (params.clamped?.reason !== "oss") return ossBase;
1199
1288
  const configured = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
1200
- return `${ossBase} (${configured} not used \u2014 the program covers this model; add its [provider key](https://docs.pullfrog.com/models) to run your pick)`;
1289
+ return `${ossBase} (${configured} not used \u2014 pick one of the [funded models](https://docs.pullfrog.com/models#pullfrog-for-oss) or add a [provider key](https://docs.pullfrog.com/keys) to run your own)`;
1201
1290
  }
1202
1291
  const base = alias?.isFree ? `\`${displayName}\` (free)` : `\`${displayName}\``;
1203
1292
  if (params.fallbackFrom) {
@@ -1597,6 +1686,8 @@ export {
1597
1686
  LEAPING_INTO_ACTION_PREFIX,
1598
1687
  MAX_LEARNINGS_LENGTH,
1599
1688
  OAuthInvalidGrantError,
1689
+ OSS_MODEL_ALLOWLIST,
1690
+ OSS_RECOMMENDED_MODEL,
1600
1691
  PULLFROG_DIVIDER,
1601
1692
  RUN_STATUS_CHECK_NAME,
1602
1693
  TIMEOUT_DISABLED,
@@ -1619,6 +1710,7 @@ export {
1619
1710
  isCardGatedModel,
1620
1711
  isEffortPosition,
1621
1712
  isLeapingIntoActionCommentBody,
1713
+ isOssAllowedModel,
1622
1714
  isPullfrog,
1623
1715
  isValidTimeString,
1624
1716
  modelAliases,
@@ -1,7 +1,7 @@
1
1
  import type { ToolContext } from "./server.ts";
2
2
  export declare const ShellParams: import("arktype/internal/variants/object.ts").ObjectType<{
3
3
  command: string;
4
- description: string;
4
+ description?: string;
5
5
  timeout?: number;
6
6
  working_directory?: string;
7
7
  background?: boolean;
@@ -16,13 +16,13 @@ export declare function getSandboxMethod(): SandboxMethod;
16
16
  export declare const MAX_OUTPUT_CHARS = 5000;
17
17
  export declare function ShellTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
18
18
  command: string;
19
- description: string;
19
+ description?: string;
20
20
  timeout?: number;
21
21
  working_directory?: string;
22
22
  background?: boolean;
23
23
  }, {
24
24
  command: string;
25
- description: string;
25
+ description?: string;
26
26
  timeout?: number;
27
27
  working_directory?: string;
28
28
  background?: boolean;
package/dist/models.d.ts CHANGED
@@ -145,11 +145,11 @@ export declare const modelAliases: ModelAlias[];
145
145
  * concrete alias by `resolveDisplayAlias` below, so every downstream consumer
146
146
  * (CLI resolve, OpenRouter resolve, footer label) handles them transparently.
147
147
  *
148
- * `efficient` mirrors the OSS/default subsidy model (DeepSeek V4 Pro beats
149
- * Kimi K2.7 on agentic-review quality at ~4-5x lower cost, run at whatever
150
- * effort the repo asks for, clamped to its published ladder); `intelligent` is the
151
- * frontier pick (Claude Opus). a `null` model means the tier hasn't been
152
- * pinned: callers default by card status via `defaultAutoTier`.
148
+ * `efficient` mirrors the OSS/default subsidy model (DeepSeek Flashthe 0731
149
+ * release is DeepSeek's first officially-shipped V4, where Pro is still the
150
+ * April preview, and it costs ~0.45x Pro on our cache-heavy review workload);
151
+ * `intelligent` is the frontier pick (Claude Opus). a `null` model means the
152
+ * tier hasn't been pinned: callers default by card status via `defaultAutoTier`.
153
153
  */
154
154
  export declare const AUTO_EFFICIENT = "auto/efficient";
155
155
  export declare const AUTO_INTELLIGENT = "auto/intelligent";
@@ -235,6 +235,30 @@ export declare function resolveModelRung(params: {
235
235
  useOpenRouter: boolean;
236
236
  }): string | undefined;
237
237
  export declare const DEFAULT_PROXY_MODEL: string;
238
+ /**
239
+ * the models Pullfrog is willing to fund on the OSS program. an accepted OSS
240
+ * repo may pick any of these and run-context honors the pick; anything else
241
+ * falls back to `DEFAULT_PROXY_MODEL`, so a subsidized run can never land on a
242
+ * frontier model.
243
+ *
244
+ * membership is a spend decision, so it lives here as a literal rather than a
245
+ * DB toggle — changing it is a deploy, which is the right friction. costs below
246
+ * are modelled on the measured OSS token mix, where cache reads are ~87.5% of
247
+ * input and list price therefore ranks models WRONG: Luna 0.39x, Flash 0.45x,
248
+ * Pro 1.00x, MiniMax M2 1.30x, Kimi 3.88x modelled — but 7.25x as actually
249
+ * measured over the pre-#1063 Kimi era, which is the number to trust.
250
+ */
251
+ export declare const OSS_MODEL_ALLOWLIST: readonly string[];
252
+ /** the pick the console badges. DERIVED from the efficient tier rather than
253
+ * restated, so the badge cannot drift from the model that actually runs — a
254
+ * second literal here would be an invariant nothing enforces. */
255
+ export declare const OSS_RECOMMENDED_MODEL: string;
256
+ /**
257
+ * whether an OSS repo's stored pick is one the program funds. resolves through
258
+ * the fallback chain first, so `auto/*` sentinels and deprecated slugs are
259
+ * judged by the model that actually runs.
260
+ */
261
+ export declare function isOssAllowedModel(slug: string | null | undefined): slug is string;
238
262
  /** short label for the model auto-select picks today (console hint copy). */
239
263
  export declare function getAutoSelectHintModel(): string;
240
264
  /** env var that supplies the Bedrock model ID for the `bedrock/byok` slug. */
@@ -1,3 +1,11 @@
1
+ /**
2
+ * whether the operator asked for debug output — GitHub's own "re-run with debug
3
+ * logging" (`RUNNER_DEBUG=1`), the `ACTIONS_STEP_DEBUG=true` repo secret, or a
4
+ * local `LOG_LEVEL=debug`. lives here rather than in `log.ts` because this
5
+ * module imports only `node:perf_hooks`, so every other util can depend on it
6
+ * without a cycle. one switch raises every diagnostic we own.
7
+ */
8
+ export declare function isDebugEnabled(): boolean;
1
9
  /**
2
10
  * generic `spawn()` idle default for ordinary short-lived subprocesses (prep
3
11
  * probes, package-manager invocations, dependency installs). these should be
@@ -53,15 +53,19 @@ export declare function validateAgentApiKey(params: {
53
53
  */
54
54
  export declare function isApiKeyAuthError(text: string): boolean;
55
55
  /**
56
- * Expired OAuth-connection credential shapes (#931) — the fix is to
57
- * re-authenticate the provider connection (`pullfrog auth <provider>`), not
58
- * to rotate a repo-secret API key, so `formatApiKeyErrorSummary` renders
59
- * distinct copy for these. Patterns are deliberately narrow:
60
- * "authentication token has expired" (not bare "token has expired") so a
61
- * GitHub installation-token expiry can't be misread as an LLM key problem.
62
- * also covers server-side revocation ("authentication token has been
63
- * invalidated", OpenAI `token_invalidated`, #1041) and the Claude CLI's
64
- * "OAuth access token has expired" phrasing (#1072) same remediation.
56
+ * Dead OAuth-connection credential — the provider is telling us the token
57
+ * itself is finished (expired, invalidated, revoked, or unrecognised), and the
58
+ * only fix is to re-authenticate the connection (`pullfrog auth <provider>`),
59
+ * never to rotate a repo-secret API key. `formatApiKeyErrorSummary` renders
60
+ * distinct copy for the whole class.
61
+ *
62
+ * Match the SHAPE, not the sentence. Four prior issues (#931, #1041, #1072,
63
+ * #1122) each landed one more literal and the next provider rewording walked
64
+ * straight through, so these patterns are parameterised over the two things
65
+ * that vary — which token noun the provider uses, and which terminal state it
66
+ * reports. Still deliberately narrow on the noun ("authentication token" /
67
+ * "OAuth access token", never bare "token") so a GitHub installation-token
68
+ * expiry can't be misread as an LLM credential problem.
65
69
  */
66
70
  export declare function isOAuthCredentialExpiredError(text: string): boolean;
67
71
  /**
@@ -70,6 +74,7 @@ export declare function isOAuthCredentialExpiredError(text: string): boolean;
70
74
  * user controls fixes it, so it gets its own copy instead of the re-auth CTA.
71
75
  */
72
76
  export declare function isClaudeSubscriptionDisabledError(text: string): boolean;
77
+ export declare function isClaudeSessionLimitError(text: string): boolean;
73
78
  /**
74
79
  * Friendly Markdown summary for both the missing-key and invalid-key cases.
75
80
  * Used in the catch / result-failure paths in `main.ts` to overwrite the raw
@@ -17,7 +17,20 @@ type SafeGitSubcommand = "fetch" | "push";
17
17
  type GitAuthOptions = {
18
18
  token: string;
19
19
  cwd?: string;
20
+ /**
21
+ * re-mint the git token when GitHub hands out one its git edge never accepts.
22
+ * when present, an auth-class failure is retried ONCE with a fresh token.
23
+ */
24
+ refreshGitToken?: ((stale: string) => Promise<string>) | undefined;
20
25
  };
26
+ /**
27
+ * installation-token 401s on git. GitHub intermittently mints a token its git
28
+ * edge never accepts, so retrying the SAME token never recovers — only a
29
+ * re-mint does. lives here rather than next to `classifyPushError` in
30
+ * `mcp/git.ts` because the fetch path needs it too and `git.ts` imports this
31
+ * module, not the other way round. see #1115.
32
+ */
33
+ export declare const TRANSIENT_AUTH_PATTERNS: RegExp[];
21
34
  type GitResult = {
22
35
  stdout: string;
23
36
  stderr: string;
@@ -34,8 +34,10 @@ export type ModelAccessDecision = {
34
34
  * decide whether an (already-resolved) requested model can run, and how.
35
35
  *
36
36
  * - non-explicit / no model → `ok` (caller's missing-key validation applies).
37
- * - proxy active + OSS → only the funded subsidy target routes; a different
38
- * model needs the repo's own key (`byok`) else `error("oss")`.
37
+ * - proxy active + OSS → the funded subsidy target and anything else on
38
+ * `OSS_MODEL_ALLOWLIST` route; a model off the list needs the repo's own key
39
+ * (`byok`) else `error("oss")`. the allowlist arm is what keeps
40
+ * `--model=<allowlisted>` from hard-failing on a pick the console offers.
39
41
  * - proxy active + Router → honor any Router-servable model (`proxy`); fall to
40
42
  * BYOK when locally authorized, else `error("router")`.
41
43
  * - no proxy → the resolved model must be locally authorized, else
@@ -47,3 +47,25 @@ export interface EnsurePackageManagerParams {
47
47
  * still works; we just don't get our version guarantee.
48
48
  */
49
49
  export declare function ensurePackageManager(params: EnsurePackageManagerParams): Promise<boolean>;
50
+ /** `SupportedPackageManager` plus deno, which corepack never manages. */
51
+ export type ProvisionablePackageManager = SupportedPackageManager | "deno";
52
+ /**
53
+ * Put the project's package manager on PATH, by whichever route provisions it —
54
+ * corepack for pnpm/yarn, `npm i -g` for bun, the install script for deno.
55
+ * Returns an error string on failure, else null.
56
+ *
57
+ * Callers must gate this on shell being enabled; provisioning executes code.
58
+ *
59
+ * Idempotent by construction (`isCommandAvailable` short-circuits and
60
+ * `ensurePackageManager` caches on a `--version` match), which is what lets
61
+ * `main.ts` call it BEFORE the `setup` lifecycle hook and the prep phase call it
62
+ * again later for the cost of one `which`. That ordering is the point: a `setup`
63
+ * hook running `bun install` used to die with `bun: command not found` 0.8s
64
+ * before Pullfrog installed bun itself, because the pre-hook site only ever
65
+ * asked corepack — which ignores bun and deno entirely. See #1121.
66
+ */
67
+ export declare function provisionPackageManager(params: {
68
+ name: ProvisionablePackageManager;
69
+ declared: PackageManagerSpec | null;
70
+ binDir: string;
71
+ }): Promise<string | null>;
@@ -32,7 +32,26 @@ type ComputeIncrementalDiffParams = {
32
32
  * - patch-text diffing (interdiff / diff-of-diffs): fragile, hunk offset noise on rebase
33
33
  * - range-diff on raw commit ranges: confused by commit reorganization across force-pushes
34
34
  */
35
- export declare function computeIncrementalDiff(params: ComputeIncrementalDiffParams): string | null;
35
+ export type IncrementalDiffResult =
36
+ /** range-diff ran and produced a delta */
37
+ {
38
+ status: "ok";
39
+ diff: string;
40
+ }
41
+ /** range-diff ran and the two versions are identical */
42
+ | {
43
+ status: "empty";
44
+ }
45
+ /** range-diff could not run — most often `beforeSha` has no ancestry to
46
+ * merge-base against on a shallow clone. distinct from "empty" on purpose:
47
+ * they were the same `null` before, so `checkout_pr` could not tell the
48
+ * agent whether there was nothing to see or whether we had simply failed.
49
+ * see #1139. */
50
+ | {
51
+ status: "unavailable";
52
+ reason: string;
53
+ };
54
+ export declare function computeIncrementalDiff(params: ComputeIncrementalDiffParams): IncrementalDiffResult;
36
55
  /**
37
56
  * transforms git range-diff output into a clean incremental diff.
38
57
  *
@@ -37,6 +37,7 @@ export interface RepoSettings {
37
37
  repoIntelligence: boolean;
38
38
  progressComments: boolean;
39
39
  statusChecks: boolean;
40
+ approvalCheck: boolean;
40
41
  modeInstructions: Record<string, string>;
41
42
  learnings: string | null;
42
43
  learningsHeadings: LearningsHeading[];
@@ -21,6 +21,21 @@ export interface RunEffort {
21
21
  /** the catalog alias the ladder came from, if we recognized one. */
22
22
  alias: ModelAlias | undefined;
23
23
  }
24
+ /**
25
+ * the position a subsidised run is pinned to — the `high` rung on the ladder of
26
+ * the funded model. only reachable on the subsidy proxy, so the ladder is always
27
+ * the OpenRouter one.
28
+ *
29
+ * `high` by name, not position 0. position 0 was equivalent for as long as every
30
+ * subsidy candidate's ladder started at `high`, but DeepSeek V4 Flash 0731
31
+ * publishes `low, high, max` on the OpenRouter route, so the floor would have
32
+ * silently dropped a level the moment that became the funded default — undoing
33
+ * the `high`-effort result #1063 chose the tier on. a model publishing no `high`
34
+ * falls back to its own floor.
35
+ */
36
+ export declare function ossEffortFloor(ctx: {
37
+ payload: ResolvedPayload;
38
+ }): EffortPosition;
24
39
  export declare function resolveRunEffort(ctx: {
25
40
  payload: ResolvedPayload;
26
41
  resolvedModel?: string | undefined;
@@ -27,6 +27,14 @@
27
27
  * 4. ProviderModelNotFoundError — configured model id no longer in the
28
28
  * OpenCode catalog; renders a nudge to pick a different model.
29
29
  *
30
+ * 4a. No-provider-available (#1077) — the model IS in the catalog but the
31
+ * provider declines to route it on this account's plan (OpenCode Zen's
32
+ * own refusal string). Same "pick another model" CTA, different reason.
33
+ *
34
+ * 4b. Context-window overflow (#1116) — terminal `Prompt is too long` /
35
+ * `maximum context length is N tokens`. Actionable, so it renders on
36
+ * both surfaces rather than collapsing to the one-line comment.
37
+ *
30
38
  * 5. Activity-timeout hang — `errorMessage` starts with
31
39
  * `"activity timeout"` or `"agent still pending"` AND none of the
32
40
  * above matched. The harness keeps structured diagnostic state on
@@ -43,8 +51,9 @@
43
51
  * banner; the PR comment collapses to the same one-line logs link as
44
52
  * the hang case, since the raw internal string helps nobody on the PR.
45
53
  *
46
- * Net: the actionable classifications (billing, API-key, model-not-found)
47
- * render identical bodies on both surfaces; the non-actionable ones (hang,
54
+ * Net: the actionable classifications (billing, API-key, model-not-found,
55
+ * no-provider-available, context-overflow) render identical bodies on both
56
+ * surfaces; the non-actionable ones (hang,
48
57
  * generic) keep the forensics in the Actions job summary and show a calm
49
58
  * one-liner in the PR comment, whose footer already carries Pullfrog
50
59
  * branding + rerun links.
@@ -61,4 +70,8 @@ export declare function renderRunError(input: {
61
70
  name: string;
62
71
  };
63
72
  agentDiagnostic: AgentDiagnostic | undefined;
73
+ /** the run is spending Pullfrog's Router wallet (a proxy key was minted), not
74
+ * the user's own provider credential. `payload.proxyModel` at both call
75
+ * sites. */
76
+ routerActive: boolean;
64
77
  }): RenderedRunError;