pullfrog 0.1.80 → 0.1.82

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.
@@ -81,5 +81,10 @@ export declare const PULLFROG_OPENCODE_PLUGIN_SOURCE: string;
81
81
  * session via `tool.execute.before`, complementing the runtime backstops from
82
82
  * PR #796 (action/mcp/checkout.ts, action/mcp/git.ts). Deny-list source of
83
83
  * truth: `action/agents/subagentToolGates.ts`.
84
+ *
85
+ * Also hard-blocks the native `bash` tool for EVERY session. bash stays in the
86
+ * tool list because Zen's free tier rejects a request without it (2026-09-17);
87
+ * `permission.bash: "ask"` is the fail-closed backstop should this plugin ever
88
+ * not load. see wiki/security.md.
84
89
  */
85
90
  export declare function buildOpencodeSubagentGateSource(deniedTools: readonly string[]): string;
package/dist/cli.mjs CHANGED
@@ -123005,7 +123005,7 @@ var import_picocolors = __toESM(require_picocolors(), 1);
123005
123005
  // package.json
123006
123006
  var package_default = {
123007
123007
  name: "pullfrog",
123008
- version: "0.1.80",
123008
+ version: "0.1.82",
123009
123009
  cliContractVersion: "1",
123010
123010
  type: "module",
123011
123011
  bin: {
@@ -125285,12 +125285,20 @@ var providers = {
125285
125285
  // the same models as `moonshotai` above, billed against a Kimi membership
125286
125286
  // instead of a Moonshot API balance — a separate endpoint, separate model
125287
125287
  // ids and a separate key, which is why it is a provider rather than a second
125288
- // `envVars` entry. no provider injection is needed: models.dev carries
125289
- // `kimi-for-coding` (api `https://api.kimi.com/coding/v1`, npm
125290
- // `@ai-sdk/anthropic`) and opencode's env loop enables it from a bare
125288
+ // `envVars` entry. no provider injection is needed: models.dev carries the
125289
+ // provider (api `https://api.kimi.com/coding/v1`, npm
125290
+ // `@ai-sdk/openai-compatible`) and opencode's env loop enables it from a bare
125291
125291
  // `KIMI_API_KEY`, verified against our pinned opencode-ai@1.18.5 — all four
125292
125292
  // ids list in `opencode models` and a run reaches Kimi's own auth check.
125293
125293
  //
125294
+ // models.dev renamed that provider on 2026-09-18: `kimi-for-coding` became
125295
+ // `kimi-code-plan-cn` (api.kimi.com — where the console mints the key) and
125296
+ // `kimi-code-plan-global` (api.kimi.ai). opencode resolves providers from
125297
+ // its models.dev cache, so a `resolve` still spelling the old key names a
125298
+ // provider it does not know. the `resolve` targets track models.dev's key;
125299
+ // the provider KEY below is Pullfrog's slug and stays put. see
125300
+ // wiki/kimi-code.md.
125301
+ //
125294
125302
  // NO `openRouterResolve` ON PURPOSE. OpenRouter cannot serve a Kimi
125295
125303
  // membership, so a Router path here would silently bill the wallet for
125296
125304
  // Moonshot pay-as-you-go under a slug picked for the opposite reason. The
@@ -125300,9 +125308,11 @@ var providers = {
125300
125308
  // keyless Router pick to the default subsidy model with `noRouterPath`.
125301
125309
  "kimi-for-coding": provider({
125302
125310
  // "Kimi Code" is the product name on kimi.com/code and in the console the
125303
- // key is minted from. The provider KEY has to stay `kimi-for-coding` — it
125304
- // is models.dev's id, so it is what `enabled_providers` and every
125305
- // `resolve` prefix must spell.
125311
+ // key is minted from. the provider KEY stays `kimi-for-coding`: it is the
125312
+ // slug prefix every stored pick, `--model` flag and BYOK card spells, and
125313
+ // it is not what reaches opencode — `enabled_providers` is derived from
125314
+ // the `resolve` prefix (`action/agents/opencode.ts`), which is why the
125315
+ // two may differ here and nowhere else in this file.
125306
125316
  displayName: "Kimi Code",
125307
125317
  envVars: ["KIMI_API_KEY"],
125308
125318
  models: {
@@ -125313,7 +125323,7 @@ var providers = {
125313
125323
  "kimi-k3": {
125314
125324
  displayName: "Kimi K3",
125315
125325
  description: "1M context, but only on Allegretto and above \xB7 Moderato caps it at 256K",
125316
- resolve: "kimi-for-coding/k3",
125326
+ resolve: "kimi-code-plan-cn/k3",
125317
125327
  effort: ["low", "high", "max"],
125318
125328
  subagentModel: "kimi-k2"
125319
125329
  },
@@ -125328,7 +125338,7 @@ var providers = {
125328
125338
  "kimi-k3-256k": {
125329
125339
  displayName: "Kimi K3 256K",
125330
125340
  description: "Same model at 256K for ~half the quota \xB7 Moderato or above",
125331
- resolve: "kimi-for-coding/k3-256k",
125341
+ resolve: "kimi-code-plan-cn/k3-256k",
125332
125342
  effort: ["low", "high", "max"],
125333
125343
  preferred: true,
125334
125344
  subagentModel: "kimi-k2"
@@ -125336,7 +125346,7 @@ var providers = {
125336
125346
  "kimi-k2": {
125337
125347
  displayName: "Kimi K2",
125338
125348
  description: "Included in every Kimi membership tier",
125339
- resolve: "kimi-for-coding/kimi-for-coding",
125349
+ resolve: "kimi-code-plan-cn/kimi-for-coding",
125340
125350
  // models.dev published this ladder on 2026-09-14; the catalog gate
125341
125351
  // mirrors it, so main was red until the alias carried it too.
125342
125352
  effort: ["low", "high", "max"]
@@ -125344,7 +125354,7 @@ var providers = {
125344
125354
  "kimi-k2-highspeed": {
125345
125355
  displayName: "Kimi K2 HighSpeed",
125346
125356
  description: "~6x output speed for ~3x quota \xB7 needs Allegretto or above",
125347
- resolve: "kimi-for-coding/kimi-for-coding-highspeed"
125357
+ resolve: "kimi-code-plan-cn/kimi-for-coding-highspeed"
125348
125358
  }
125349
125359
  }
125350
125360
  }),
@@ -125578,17 +125588,21 @@ var providers = {
125578
125588
  },
125579
125589
  "gpt-5-nano": {
125580
125590
  displayName: "GPT Nano",
125581
- resolve: "opencode/gpt-5-nano",
125582
- effort: ["minimal", "low", "medium", "high"],
125583
- openRouterResolve: "openrouter/openai/gpt-5-nano"
125591
+ resolve: "opencode/gpt-5.4-nano",
125592
+ effort: ["none", "low", "medium", "high", "xhigh"],
125593
+ openRouterResolve: "openrouter/openai/gpt-5.4-nano"
125584
125594
  },
125585
125595
  // Zen's PAID Muse Spark, priced like Meta's own Standard tier. answered
125586
125596
  // `OK` through the harness on 2026-09-12 once the workspace was funded.
125587
125597
  "muse-spark": {
125588
125598
  displayName: "Muse Spark",
125589
125599
  resolve: "opencode/muse-spark-1.3",
125590
- effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125591
- openRouterResolve: "openrouter/meta/muse-spark-1.3"
125600
+ // models.dev dropped `max` from Zen's ladder on 2026-09-19 while the
125601
+ // OpenRouter and direct `meta/` routes kept it; the catalog gate
125602
+ // mirrors what is published per route.
125603
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
125604
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
125605
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"]
125592
125606
  },
125593
125607
  // Zen's FREE contributor tier: the same model at $0 because Meta trains
125594
125608
  // on the prompts and completions. Zen served it to our key on 2026-09-12
@@ -125603,6 +125617,22 @@ var providers = {
125603
125617
  // see the big-pickle note above (#1077).
125604
125618
  isFree: true
125605
125619
  },
125620
+ // Zen's FREE stealth preview (listed 2026-09-16), the big-pickle shape: an
125621
+ // anonymous vendor's model at $0 for a limited time. OpenRouter's listing:
125622
+ // prompts and completions may be retained, not trained on.
125623
+ "union-alpha": {
125624
+ displayName: "Union Alpha",
125625
+ description: "Stealth preview; prompts may be retained",
125626
+ resolve: "opencode/union-alpha",
125627
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
125628
+ // see the big-pickle note above (#1077).
125629
+ isFree: true,
125630
+ // Zen dropped the id from `/v1/models` on 2026-09-18, two days after it
125631
+ // listed it, and answers a 500 for it. a stealth preview has no same-
125632
+ // family successor, so stored picks land on the other free stealth
125633
+ // model, as `minimax-m2.5-free` does.
125634
+ fallback: "opencode/big-pickle"
125635
+ },
125606
125636
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
125607
125637
  // was alone in since `mimo-v2-pro-free` lost its model.
125608
125638
  mimo: {
@@ -135867,6 +135897,11 @@ export default async function pullfrogSubagentGatePlugin() {
135867
135897
  // pick a different action.
135868
135898
  const sessionID = typeof input?.sessionID === "string" ? input.sessionID : "";
135869
135899
  const tool = typeof input?.tool === "string" ? input.tool : "";
135900
+ // above the sessionID check: the bash block must never depend on a
135901
+ // session id being present.
135902
+ if (tool === "bash") {
135903
+ throw new Error("the native bash tool is disabled in Pullfrog runs.");
135904
+ }
135870
135905
  if (!sessionID || !tool) return;
135871
135906
  if (orchestratorSessionID === undefined) orchestratorSessionID = sessionID;
135872
135907
  if (sessionID === orchestratorSessionID) return;
@@ -136079,7 +136114,11 @@ var installCli = () => installOpencodeCli({ binPath: "bin/opencode.exe" });
136079
136114
  function buildSecurityConfig(ctx, model) {
136080
136115
  const config4 = {
136081
136116
  permission: {
136082
- bash: "deny",
136117
+ // listed but never run: Zen's free tier 403s a tool list missing `bash`,
136118
+ // `glob`, `grep` or `read` (2026-09-17), so the gate plugin throws on
136119
+ // every bash call and "ask" (no responder in serve mode) fails closed.
136120
+ // never switch one of those four to "deny". see wiki/security.md.
136121
+ bash: "ask",
136083
136122
  edit: "allow",
136084
136123
  read: "allow",
136085
136124
  webfetch: "allow",
@@ -218065,6 +218104,23 @@ function isContextOverflowError(message) {
218065
218104
  function isNoProviderAvailableError(message) {
218066
218105
  return /\bNo provider available\b/i.test(message);
218067
218106
  }
218107
+ function isZenFreeTierGateError(message) {
218108
+ return /free tier can only be used from within OpenCode/i.test(message);
218109
+ }
218110
+ function formatZenFreeTierGateSummary(input2) {
218111
+ const settingsUrl = `${getApiUrl()}/console/${input2.owner}/${input2.name}`;
218112
+ return [
218113
+ "**Zen's free tier refused a request this run made.** OpenCode Zen currently rejects free-model requests whose tool list is missing one of the built-in tools it expects ([upstream issue](https://github.com/anomalyco/opencode/issues/49587)). Pullfrog sends all of them, but opencode's mid-run context-compaction request carries no tools at all, and a repo-level `opencode.json` that denies `bash`, `glob`, `grep` or `read` strips that tool from every request.",
218114
+ "",
218115
+ 'Pick a paid model for this repo, drop any `"deny"` on `bash`, `glob`, `grep` or `read` from the repo\'s `opencode.json` if it sets one, or split the PR so the run stays under the compaction threshold and re-trigger.',
218116
+ "",
218117
+ `[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
218118
+ "",
218119
+ `\`\`\`
218120
+ ${input2.raw}
218121
+ \`\`\``
218122
+ ].join("\n");
218123
+ }
218068
218124
  function formatNoProviderAvailableSummary(input2) {
218069
218125
  const settingsUrl = `${getApiUrl()}/console/${input2.owner}/${input2.name}`;
218070
218126
  return [
@@ -218308,6 +218364,16 @@ ${body}`, comment: body };
218308
218364
  });
218309
218365
  return { summary: `### \u274C Pullfrog failed
218310
218366
 
218367
+ ${body}`, comment: body };
218368
+ }
218369
+ if (isZenFreeTierGateError(input2.errorMessage)) {
218370
+ const body = formatZenFreeTierGateSummary({
218371
+ owner: input2.repo.owner,
218372
+ name: input2.repo.name,
218373
+ raw: input2.errorMessage
218374
+ });
218375
+ return { summary: `### \u274C Pullfrog failed
218376
+
218311
218377
  ${body}`, comment: body };
218312
218378
  }
218313
218379
  if (isContextOverflowError(input2.errorMessage)) {
@@ -220161,7 +220227,7 @@ function resolveTarget2(repo) {
220161
220227
  return { owner: match3[1], repo: match3[2] };
220162
220228
  }
220163
220229
  function cliVersion() {
220164
- const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.80");
220230
+ const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.82");
220165
220231
  if (!parts) return "0.0.0";
220166
220232
  return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
220167
220233
  }
@@ -220328,7 +220394,7 @@ async function runCli8(input2) {
220328
220394
  }
220329
220395
 
220330
220396
  // cli.ts
220331
- var VERSION10 = "0.1.80";
220397
+ var VERSION10 = "0.1.82";
220332
220398
  var bin = basename2(process.argv[1] || "");
220333
220399
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
220334
220400
  var rawArgs = process.argv.slice(2);
package/dist/index.js CHANGED
@@ -108061,12 +108061,20 @@ var providers = {
108061
108061
  // the same models as `moonshotai` above, billed against a Kimi membership
108062
108062
  // instead of a Moonshot API balance — a separate endpoint, separate model
108063
108063
  // ids and a separate key, which is why it is a provider rather than a second
108064
- // `envVars` entry. no provider injection is needed: models.dev carries
108065
- // `kimi-for-coding` (api `https://api.kimi.com/coding/v1`, npm
108066
- // `@ai-sdk/anthropic`) and opencode's env loop enables it from a bare
108064
+ // `envVars` entry. no provider injection is needed: models.dev carries the
108065
+ // provider (api `https://api.kimi.com/coding/v1`, npm
108066
+ // `@ai-sdk/openai-compatible`) and opencode's env loop enables it from a bare
108067
108067
  // `KIMI_API_KEY`, verified against our pinned opencode-ai@1.18.5 — all four
108068
108068
  // ids list in `opencode models` and a run reaches Kimi's own auth check.
108069
108069
  //
108070
+ // models.dev renamed that provider on 2026-09-18: `kimi-for-coding` became
108071
+ // `kimi-code-plan-cn` (api.kimi.com — where the console mints the key) and
108072
+ // `kimi-code-plan-global` (api.kimi.ai). opencode resolves providers from
108073
+ // its models.dev cache, so a `resolve` still spelling the old key names a
108074
+ // provider it does not know. the `resolve` targets track models.dev's key;
108075
+ // the provider KEY below is Pullfrog's slug and stays put. see
108076
+ // wiki/kimi-code.md.
108077
+ //
108070
108078
  // NO `openRouterResolve` ON PURPOSE. OpenRouter cannot serve a Kimi
108071
108079
  // membership, so a Router path here would silently bill the wallet for
108072
108080
  // Moonshot pay-as-you-go under a slug picked for the opposite reason. The
@@ -108076,9 +108084,11 @@ var providers = {
108076
108084
  // keyless Router pick to the default subsidy model with `noRouterPath`.
108077
108085
  "kimi-for-coding": provider({
108078
108086
  // "Kimi Code" is the product name on kimi.com/code and in the console the
108079
- // key is minted from. The provider KEY has to stay `kimi-for-coding` — it
108080
- // is models.dev's id, so it is what `enabled_providers` and every
108081
- // `resolve` prefix must spell.
108087
+ // key is minted from. the provider KEY stays `kimi-for-coding`: it is the
108088
+ // slug prefix every stored pick, `--model` flag and BYOK card spells, and
108089
+ // it is not what reaches opencode — `enabled_providers` is derived from
108090
+ // the `resolve` prefix (`action/agents/opencode.ts`), which is why the
108091
+ // two may differ here and nowhere else in this file.
108082
108092
  displayName: "Kimi Code",
108083
108093
  envVars: ["KIMI_API_KEY"],
108084
108094
  models: {
@@ -108089,7 +108099,7 @@ var providers = {
108089
108099
  "kimi-k3": {
108090
108100
  displayName: "Kimi K3",
108091
108101
  description: "1M context, but only on Allegretto and above \xB7 Moderato caps it at 256K",
108092
- resolve: "kimi-for-coding/k3",
108102
+ resolve: "kimi-code-plan-cn/k3",
108093
108103
  effort: ["low", "high", "max"],
108094
108104
  subagentModel: "kimi-k2"
108095
108105
  },
@@ -108104,7 +108114,7 @@ var providers = {
108104
108114
  "kimi-k3-256k": {
108105
108115
  displayName: "Kimi K3 256K",
108106
108116
  description: "Same model at 256K for ~half the quota \xB7 Moderato or above",
108107
- resolve: "kimi-for-coding/k3-256k",
108117
+ resolve: "kimi-code-plan-cn/k3-256k",
108108
108118
  effort: ["low", "high", "max"],
108109
108119
  preferred: true,
108110
108120
  subagentModel: "kimi-k2"
@@ -108112,7 +108122,7 @@ var providers = {
108112
108122
  "kimi-k2": {
108113
108123
  displayName: "Kimi K2",
108114
108124
  description: "Included in every Kimi membership tier",
108115
- resolve: "kimi-for-coding/kimi-for-coding",
108125
+ resolve: "kimi-code-plan-cn/kimi-for-coding",
108116
108126
  // models.dev published this ladder on 2026-09-14; the catalog gate
108117
108127
  // mirrors it, so main was red until the alias carried it too.
108118
108128
  effort: ["low", "high", "max"]
@@ -108120,7 +108130,7 @@ var providers = {
108120
108130
  "kimi-k2-highspeed": {
108121
108131
  displayName: "Kimi K2 HighSpeed",
108122
108132
  description: "~6x output speed for ~3x quota \xB7 needs Allegretto or above",
108123
- resolve: "kimi-for-coding/kimi-for-coding-highspeed"
108133
+ resolve: "kimi-code-plan-cn/kimi-for-coding-highspeed"
108124
108134
  }
108125
108135
  }
108126
108136
  }),
@@ -108354,17 +108364,21 @@ var providers = {
108354
108364
  },
108355
108365
  "gpt-5-nano": {
108356
108366
  displayName: "GPT Nano",
108357
- resolve: "opencode/gpt-5-nano",
108358
- effort: ["minimal", "low", "medium", "high"],
108359
- openRouterResolve: "openrouter/openai/gpt-5-nano"
108367
+ resolve: "opencode/gpt-5.4-nano",
108368
+ effort: ["none", "low", "medium", "high", "xhigh"],
108369
+ openRouterResolve: "openrouter/openai/gpt-5.4-nano"
108360
108370
  },
108361
108371
  // Zen's PAID Muse Spark, priced like Meta's own Standard tier. answered
108362
108372
  // `OK` through the harness on 2026-09-12 once the workspace was funded.
108363
108373
  "muse-spark": {
108364
108374
  displayName: "Muse Spark",
108365
108375
  resolve: "opencode/muse-spark-1.3",
108366
- effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108367
- openRouterResolve: "openrouter/meta/muse-spark-1.3"
108376
+ // models.dev dropped `max` from Zen's ladder on 2026-09-19 while the
108377
+ // OpenRouter and direct `meta/` routes kept it; the catalog gate
108378
+ // mirrors what is published per route.
108379
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
108380
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
108381
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"]
108368
108382
  },
108369
108383
  // Zen's FREE contributor tier: the same model at $0 because Meta trains
108370
108384
  // on the prompts and completions. Zen served it to our key on 2026-09-12
@@ -108379,6 +108393,22 @@ var providers = {
108379
108393
  // see the big-pickle note above (#1077).
108380
108394
  isFree: true
108381
108395
  },
108396
+ // Zen's FREE stealth preview (listed 2026-09-16), the big-pickle shape: an
108397
+ // anonymous vendor's model at $0 for a limited time. OpenRouter's listing:
108398
+ // prompts and completions may be retained, not trained on.
108399
+ "union-alpha": {
108400
+ displayName: "Union Alpha",
108401
+ description: "Stealth preview; prompts may be retained",
108402
+ resolve: "opencode/union-alpha",
108403
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
108404
+ // see the big-pickle note above (#1077).
108405
+ isFree: true,
108406
+ // Zen dropped the id from `/v1/models` on 2026-09-18, two days after it
108407
+ // listed it, and answers a 500 for it. a stealth preview has no same-
108408
+ // family successor, so stored picks land on the other free stealth
108409
+ // model, as `minimax-m2.5-free` does.
108410
+ fallback: "opencode/big-pickle"
108411
+ },
108382
108412
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
108383
108413
  // was alone in since `mimo-v2-pro-free` lost its model.
108384
108414
  mimo: {
@@ -109975,7 +110005,7 @@ var import_semver = __toESM(require_semver2(), 1);
109975
110005
  // package.json
109976
110006
  var package_default = {
109977
110007
  name: "pullfrog",
109978
- version: "0.1.80",
110008
+ version: "0.1.82",
109979
110009
  cliContractVersion: "1",
109980
110010
  type: "module",
109981
110011
  bin: {
@@ -118684,6 +118714,11 @@ export default async function pullfrogSubagentGatePlugin() {
118684
118714
  // pick a different action.
118685
118715
  const sessionID = typeof input?.sessionID === "string" ? input.sessionID : "";
118686
118716
  const tool = typeof input?.tool === "string" ? input.tool : "";
118717
+ // above the sessionID check: the bash block must never depend on a
118718
+ // session id being present.
118719
+ if (tool === "bash") {
118720
+ throw new Error("the native bash tool is disabled in Pullfrog runs.");
118721
+ }
118687
118722
  if (!sessionID || !tool) return;
118688
118723
  if (orchestratorSessionID === undefined) orchestratorSessionID = sessionID;
118689
118724
  if (sessionID === orchestratorSessionID) return;
@@ -118896,7 +118931,11 @@ var installCli = () => installOpencodeCli({ binPath: "bin/opencode.exe" });
118896
118931
  function buildSecurityConfig(ctx, model) {
118897
118932
  const config3 = {
118898
118933
  permission: {
118899
- bash: "deny",
118934
+ // listed but never run: Zen's free tier 403s a tool list missing `bash`,
118935
+ // `glob`, `grep` or `read` (2026-09-17), so the gate plugin throws on
118936
+ // every bash call and "ask" (no responder in serve mode) fails closed.
118937
+ // never switch one of those four to "deny". see wiki/security.md.
118938
+ bash: "ask",
118900
118939
  edit: "allow",
118901
118940
  read: "allow",
118902
118941
  webfetch: "allow",
@@ -200882,6 +200921,23 @@ function isContextOverflowError(message) {
200882
200921
  function isNoProviderAvailableError(message) {
200883
200922
  return /\bNo provider available\b/i.test(message);
200884
200923
  }
200924
+ function isZenFreeTierGateError(message) {
200925
+ return /free tier can only be used from within OpenCode/i.test(message);
200926
+ }
200927
+ function formatZenFreeTierGateSummary(input2) {
200928
+ const settingsUrl = `${getApiUrl()}/console/${input2.owner}/${input2.name}`;
200929
+ return [
200930
+ "**Zen's free tier refused a request this run made.** OpenCode Zen currently rejects free-model requests whose tool list is missing one of the built-in tools it expects ([upstream issue](https://github.com/anomalyco/opencode/issues/49587)). Pullfrog sends all of them, but opencode's mid-run context-compaction request carries no tools at all, and a repo-level `opencode.json` that denies `bash`, `glob`, `grep` or `read` strips that tool from every request.",
200931
+ "",
200932
+ 'Pick a paid model for this repo, drop any `"deny"` on `bash`, `glob`, `grep` or `read` from the repo\'s `opencode.json` if it sets one, or split the PR so the run stays under the compaction threshold and re-trigger.',
200933
+ "",
200934
+ `[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
200935
+ "",
200936
+ `\`\`\`
200937
+ ${input2.raw}
200938
+ \`\`\``
200939
+ ].join("\n");
200940
+ }
200885
200941
  function formatNoProviderAvailableSummary(input2) {
200886
200942
  const settingsUrl = `${getApiUrl()}/console/${input2.owner}/${input2.name}`;
200887
200943
  return [
@@ -201125,6 +201181,16 @@ ${body}`, comment: body };
201125
201181
  });
201126
201182
  return { summary: `### \u274C Pullfrog failed
201127
201183
 
201184
+ ${body}`, comment: body };
201185
+ }
201186
+ if (isZenFreeTierGateError(input2.errorMessage)) {
201187
+ const body = formatZenFreeTierGateSummary({
201188
+ owner: input2.repo.owner,
201189
+ name: input2.repo.name,
201190
+ raw: input2.errorMessage
201191
+ });
201192
+ return { summary: `### \u274C Pullfrog failed
201193
+
201128
201194
  ${body}`, comment: body };
201129
201195
  }
201130
201196
  if (isContextOverflowError(input2.errorMessage)) {
package/dist/internal.js CHANGED
@@ -8,7 +8,7 @@ var __export = (target, all) => {
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "pullfrog",
11
- version: "0.1.80",
11
+ version: "0.1.82",
12
12
  cliContractVersion: "1",
13
13
  type: "module",
14
14
  bin: {
@@ -14629,12 +14629,20 @@ var providers = {
14629
14629
  // the same models as `moonshotai` above, billed against a Kimi membership
14630
14630
  // instead of a Moonshot API balance — a separate endpoint, separate model
14631
14631
  // ids and a separate key, which is why it is a provider rather than a second
14632
- // `envVars` entry. no provider injection is needed: models.dev carries
14633
- // `kimi-for-coding` (api `https://api.kimi.com/coding/v1`, npm
14634
- // `@ai-sdk/anthropic`) and opencode's env loop enables it from a bare
14632
+ // `envVars` entry. no provider injection is needed: models.dev carries the
14633
+ // provider (api `https://api.kimi.com/coding/v1`, npm
14634
+ // `@ai-sdk/openai-compatible`) and opencode's env loop enables it from a bare
14635
14635
  // `KIMI_API_KEY`, verified against our pinned opencode-ai@1.18.5 — all four
14636
14636
  // ids list in `opencode models` and a run reaches Kimi's own auth check.
14637
14637
  //
14638
+ // models.dev renamed that provider on 2026-09-18: `kimi-for-coding` became
14639
+ // `kimi-code-plan-cn` (api.kimi.com — where the console mints the key) and
14640
+ // `kimi-code-plan-global` (api.kimi.ai). opencode resolves providers from
14641
+ // its models.dev cache, so a `resolve` still spelling the old key names a
14642
+ // provider it does not know. the `resolve` targets track models.dev's key;
14643
+ // the provider KEY below is Pullfrog's slug and stays put. see
14644
+ // wiki/kimi-code.md.
14645
+ //
14638
14646
  // NO `openRouterResolve` ON PURPOSE. OpenRouter cannot serve a Kimi
14639
14647
  // membership, so a Router path here would silently bill the wallet for
14640
14648
  // Moonshot pay-as-you-go under a slug picked for the opposite reason. The
@@ -14644,9 +14652,11 @@ var providers = {
14644
14652
  // keyless Router pick to the default subsidy model with `noRouterPath`.
14645
14653
  "kimi-for-coding": provider({
14646
14654
  // "Kimi Code" is the product name on kimi.com/code and in the console the
14647
- // key is minted from. The provider KEY has to stay `kimi-for-coding` — it
14648
- // is models.dev's id, so it is what `enabled_providers` and every
14649
- // `resolve` prefix must spell.
14655
+ // key is minted from. the provider KEY stays `kimi-for-coding`: it is the
14656
+ // slug prefix every stored pick, `--model` flag and BYOK card spells, and
14657
+ // it is not what reaches opencode — `enabled_providers` is derived from
14658
+ // the `resolve` prefix (`action/agents/opencode.ts`), which is why the
14659
+ // two may differ here and nowhere else in this file.
14650
14660
  displayName: "Kimi Code",
14651
14661
  envVars: ["KIMI_API_KEY"],
14652
14662
  models: {
@@ -14657,7 +14667,7 @@ var providers = {
14657
14667
  "kimi-k3": {
14658
14668
  displayName: "Kimi K3",
14659
14669
  description: "1M context, but only on Allegretto and above \xB7 Moderato caps it at 256K",
14660
- resolve: "kimi-for-coding/k3",
14670
+ resolve: "kimi-code-plan-cn/k3",
14661
14671
  effort: ["low", "high", "max"],
14662
14672
  subagentModel: "kimi-k2"
14663
14673
  },
@@ -14672,7 +14682,7 @@ var providers = {
14672
14682
  "kimi-k3-256k": {
14673
14683
  displayName: "Kimi K3 256K",
14674
14684
  description: "Same model at 256K for ~half the quota \xB7 Moderato or above",
14675
- resolve: "kimi-for-coding/k3-256k",
14685
+ resolve: "kimi-code-plan-cn/k3-256k",
14676
14686
  effort: ["low", "high", "max"],
14677
14687
  preferred: true,
14678
14688
  subagentModel: "kimi-k2"
@@ -14680,7 +14690,7 @@ var providers = {
14680
14690
  "kimi-k2": {
14681
14691
  displayName: "Kimi K2",
14682
14692
  description: "Included in every Kimi membership tier",
14683
- resolve: "kimi-for-coding/kimi-for-coding",
14693
+ resolve: "kimi-code-plan-cn/kimi-for-coding",
14684
14694
  // models.dev published this ladder on 2026-09-14; the catalog gate
14685
14695
  // mirrors it, so main was red until the alias carried it too.
14686
14696
  effort: ["low", "high", "max"]
@@ -14688,7 +14698,7 @@ var providers = {
14688
14698
  "kimi-k2-highspeed": {
14689
14699
  displayName: "Kimi K2 HighSpeed",
14690
14700
  description: "~6x output speed for ~3x quota \xB7 needs Allegretto or above",
14691
- resolve: "kimi-for-coding/kimi-for-coding-highspeed"
14701
+ resolve: "kimi-code-plan-cn/kimi-for-coding-highspeed"
14692
14702
  }
14693
14703
  }
14694
14704
  }),
@@ -14922,17 +14932,21 @@ var providers = {
14922
14932
  },
14923
14933
  "gpt-5-nano": {
14924
14934
  displayName: "GPT Nano",
14925
- resolve: "opencode/gpt-5-nano",
14926
- effort: ["minimal", "low", "medium", "high"],
14927
- openRouterResolve: "openrouter/openai/gpt-5-nano"
14935
+ resolve: "opencode/gpt-5.4-nano",
14936
+ effort: ["none", "low", "medium", "high", "xhigh"],
14937
+ openRouterResolve: "openrouter/openai/gpt-5.4-nano"
14928
14938
  },
14929
14939
  // Zen's PAID Muse Spark, priced like Meta's own Standard tier. answered
14930
14940
  // `OK` through the harness on 2026-09-12 once the workspace was funded.
14931
14941
  "muse-spark": {
14932
14942
  displayName: "Muse Spark",
14933
14943
  resolve: "opencode/muse-spark-1.3",
14934
- effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14935
- openRouterResolve: "openrouter/meta/muse-spark-1.3"
14944
+ // models.dev dropped `max` from Zen's ladder on 2026-09-19 while the
14945
+ // OpenRouter and direct `meta/` routes kept it; the catalog gate
14946
+ // mirrors what is published per route.
14947
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
14948
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
14949
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"]
14936
14950
  },
14937
14951
  // Zen's FREE contributor tier: the same model at $0 because Meta trains
14938
14952
  // on the prompts and completions. Zen served it to our key on 2026-09-12
@@ -14947,6 +14961,22 @@ var providers = {
14947
14961
  // see the big-pickle note above (#1077).
14948
14962
  isFree: true
14949
14963
  },
14964
+ // Zen's FREE stealth preview (listed 2026-09-16), the big-pickle shape: an
14965
+ // anonymous vendor's model at $0 for a limited time. OpenRouter's listing:
14966
+ // prompts and completions may be retained, not trained on.
14967
+ "union-alpha": {
14968
+ displayName: "Union Alpha",
14969
+ description: "Stealth preview; prompts may be retained",
14970
+ resolve: "opencode/union-alpha",
14971
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
14972
+ // see the big-pickle note above (#1077).
14973
+ isFree: true,
14974
+ // Zen dropped the id from `/v1/models` on 2026-09-18, two days after it
14975
+ // listed it, and answers a 500 for it. a stealth preview has no same-
14976
+ // family successor, so stored picks land on the other free stealth
14977
+ // model, as `minimax-m2.5-free` does.
14978
+ fallback: "opencode/big-pickle"
14979
+ },
14950
14980
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
14951
14981
  // was alone in since `mimo-v2-pro-free` lost its model.
14952
14982
  mimo: {
@@ -31,6 +31,11 @@
31
31
  * provider declines to route it on this account's plan (OpenCode Zen's
32
32
  * own refusal string). Same "pick another model" CTA, different reason.
33
33
  *
34
+ * 4a'. Zen free-tier gate (#1377) — Zen 403s a free-tier request whose tool
35
+ * list is missing a built-in it expects. The harness keeps `bash` listed,
36
+ * but opencode's auto-compaction request carries no tools, so a long
37
+ * free-Zen run can still die mid-flight on the raw upstream string.
38
+ *
34
39
  * 4b. Context-window overflow (#1116) — terminal `Prompt is too long` /
35
40
  * `maximum context length is N tokens`. Actionable, so it renders on
36
41
  * both surfaces rather than collapsing to the one-line comment.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.80",
3
+ "version": "0.1.82",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {