pullfrog 0.1.81 → 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.81",
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
  }),
@@ -125587,8 +125597,12 @@ var providers = {
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
@@ -125612,7 +125626,12 @@ var providers = {
125612
125626
  resolve: "opencode/union-alpha",
125613
125627
  // free to run, still gated on the provider's own OPENCODE_API_KEY —
125614
125628
  // see the big-pickle note above (#1077).
125615
- isFree: true
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"
125616
125635
  },
125617
125636
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
125618
125637
  // was alone in since `mimo-v2-pro-free` lost its model.
@@ -135878,6 +135897,11 @@ export default async function pullfrogSubagentGatePlugin() {
135878
135897
  // pick a different action.
135879
135898
  const sessionID = typeof input?.sessionID === "string" ? input.sessionID : "";
135880
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
+ }
135881
135905
  if (!sessionID || !tool) return;
135882
135906
  if (orchestratorSessionID === undefined) orchestratorSessionID = sessionID;
135883
135907
  if (sessionID === orchestratorSessionID) return;
@@ -136090,7 +136114,11 @@ var installCli = () => installOpencodeCli({ binPath: "bin/opencode.exe" });
136090
136114
  function buildSecurityConfig(ctx, model) {
136091
136115
  const config4 = {
136092
136116
  permission: {
136093
- 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",
136094
136122
  edit: "allow",
136095
136123
  read: "allow",
136096
136124
  webfetch: "allow",
@@ -218076,6 +218104,23 @@ function isContextOverflowError(message) {
218076
218104
  function isNoProviderAvailableError(message) {
218077
218105
  return /\bNo provider available\b/i.test(message);
218078
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
+ }
218079
218124
  function formatNoProviderAvailableSummary(input2) {
218080
218125
  const settingsUrl = `${getApiUrl()}/console/${input2.owner}/${input2.name}`;
218081
218126
  return [
@@ -218319,6 +218364,16 @@ ${body}`, comment: body };
218319
218364
  });
218320
218365
  return { summary: `### \u274C Pullfrog failed
218321
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
+
218322
218377
  ${body}`, comment: body };
218323
218378
  }
218324
218379
  if (isContextOverflowError(input2.errorMessage)) {
@@ -220172,7 +220227,7 @@ function resolveTarget2(repo) {
220172
220227
  return { owner: match3[1], repo: match3[2] };
220173
220228
  }
220174
220229
  function cliVersion() {
220175
- const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.81");
220230
+ const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.82");
220176
220231
  if (!parts) return "0.0.0";
220177
220232
  return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
220178
220233
  }
@@ -220339,7 +220394,7 @@ async function runCli8(input2) {
220339
220394
  }
220340
220395
 
220341
220396
  // cli.ts
220342
- var VERSION10 = "0.1.81";
220397
+ var VERSION10 = "0.1.82";
220343
220398
  var bin = basename2(process.argv[1] || "");
220344
220399
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
220345
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
  }),
@@ -108363,8 +108373,12 @@ var providers = {
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
@@ -108388,7 +108402,12 @@ var providers = {
108388
108402
  resolve: "opencode/union-alpha",
108389
108403
  // free to run, still gated on the provider's own OPENCODE_API_KEY —
108390
108404
  // see the big-pickle note above (#1077).
108391
- isFree: true
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"
108392
108411
  },
108393
108412
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
108394
108413
  // was alone in since `mimo-v2-pro-free` lost its model.
@@ -109986,7 +110005,7 @@ var import_semver = __toESM(require_semver2(), 1);
109986
110005
  // package.json
109987
110006
  var package_default = {
109988
110007
  name: "pullfrog",
109989
- version: "0.1.81",
110008
+ version: "0.1.82",
109990
110009
  cliContractVersion: "1",
109991
110010
  type: "module",
109992
110011
  bin: {
@@ -118695,6 +118714,11 @@ export default async function pullfrogSubagentGatePlugin() {
118695
118714
  // pick a different action.
118696
118715
  const sessionID = typeof input?.sessionID === "string" ? input.sessionID : "";
118697
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
+ }
118698
118722
  if (!sessionID || !tool) return;
118699
118723
  if (orchestratorSessionID === undefined) orchestratorSessionID = sessionID;
118700
118724
  if (sessionID === orchestratorSessionID) return;
@@ -118907,7 +118931,11 @@ var installCli = () => installOpencodeCli({ binPath: "bin/opencode.exe" });
118907
118931
  function buildSecurityConfig(ctx, model) {
118908
118932
  const config3 = {
118909
118933
  permission: {
118910
- 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",
118911
118939
  edit: "allow",
118912
118940
  read: "allow",
118913
118941
  webfetch: "allow",
@@ -200893,6 +200921,23 @@ function isContextOverflowError(message) {
200893
200921
  function isNoProviderAvailableError(message) {
200894
200922
  return /\bNo provider available\b/i.test(message);
200895
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
+ }
200896
200941
  function formatNoProviderAvailableSummary(input2) {
200897
200942
  const settingsUrl = `${getApiUrl()}/console/${input2.owner}/${input2.name}`;
200898
200943
  return [
@@ -201136,6 +201181,16 @@ ${body}`, comment: body };
201136
201181
  });
201137
201182
  return { summary: `### \u274C Pullfrog failed
201138
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
+
201139
201194
  ${body}`, comment: body };
201140
201195
  }
201141
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.81",
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
  }),
@@ -14931,8 +14941,12 @@ var providers = {
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
@@ -14956,7 +14970,12 @@ var providers = {
14956
14970
  resolve: "opencode/union-alpha",
14957
14971
  // free to run, still gated on the provider's own OPENCODE_API_KEY —
14958
14972
  // see the big-pickle note above (#1077).
14959
- isFree: true
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"
14960
14979
  },
14961
14980
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
14962
14981
  // was alone in since `mimo-v2-pro-free` lost its model.
@@ -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.81",
3
+ "version": "0.1.82",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {