pullfrog 0.1.77 → 0.1.78

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.
@@ -76,23 +76,57 @@ export declare function providerGatewayOverride(model: string | undefined): Reco
76
76
  * openai-compatible's do; `validateAzureSetup` guarantees they parse.
77
77
  */
78
78
  export declare function azureProvider(model: string | undefined): Record<string, AzureProviderEntry>;
79
+ export type OpenRouterDataCollection = "allow" | "deny";
79
80
  /**
80
- * Build the `provider.openrouter.models[id].options` map that pins every Kimi
81
- * K2 OpenRouter alias away from the Enforcer-less providers via OpenRouter's
82
- * `provider: {ignore:[...]}` routing directive. Sourced from the model registry
83
- * so a Kimi alias/route change in `action/models.ts` flows through automatically.
81
+ * OpenRouter's request-level `provider.data_collection` decides whether hosts
82
+ * that retain or train on prompts may serve a run. The account-wide privacy
83
+ * setting is only a ceiling a request can tighten, so the policy rides on the
84
+ * run instead: OSS-funded runs `allow` (public code on headless runs — and the
85
+ * cheapest V4.1 Flash host, DeepSeek's own, is a training host), Router runs
86
+ * `deny` (a customer's private code never reaches one; every catalog target
87
+ * was still served under `deny` on 2026-09-11), and a BYOK OpenRouter key gets
88
+ * no preference — the customer's own account decides. see wiki/muse-spark.md.
89
+ */
90
+ export declare function openRouterDataCollection(ctx: {
91
+ payload: {
92
+ proxyModel?: string | undefined;
93
+ };
94
+ toolState: {
95
+ oss?: boolean | undefined;
96
+ };
97
+ }): OpenRouterDataCollection | undefined;
98
+ /**
99
+ * The `provider.openrouter` config block: the run's data policy as `extraBody`
100
+ * (the SDK merges it into every request), plus the per-model `options` that
101
+ * carry OpenRouter's `provider` routing object where a model needs its own —
102
+ * Kimi K2 pinned away from the Enforcer-less providers, and the Muse Spark
103
+ * contributor tier opened to data collection whatever the run's policy, since
104
+ * Meta training on the traffic is what that tier is. Sourced from the model
105
+ * registry so an alias/route change in `action/models.ts` flows through.
84
106
  *
85
107
  * Wiring: the per-model `options` object merges into the request options
86
108
  * (opencode `session/llm/request.ts` `mergeOptions(base, model.options)`),
87
109
  * gets wrapped under `providerOptions.openrouter` (`provider/transform.ts`
88
110
  * `sdkKey("@openrouter/ai-sdk-provider") === "openrouter"`), and the OpenRouter
89
- * AI-SDK provider spreads everything under `providerOptions.openrouter` straight
90
- * into the request body (`@openrouter/ai-sdk-provider` `doStream`/`doGenerate`),
91
- * so `provider` lands as the top-level routing object OpenRouter expects.
111
+ * AI-SDK provider spreads everything under `providerOptions.openrouter` into the
112
+ * request body LAST — after `extraBody` — so a per-model `provider` object
113
+ * replaces the run-level one wholesale. that is why the Kimi entry restates
114
+ * the run's `data_collection` beside its `ignore` list.
92
115
  */
93
- export declare function kimiOpenRouterProviderOverrides(): Record<string, {
94
- options: object;
95
- }>;
116
+ export declare function openRouterProvider(policy: OpenRouterDataCollection | undefined): {
117
+ options?: {
118
+ extraBody: {
119
+ provider: {
120
+ data_collection: OpenRouterDataCollection;
121
+ };
122
+ };
123
+ };
124
+ models: Record<string, {
125
+ options: {
126
+ provider: object;
127
+ };
128
+ }>;
129
+ };
96
130
  /**
97
131
  * Read-only `reviewfrog` subagent for lens-based review. Non-mutative +
98
132
  * non-recursive — enforced by the system prompt in reviewer.ts.
package/dist/cli.mjs CHANGED
@@ -123000,7 +123000,7 @@ var import_picocolors = __toESM(require_picocolors(), 1);
123000
123000
  // package.json
123001
123001
  var package_default = {
123002
123002
  name: "pullfrog",
123003
- version: "0.1.77",
123003
+ version: "0.1.78",
123004
123004
  cliContractVersion: "1",
123005
123005
  type: "module",
123006
123006
  bin: {
@@ -125122,26 +125122,34 @@ var providers = {
125122
125122
  models: {
125123
125123
  grok: {
125124
125124
  displayName: "Grok",
125125
- resolve: "xai/grok-4.5",
125126
- effort: ["low", "medium", "high"],
125127
- openRouterResolve: "openrouter/x-ai/grok-4.5",
125125
+ resolve: "xai/grok-4.6",
125126
+ effort: ["low", "medium", "high", "xhigh"],
125127
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
125128
125128
  preferred: true
125129
125129
  },
125130
+ // the Smart ladder's cheap rung: 1.25/2.5 against 4.6's 2/6, and a 0.2
125131
+ // cache read against 0.5 — the only live xAI model a rung can save on.
125132
+ "grok-4.3": {
125133
+ displayName: "Grok 4.3",
125134
+ resolve: "xai/grok-4.3",
125135
+ effort: ["none", "low", "medium", "high"],
125136
+ openRouterResolve: "openrouter/x-ai/grok-4.3"
125137
+ },
125130
125138
  // legacy aliases — xAI retired the entire fast/code-fast line on
125131
125139
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
125132
125140
  // and now redirects every deprecated text-model slug to grok-4.3 at
125133
125141
  // standard pricing. fall back to the live `xai/grok` so the alias
125134
- // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
125142
+ // chain resolves to grok-4.6 for both direct-key and OpenRouter users.
125135
125143
  "grok-fast": {
125136
125144
  displayName: "Grok Fast",
125137
125145
  resolve: "xai/grok-4-1-fast",
125138
- openRouterResolve: "openrouter/x-ai/grok-4.5",
125146
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
125139
125147
  fallback: "xai/grok"
125140
125148
  },
125141
125149
  "grok-code-fast": {
125142
125150
  displayName: "Grok Code Fast",
125143
125151
  resolve: "xai/grok-code-fast-1",
125144
- openRouterResolve: "openrouter/x-ai/grok-4.5",
125152
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
125145
125153
  fallback: "xai/grok"
125146
125154
  }
125147
125155
  }
@@ -125160,6 +125168,12 @@ var providers = {
125160
125168
  // $0.0405. there is no `~deepseek/*-pro-latest` pointer to track, so this
125161
125169
  // one has to be a dated pin; the `models-catalog` drift test is what
125162
125170
  // catches the next release.
125171
+ // from 2026-09-14 DeepSeek serves every direct `deepseek-v4-pro` call with
125172
+ // V4.1-Flash at Flash rates until V4.1-Pro ships. it is still the only Pro
125173
+ // id the vendor lists, and the OpenRouter 0813 pin is third-party-hosted
125174
+ // and unaffected — so no `fallback` to Flash, which would drag the Router
125175
+ // route down with it. the OSS program dropped Pro from its menu instead;
125176
+ // see `OSS_MODEL_ALLOWLIST`.
125163
125177
  "deepseek-pro": {
125164
125178
  displayName: "DeepSeek Pro",
125165
125179
  resolve: "deepseek/deepseek-v4-pro",
@@ -125168,30 +125182,24 @@ var providers = {
125168
125182
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813",
125169
125183
  preferred: true
125170
125184
  },
125171
- // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
125172
- // direct `resolve` needs no version. OpenRouter instead forked the 0731
125173
- // release into its own id and left the April preview live under the
125174
- // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
125175
- // OpenRouter route can never use the bare id. it tracks the rolling
125176
- // `~deepseek/*-latest` pointer (rule 4), which follows the next in-place
125177
- // upgrade on its own rather than pinning a dated snapshot that goes stale
125178
- // every release. that pointer is NOT priced like 0731 — its listed rates
125179
- // run +40% on output and +57.5% on cache read, and it costs 12% more per
125180
- // run on authoritative spend ($0.0405 vs $0.0361). kept anyway: ~$45/yr
125181
- // buys auto-following the upgrade, and the listed gap overstates the real
125182
- // one because a rolling alias prices at its routing ceiling.
125183
- // 0731 gained a `low` rung and renamed the top to `max`, and that ladder
125184
- // now reads the same on BOTH routes — the in-place direct upgrade caught
125185
- // up to the fork. so `low`, not `high`, is position 0 either way, which is
125186
- // why the OSS effort floor in `main.ts` pins the `high` rung by name. Pro
125187
- // is the same shape via OpenRouter since 0813; only its direct route still
125188
- // starts at `high`.
125185
+ // V4.1-Flash (2026-09-10) retired `deepseek-v4-flash`; DeepSeek's /models
125186
+ // now lists the unversioned `deepseek-flash`, so the direct resolve is the
125187
+ // rolling id at the same price. OpenRouter treats V4.1 as its own id
125188
+ // (`deepseek/deepseek-v4.1-flash`, $0.15/$0.6, cache $0.003) and its
125189
+ // `~deepseek/deepseek-v4-flash-latest` pointer still served 0731 on
125190
+ // 2026-09-11, so this is a pinned id rather than the pointer and the next
125191
+ // Flash release is a catalog edit (the bump cron flags it). this target is
125192
+ // the funded OSS default: priced on the measured OSS token mix at x1.34
125193
+ // the pointer's $0.0531/run on the DeepSeek-hosted endpoint — see
125194
+ // wiki/oss-model-allowlist.md. the bare `deepseek-v4-flash` on OpenRouter
125195
+ // is still the April preview, so that route can never use it. both routes
125196
+ // publish `low, high, max`; the OSS effort floor pins `high` by name.
125189
125197
  "deepseek-flash": {
125190
125198
  displayName: "DeepSeek Flash",
125191
- resolve: "deepseek/deepseek-v4-flash",
125199
+ resolve: "deepseek/deepseek-flash",
125192
125200
  effort: ["low", "high", "max"],
125193
125201
  openRouterEffort: ["low", "high", "max"],
125194
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
125202
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
125195
125203
  },
125196
125204
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
125197
125205
  // upgrade existing users to the v4 family via the fallback chain.
@@ -125294,6 +125302,40 @@ var providers = {
125294
125302
  }
125295
125303
  }
125296
125304
  }),
125305
+ // Meta Model API — the direct route to Muse Spark. a registry entry, like
125306
+ // kimi-for-coding: models.dev carries `meta` (`https://api.meta.ai/v1`, npm
125307
+ // `@ai-sdk/openai`) and opencode 1.18.29 enables it from a bare
125308
+ // META_MODEL_API_KEY — all five ids list in `opencode models`, and a bogus key
125309
+ // reaches Meta's own auth check (`invalid_api_key`). see wiki/muse-spark.md.
125310
+ meta: provider({
125311
+ displayName: "Meta",
125312
+ envVars: ["META_MODEL_API_KEY"],
125313
+ models: {
125314
+ // the Standard tier. no `subagentModel`: the contributor tier below is
125315
+ // the same model, not a cheaper sibling.
125316
+ "muse-spark": {
125317
+ displayName: "Muse Spark",
125318
+ resolve: "meta/muse-spark-1.3",
125319
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125320
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
125321
+ preferred: true
125322
+ },
125323
+ // the Contributor tier: the same model at $0.10 / $0.20 (cache read
125324
+ // $0.002) because Meta trains on the prompts and completions. an opt-in
125325
+ // pick on the OSS menu (public code, headless runs), never the default.
125326
+ // OpenRouter only serves it when the account allows paid-model training,
125327
+ // so the runtime opens data collection for this id alone — see
125328
+ // `openRouterProvider` in opencodeShared.ts.
125329
+ "muse-spark-contributor": {
125330
+ displayName: "Muse Spark Contributor",
125331
+ description: "Meta trains on prompts and completions",
125332
+ resolve: "meta/muse-spark-1.3-contributor",
125333
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
125334
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125335
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
125336
+ }
125337
+ }
125338
+ }),
125297
125339
  opencode: provider({
125298
125340
  displayName: "OpenCode Zen",
125299
125341
  envVars: ["OPENCODE_API_KEY"],
@@ -125494,6 +125536,17 @@ var providers = {
125494
125536
  effort: ["minimal", "low", "medium", "high"],
125495
125537
  openRouterResolve: "openrouter/openai/gpt-5-nano"
125496
125538
  },
125539
+ // Zen's PAID Muse Spark, priced like Meta's own Standard tier. not the
125540
+ // `-contributor-free` id beside it, which is the data-collection variant
125541
+ // Go refuses with DataPolicyError. unverified through the harness on
125542
+ // 2026-09-11: the workspace was out of balance and a claude-sonnet-5
125543
+ // control failed identically. see wiki/muse-spark.md.
125544
+ "muse-spark": {
125545
+ displayName: "Muse Spark",
125546
+ resolve: "opencode/muse-spark-1.3",
125547
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125548
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
125549
+ },
125497
125550
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
125498
125551
  // was alone in since `mimo-v2-pro-free` lost its model.
125499
125552
  mimo: {
@@ -125873,9 +125926,9 @@ var providers = {
125873
125926
  },
125874
125927
  grok: {
125875
125928
  displayName: "Grok",
125876
- resolve: "openrouter/x-ai/grok-4.5",
125877
- effort: ["low", "medium", "high"],
125878
- openRouterResolve: "openrouter/x-ai/grok-4.5"
125929
+ resolve: "openrouter/x-ai/grok-4.6",
125930
+ effort: ["low", "medium", "high", "xhigh"],
125931
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
125879
125932
  },
125880
125933
  // dated pin, not the bare id — see `deepseek/deepseek-pro` for why
125881
125934
  // OpenRouter's unversioned `deepseek-v4-pro` is the stale April preview.
@@ -125885,13 +125938,14 @@ var providers = {
125885
125938
  effort: ["low", "high", "max"],
125886
125939
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813"
125887
125940
  },
125888
- // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
125889
- // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
125941
+ // the V4.1 id, not the bare one — see `deepseek/deepseek-flash` for why
125942
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview
125943
+ // and why the `~deepseek/*-latest` pointer is no longer the target.
125890
125944
  "deepseek-flash": {
125891
125945
  displayName: "DeepSeek Flash",
125892
- resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
125946
+ resolve: "openrouter/deepseek/deepseek-v4.1-flash",
125893
125947
  effort: ["low", "high", "max"],
125894
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
125948
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
125895
125949
  },
125896
125950
  // legacy alias — deepseek retires this on 2026-07-24; transparently
125897
125951
  // upgrade existing users to the v4 family via the fallback chain.
@@ -125922,6 +125976,23 @@ var providers = {
125922
125976
  displayName: "MiniMax M3",
125923
125977
  resolve: "openrouter/minimax/minimax-m3",
125924
125978
  openRouterResolve: "openrouter/minimax/minimax-m3"
125979
+ },
125980
+ // OpenRouter gates Meta models on an ACCOUNT-level 18+ confirmation
125981
+ // (openrouter.ai/settings/preferences). Pullfrog's account has it, so the
125982
+ // Router path runs; a BYOK OpenRouter key without it refuses with that
125983
+ // link before the request reaches Meta. see wiki/muse-spark.md.
125984
+ "muse-spark": {
125985
+ displayName: "Muse Spark",
125986
+ resolve: "openrouter/meta/muse-spark-1.3",
125987
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125988
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
125989
+ },
125990
+ "muse-spark-contributor": {
125991
+ displayName: "Muse Spark Contributor",
125992
+ description: "Meta trains on prompts and completions",
125993
+ resolve: "openrouter/meta/muse-spark-1.3-contributor",
125994
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
125995
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
125925
125996
  }
125926
125997
  }
125927
125998
  }),
@@ -125989,10 +126060,13 @@ var providers = {
125989
126060
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
125990
126061
  effort: ["high", "xhigh"]
125991
126062
  },
126063
+ // the gateway's bare `deepseek-v4-flash` is the April preview — the same
126064
+ // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
126065
+ // this entry sat on the preview until V4.1. the gateway publishes no
126066
+ // effort ladder for the V4.1 id.
125992
126067
  "deepseek-flash": {
125993
126068
  displayName: "DeepSeek Flash",
125994
- resolve: "vercel/deepseek/deepseek-v4-flash",
125995
- effort: ["high", "xhigh"]
126069
+ resolve: "vercel/deepseek/deepseek-v4.1-flash"
125996
126070
  },
125997
126071
  glm: {
125998
126072
  displayName: "GLM",
@@ -126003,6 +126077,11 @@ var providers = {
126003
126077
  displayName: "Kimi K3",
126004
126078
  resolve: "vercel/moonshotai/kimi-k3",
126005
126079
  effort: ["low", "high", "max"]
126080
+ },
126081
+ // the gateway publishes no effort ladder for this id.
126082
+ "muse-spark": {
126083
+ displayName: "Muse Spark",
126084
+ resolve: "vercel/meta/muse-spark-1.3"
126006
126085
  }
126007
126086
  }
126008
126087
  })
@@ -126098,8 +126177,8 @@ var PROVIDER_LADDERS = {
126098
126177
  deep: "deepseek/deepseek-pro"
126099
126178
  },
126100
126179
  xai: {
126101
- minimal: "xai/grok-fast",
126102
- light: "xai/grok-fast",
126180
+ minimal: "xai/grok-4.3",
126181
+ light: "xai/grok-4.3",
126103
126182
  standard: "xai/grok",
126104
126183
  deep: "xai/grok"
126105
126184
  },
@@ -126181,15 +126260,22 @@ if (!defaultProxyAlias?.openRouterResolve) {
126181
126260
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
126182
126261
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
126183
126262
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
126263
+ const terminal = /* @__PURE__ */ new Set();
126184
126264
  for (const slug2 of Object.values(ladder)) {
126185
- if (!resolveDisplayAlias(slug2)) throw new Error(`${name} ladder names unknown alias ${slug2}`);
126265
+ const alias = resolveDisplayAlias(slug2);
126266
+ if (!alias) throw new Error(`${name} ladder names unknown alias ${slug2}`);
126267
+ terminal.add(alias.slug);
126186
126268
  }
126269
+ if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
126187
126270
  }
126188
126271
  var OSS_MODEL_ALLOWLIST = [
126189
126272
  "deepseek/deepseek-flash",
126190
- "deepseek/deepseek-pro",
126191
126273
  "openai/gpt-luna",
126192
- "openrouter/minimax-m2.5"
126274
+ "openrouter/minimax-m2.5",
126275
+ // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
126276
+ // traffic — fine for public code on headless runs, the human decided
126277
+ // 2026-09-11. unmeasured on a real run; not the default until it is.
126278
+ "meta/muse-spark-contributor"
126193
126279
  ];
126194
126280
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
126195
126281
  function ossFundedModelNames() {
@@ -135865,13 +135951,29 @@ function azureProvider(model) {
135865
135951
  };
135866
135952
  }
135867
135953
  var KIMI_ENFORCERLESS_PROVIDERS = ["siliconflow", "together"];
135868
- function kimiOpenRouterProviderOverrides() {
135869
- return Object.fromEntries(
135870
- modelAliases.map((a2) => a2.openRouterResolve).filter((r2) => r2?.includes("kimi") ?? false).map((r2) => [
135871
- r2.replace(/^openrouter\//, ""),
135872
- { options: { provider: { ignore: KIMI_ENFORCERLESS_PROVIDERS } } }
135873
- ])
135874
- );
135954
+ function openRouterDataCollection(ctx) {
135955
+ if (!ctx.payload.proxyModel) return void 0;
135956
+ return ctx.toolState.oss ? "allow" : "deny";
135957
+ }
135958
+ function dataCollectionPreference(policy) {
135959
+ if (!policy) return {};
135960
+ return { data_collection: policy };
135961
+ }
135962
+ function openRouterProvider(policy) {
135963
+ const models = {};
135964
+ for (const alias of modelAliases) {
135965
+ const id = alias.openRouterResolve?.replace(/^openrouter\//, "");
135966
+ if (!id) continue;
135967
+ if (id.endsWith("-contributor")) {
135968
+ models[id] = { options: { provider: { data_collection: "allow" } } };
135969
+ }
135970
+ if (id.includes("kimi")) {
135971
+ const provider2 = { ...dataCollectionPreference(policy), ignore: KIMI_ENFORCERLESS_PROVIDERS };
135972
+ models[id] = { options: { provider: provider2 } };
135973
+ }
135974
+ }
135975
+ if (!policy) return { models };
135976
+ return { options: { extraBody: { provider: { data_collection: policy } } }, models };
135875
135977
  }
135876
135978
  function buildReviewerAgentConfig(orchestratorModel) {
135877
135979
  const overrides = deriveSubagentModels(orchestratorModel);
@@ -135947,13 +136049,12 @@ function buildSecurityConfig(ctx, model) {
135947
136049
  log2.info(`\xBB subagent models: reviewfrog=${reviewerModel}`);
135948
136050
  return cfg;
135949
136051
  })(),
135950
- // kimi pinned away from Enforcer-less openrouter providers (siliconflow /
135951
- // together) that drop optional tool-call params — per-model on the
135952
- // openrouter route, so other models are unaffected. this is routing, not
135953
- // reasoning: every model's effort now rides the per-prompt `variant`.
135954
- // see opencodeShared.ts.
136052
+ // openrouter routing, not reasoning (every model's effort rides the
136053
+ // per-prompt `variant`): the run's data-collection policy, kimi pinned
136054
+ // away from Enforcer-less providers, the Muse Spark contributor tier
136055
+ // opened to training hosts. see opencodeShared.ts.
135955
136056
  provider: {
135956
- openrouter: { models: kimiOpenRouterProviderOverrides() },
136057
+ openrouter: openRouterProvider(openRouterDataCollection(ctx)),
135957
136058
  ...openAICompatibleProvider(model),
135958
136059
  ...azureProvider(model),
135959
136060
  ...providerGatewayOverride(model)
@@ -219871,7 +219972,7 @@ function resolveTarget2(repo) {
219871
219972
  return { owner: match3[1], repo: match3[2] };
219872
219973
  }
219873
219974
  function cliVersion() {
219874
- const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.77");
219975
+ const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.78");
219875
219976
  if (!parts) return "0.0.0";
219876
219977
  return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
219877
219978
  }
@@ -220038,7 +220139,7 @@ async function runCli8(input2) {
220038
220139
  }
220039
220140
 
220040
220141
  // cli.ts
220041
- var VERSION10 = "0.1.77";
220142
+ var VERSION10 = "0.1.78";
220042
220143
  var bin = basename2(process.argv[1] || "");
220043
220144
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
220044
220145
  var rawArgs = process.argv.slice(2);
package/dist/index.js CHANGED
@@ -107941,26 +107941,34 @@ var providers = {
107941
107941
  models: {
107942
107942
  grok: {
107943
107943
  displayName: "Grok",
107944
- resolve: "xai/grok-4.5",
107945
- effort: ["low", "medium", "high"],
107946
- openRouterResolve: "openrouter/x-ai/grok-4.5",
107944
+ resolve: "xai/grok-4.6",
107945
+ effort: ["low", "medium", "high", "xhigh"],
107946
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
107947
107947
  preferred: true
107948
107948
  },
107949
+ // the Smart ladder's cheap rung: 1.25/2.5 against 4.6's 2/6, and a 0.2
107950
+ // cache read against 0.5 — the only live xAI model a rung can save on.
107951
+ "grok-4.3": {
107952
+ displayName: "Grok 4.3",
107953
+ resolve: "xai/grok-4.3",
107954
+ effort: ["none", "low", "medium", "high"],
107955
+ openRouterResolve: "openrouter/x-ai/grok-4.3"
107956
+ },
107949
107957
  // legacy aliases — xAI retired the entire fast/code-fast line on
107950
107958
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
107951
107959
  // and now redirects every deprecated text-model slug to grok-4.3 at
107952
107960
  // standard pricing. fall back to the live `xai/grok` so the alias
107953
- // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
107961
+ // chain resolves to grok-4.6 for both direct-key and OpenRouter users.
107954
107962
  "grok-fast": {
107955
107963
  displayName: "Grok Fast",
107956
107964
  resolve: "xai/grok-4-1-fast",
107957
- openRouterResolve: "openrouter/x-ai/grok-4.5",
107965
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
107958
107966
  fallback: "xai/grok"
107959
107967
  },
107960
107968
  "grok-code-fast": {
107961
107969
  displayName: "Grok Code Fast",
107962
107970
  resolve: "xai/grok-code-fast-1",
107963
- openRouterResolve: "openrouter/x-ai/grok-4.5",
107971
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
107964
107972
  fallback: "xai/grok"
107965
107973
  }
107966
107974
  }
@@ -107979,6 +107987,12 @@ var providers = {
107979
107987
  // $0.0405. there is no `~deepseek/*-pro-latest` pointer to track, so this
107980
107988
  // one has to be a dated pin; the `models-catalog` drift test is what
107981
107989
  // catches the next release.
107990
+ // from 2026-09-14 DeepSeek serves every direct `deepseek-v4-pro` call with
107991
+ // V4.1-Flash at Flash rates until V4.1-Pro ships. it is still the only Pro
107992
+ // id the vendor lists, and the OpenRouter 0813 pin is third-party-hosted
107993
+ // and unaffected — so no `fallback` to Flash, which would drag the Router
107994
+ // route down with it. the OSS program dropped Pro from its menu instead;
107995
+ // see `OSS_MODEL_ALLOWLIST`.
107982
107996
  "deepseek-pro": {
107983
107997
  displayName: "DeepSeek Pro",
107984
107998
  resolve: "deepseek/deepseek-v4-pro",
@@ -107987,30 +108001,24 @@ var providers = {
107987
108001
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813",
107988
108002
  preferred: true
107989
108003
  },
107990
- // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
107991
- // direct `resolve` needs no version. OpenRouter instead forked the 0731
107992
- // release into its own id and left the April preview live under the
107993
- // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
107994
- // OpenRouter route can never use the bare id. it tracks the rolling
107995
- // `~deepseek/*-latest` pointer (rule 4), which follows the next in-place
107996
- // upgrade on its own rather than pinning a dated snapshot that goes stale
107997
- // every release. that pointer is NOT priced like 0731 — its listed rates
107998
- // run +40% on output and +57.5% on cache read, and it costs 12% more per
107999
- // run on authoritative spend ($0.0405 vs $0.0361). kept anyway: ~$45/yr
108000
- // buys auto-following the upgrade, and the listed gap overstates the real
108001
- // one because a rolling alias prices at its routing ceiling.
108002
- // 0731 gained a `low` rung and renamed the top to `max`, and that ladder
108003
- // now reads the same on BOTH routes — the in-place direct upgrade caught
108004
- // up to the fork. so `low`, not `high`, is position 0 either way, which is
108005
- // why the OSS effort floor in `main.ts` pins the `high` rung by name. Pro
108006
- // is the same shape via OpenRouter since 0813; only its direct route still
108007
- // starts at `high`.
108004
+ // V4.1-Flash (2026-09-10) retired `deepseek-v4-flash`; DeepSeek's /models
108005
+ // now lists the unversioned `deepseek-flash`, so the direct resolve is the
108006
+ // rolling id at the same price. OpenRouter treats V4.1 as its own id
108007
+ // (`deepseek/deepseek-v4.1-flash`, $0.15/$0.6, cache $0.003) and its
108008
+ // `~deepseek/deepseek-v4-flash-latest` pointer still served 0731 on
108009
+ // 2026-09-11, so this is a pinned id rather than the pointer and the next
108010
+ // Flash release is a catalog edit (the bump cron flags it). this target is
108011
+ // the funded OSS default: priced on the measured OSS token mix at x1.34
108012
+ // the pointer's $0.0531/run on the DeepSeek-hosted endpoint — see
108013
+ // wiki/oss-model-allowlist.md. the bare `deepseek-v4-flash` on OpenRouter
108014
+ // is still the April preview, so that route can never use it. both routes
108015
+ // publish `low, high, max`; the OSS effort floor pins `high` by name.
108008
108016
  "deepseek-flash": {
108009
108017
  displayName: "DeepSeek Flash",
108010
- resolve: "deepseek/deepseek-v4-flash",
108018
+ resolve: "deepseek/deepseek-flash",
108011
108019
  effort: ["low", "high", "max"],
108012
108020
  openRouterEffort: ["low", "high", "max"],
108013
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
108021
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
108014
108022
  },
108015
108023
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
108016
108024
  // upgrade existing users to the v4 family via the fallback chain.
@@ -108113,6 +108121,40 @@ var providers = {
108113
108121
  }
108114
108122
  }
108115
108123
  }),
108124
+ // Meta Model API — the direct route to Muse Spark. a registry entry, like
108125
+ // kimi-for-coding: models.dev carries `meta` (`https://api.meta.ai/v1`, npm
108126
+ // `@ai-sdk/openai`) and opencode 1.18.29 enables it from a bare
108127
+ // META_MODEL_API_KEY — all five ids list in `opencode models`, and a bogus key
108128
+ // reaches Meta's own auth check (`invalid_api_key`). see wiki/muse-spark.md.
108129
+ meta: provider({
108130
+ displayName: "Meta",
108131
+ envVars: ["META_MODEL_API_KEY"],
108132
+ models: {
108133
+ // the Standard tier. no `subagentModel`: the contributor tier below is
108134
+ // the same model, not a cheaper sibling.
108135
+ "muse-spark": {
108136
+ displayName: "Muse Spark",
108137
+ resolve: "meta/muse-spark-1.3",
108138
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108139
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
108140
+ preferred: true
108141
+ },
108142
+ // the Contributor tier: the same model at $0.10 / $0.20 (cache read
108143
+ // $0.002) because Meta trains on the prompts and completions. an opt-in
108144
+ // pick on the OSS menu (public code, headless runs), never the default.
108145
+ // OpenRouter only serves it when the account allows paid-model training,
108146
+ // so the runtime opens data collection for this id alone — see
108147
+ // `openRouterProvider` in opencodeShared.ts.
108148
+ "muse-spark-contributor": {
108149
+ displayName: "Muse Spark Contributor",
108150
+ description: "Meta trains on prompts and completions",
108151
+ resolve: "meta/muse-spark-1.3-contributor",
108152
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
108153
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108154
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
108155
+ }
108156
+ }
108157
+ }),
108116
108158
  opencode: provider({
108117
108159
  displayName: "OpenCode Zen",
108118
108160
  envVars: ["OPENCODE_API_KEY"],
@@ -108313,6 +108355,17 @@ var providers = {
108313
108355
  effort: ["minimal", "low", "medium", "high"],
108314
108356
  openRouterResolve: "openrouter/openai/gpt-5-nano"
108315
108357
  },
108358
+ // Zen's PAID Muse Spark, priced like Meta's own Standard tier. not the
108359
+ // `-contributor-free` id beside it, which is the data-collection variant
108360
+ // Go refuses with DataPolicyError. unverified through the harness on
108361
+ // 2026-09-11: the workspace was out of balance and a claude-sonnet-5
108362
+ // control failed identically. see wiki/muse-spark.md.
108363
+ "muse-spark": {
108364
+ displayName: "Muse Spark",
108365
+ resolve: "opencode/muse-spark-1.3",
108366
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108367
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
108368
+ },
108316
108369
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
108317
108370
  // was alone in since `mimo-v2-pro-free` lost its model.
108318
108371
  mimo: {
@@ -108692,9 +108745,9 @@ var providers = {
108692
108745
  },
108693
108746
  grok: {
108694
108747
  displayName: "Grok",
108695
- resolve: "openrouter/x-ai/grok-4.5",
108696
- effort: ["low", "medium", "high"],
108697
- openRouterResolve: "openrouter/x-ai/grok-4.5"
108748
+ resolve: "openrouter/x-ai/grok-4.6",
108749
+ effort: ["low", "medium", "high", "xhigh"],
108750
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
108698
108751
  },
108699
108752
  // dated pin, not the bare id — see `deepseek/deepseek-pro` for why
108700
108753
  // OpenRouter's unversioned `deepseek-v4-pro` is the stale April preview.
@@ -108704,13 +108757,14 @@ var providers = {
108704
108757
  effort: ["low", "high", "max"],
108705
108758
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813"
108706
108759
  },
108707
- // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
108708
- // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
108760
+ // the V4.1 id, not the bare one — see `deepseek/deepseek-flash` for why
108761
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview
108762
+ // and why the `~deepseek/*-latest` pointer is no longer the target.
108709
108763
  "deepseek-flash": {
108710
108764
  displayName: "DeepSeek Flash",
108711
- resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
108765
+ resolve: "openrouter/deepseek/deepseek-v4.1-flash",
108712
108766
  effort: ["low", "high", "max"],
108713
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
108767
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
108714
108768
  },
108715
108769
  // legacy alias — deepseek retires this on 2026-07-24; transparently
108716
108770
  // upgrade existing users to the v4 family via the fallback chain.
@@ -108741,6 +108795,23 @@ var providers = {
108741
108795
  displayName: "MiniMax M3",
108742
108796
  resolve: "openrouter/minimax/minimax-m3",
108743
108797
  openRouterResolve: "openrouter/minimax/minimax-m3"
108798
+ },
108799
+ // OpenRouter gates Meta models on an ACCOUNT-level 18+ confirmation
108800
+ // (openrouter.ai/settings/preferences). Pullfrog's account has it, so the
108801
+ // Router path runs; a BYOK OpenRouter key without it refuses with that
108802
+ // link before the request reaches Meta. see wiki/muse-spark.md.
108803
+ "muse-spark": {
108804
+ displayName: "Muse Spark",
108805
+ resolve: "openrouter/meta/muse-spark-1.3",
108806
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108807
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
108808
+ },
108809
+ "muse-spark-contributor": {
108810
+ displayName: "Muse Spark Contributor",
108811
+ description: "Meta trains on prompts and completions",
108812
+ resolve: "openrouter/meta/muse-spark-1.3-contributor",
108813
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
108814
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
108744
108815
  }
108745
108816
  }
108746
108817
  }),
@@ -108808,10 +108879,13 @@ var providers = {
108808
108879
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
108809
108880
  effort: ["high", "xhigh"]
108810
108881
  },
108882
+ // the gateway's bare `deepseek-v4-flash` is the April preview — the same
108883
+ // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
108884
+ // this entry sat on the preview until V4.1. the gateway publishes no
108885
+ // effort ladder for the V4.1 id.
108811
108886
  "deepseek-flash": {
108812
108887
  displayName: "DeepSeek Flash",
108813
- resolve: "vercel/deepseek/deepseek-v4-flash",
108814
- effort: ["high", "xhigh"]
108888
+ resolve: "vercel/deepseek/deepseek-v4.1-flash"
108815
108889
  },
108816
108890
  glm: {
108817
108891
  displayName: "GLM",
@@ -108822,6 +108896,11 @@ var providers = {
108822
108896
  displayName: "Kimi K3",
108823
108897
  resolve: "vercel/moonshotai/kimi-k3",
108824
108898
  effort: ["low", "high", "max"]
108899
+ },
108900
+ // the gateway publishes no effort ladder for this id.
108901
+ "muse-spark": {
108902
+ displayName: "Muse Spark",
108903
+ resolve: "vercel/meta/muse-spark-1.3"
108825
108904
  }
108826
108905
  }
108827
108906
  })
@@ -108917,8 +108996,8 @@ var PROVIDER_LADDERS = {
108917
108996
  deep: "deepseek/deepseek-pro"
108918
108997
  },
108919
108998
  xai: {
108920
- minimal: "xai/grok-fast",
108921
- light: "xai/grok-fast",
108999
+ minimal: "xai/grok-4.3",
109000
+ light: "xai/grok-4.3",
108922
109001
  standard: "xai/grok",
108923
109002
  deep: "xai/grok"
108924
109003
  },
@@ -109000,15 +109079,22 @@ if (!defaultProxyAlias?.openRouterResolve) {
109000
109079
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
109001
109080
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
109002
109081
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
109082
+ const terminal = /* @__PURE__ */ new Set();
109003
109083
  for (const slug2 of Object.values(ladder)) {
109004
- if (!resolveDisplayAlias(slug2)) throw new Error(`${name} ladder names unknown alias ${slug2}`);
109084
+ const alias = resolveDisplayAlias(slug2);
109085
+ if (!alias) throw new Error(`${name} ladder names unknown alias ${slug2}`);
109086
+ terminal.add(alias.slug);
109005
109087
  }
109088
+ if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
109006
109089
  }
109007
109090
  var OSS_MODEL_ALLOWLIST = [
109008
109091
  "deepseek/deepseek-flash",
109009
- "deepseek/deepseek-pro",
109010
109092
  "openai/gpt-luna",
109011
- "openrouter/minimax-m2.5"
109093
+ "openrouter/minimax-m2.5",
109094
+ // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
109095
+ // traffic — fine for public code on headless runs, the human decided
109096
+ // 2026-09-11. unmeasured on a real run; not the default until it is.
109097
+ "meta/muse-spark-contributor"
109012
109098
  ];
109013
109099
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
109014
109100
  function ossFundedModelNames() {
@@ -109876,7 +109962,7 @@ var import_semver = __toESM(require_semver2(), 1);
109876
109962
  // package.json
109877
109963
  var package_default = {
109878
109964
  name: "pullfrog",
109879
- version: "0.1.77",
109965
+ version: "0.1.78",
109880
109966
  cliContractVersion: "1",
109881
109967
  type: "module",
109882
109968
  bin: {
@@ -118725,13 +118811,29 @@ function azureProvider(model) {
118725
118811
  };
118726
118812
  }
118727
118813
  var KIMI_ENFORCERLESS_PROVIDERS = ["siliconflow", "together"];
118728
- function kimiOpenRouterProviderOverrides() {
118729
- return Object.fromEntries(
118730
- modelAliases.map((a) => a.openRouterResolve).filter((r) => r?.includes("kimi") ?? false).map((r) => [
118731
- r.replace(/^openrouter\//, ""),
118732
- { options: { provider: { ignore: KIMI_ENFORCERLESS_PROVIDERS } } }
118733
- ])
118734
- );
118814
+ function openRouterDataCollection(ctx) {
118815
+ if (!ctx.payload.proxyModel) return void 0;
118816
+ return ctx.toolState.oss ? "allow" : "deny";
118817
+ }
118818
+ function dataCollectionPreference(policy) {
118819
+ if (!policy) return {};
118820
+ return { data_collection: policy };
118821
+ }
118822
+ function openRouterProvider(policy) {
118823
+ const models = {};
118824
+ for (const alias of modelAliases) {
118825
+ const id = alias.openRouterResolve?.replace(/^openrouter\//, "");
118826
+ if (!id) continue;
118827
+ if (id.endsWith("-contributor")) {
118828
+ models[id] = { options: { provider: { data_collection: "allow" } } };
118829
+ }
118830
+ if (id.includes("kimi")) {
118831
+ const provider2 = { ...dataCollectionPreference(policy), ignore: KIMI_ENFORCERLESS_PROVIDERS };
118832
+ models[id] = { options: { provider: provider2 } };
118833
+ }
118834
+ }
118835
+ if (!policy) return { models };
118836
+ return { options: { extraBody: { provider: { data_collection: policy } } }, models };
118735
118837
  }
118736
118838
  function buildReviewerAgentConfig(orchestratorModel) {
118737
118839
  const overrides = deriveSubagentModels(orchestratorModel);
@@ -118807,13 +118909,12 @@ function buildSecurityConfig(ctx, model) {
118807
118909
  log.info(`\xBB subagent models: reviewfrog=${reviewerModel}`);
118808
118910
  return cfg;
118809
118911
  })(),
118810
- // kimi pinned away from Enforcer-less openrouter providers (siliconflow /
118811
- // together) that drop optional tool-call params — per-model on the
118812
- // openrouter route, so other models are unaffected. this is routing, not
118813
- // reasoning: every model's effort now rides the per-prompt `variant`.
118814
- // see opencodeShared.ts.
118912
+ // openrouter routing, not reasoning (every model's effort rides the
118913
+ // per-prompt `variant`): the run's data-collection policy, kimi pinned
118914
+ // away from Enforcer-less providers, the Muse Spark contributor tier
118915
+ // opened to training hosts. see opencodeShared.ts.
118815
118916
  provider: {
118816
- openrouter: { models: kimiOpenRouterProviderOverrides() },
118917
+ openrouter: openRouterProvider(openRouterDataCollection(ctx)),
118817
118918
  ...openAICompatibleProvider(model),
118818
118919
  ...azureProvider(model),
118819
118920
  ...providerGatewayOverride(model)
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.77",
11
+ version: "0.1.78",
12
12
  cliContractVersion: "1",
13
13
  type: "module",
14
14
  bin: {
@@ -14509,26 +14509,34 @@ var providers = {
14509
14509
  models: {
14510
14510
  grok: {
14511
14511
  displayName: "Grok",
14512
- resolve: "xai/grok-4.5",
14513
- effort: ["low", "medium", "high"],
14514
- openRouterResolve: "openrouter/x-ai/grok-4.5",
14512
+ resolve: "xai/grok-4.6",
14513
+ effort: ["low", "medium", "high", "xhigh"],
14514
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
14515
14515
  preferred: true
14516
14516
  },
14517
+ // the Smart ladder's cheap rung: 1.25/2.5 against 4.6's 2/6, and a 0.2
14518
+ // cache read against 0.5 — the only live xAI model a rung can save on.
14519
+ "grok-4.3": {
14520
+ displayName: "Grok 4.3",
14521
+ resolve: "xai/grok-4.3",
14522
+ effort: ["none", "low", "medium", "high"],
14523
+ openRouterResolve: "openrouter/x-ai/grok-4.3"
14524
+ },
14517
14525
  // legacy aliases — xAI retired the entire fast/code-fast line on
14518
14526
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
14519
14527
  // and now redirects every deprecated text-model slug to grok-4.3 at
14520
14528
  // standard pricing. fall back to the live `xai/grok` so the alias
14521
- // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
14529
+ // chain resolves to grok-4.6 for both direct-key and OpenRouter users.
14522
14530
  "grok-fast": {
14523
14531
  displayName: "Grok Fast",
14524
14532
  resolve: "xai/grok-4-1-fast",
14525
- openRouterResolve: "openrouter/x-ai/grok-4.5",
14533
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
14526
14534
  fallback: "xai/grok"
14527
14535
  },
14528
14536
  "grok-code-fast": {
14529
14537
  displayName: "Grok Code Fast",
14530
14538
  resolve: "xai/grok-code-fast-1",
14531
- openRouterResolve: "openrouter/x-ai/grok-4.5",
14539
+ openRouterResolve: "openrouter/x-ai/grok-4.6",
14532
14540
  fallback: "xai/grok"
14533
14541
  }
14534
14542
  }
@@ -14547,6 +14555,12 @@ var providers = {
14547
14555
  // $0.0405. there is no `~deepseek/*-pro-latest` pointer to track, so this
14548
14556
  // one has to be a dated pin; the `models-catalog` drift test is what
14549
14557
  // catches the next release.
14558
+ // from 2026-09-14 DeepSeek serves every direct `deepseek-v4-pro` call with
14559
+ // V4.1-Flash at Flash rates until V4.1-Pro ships. it is still the only Pro
14560
+ // id the vendor lists, and the OpenRouter 0813 pin is third-party-hosted
14561
+ // and unaffected — so no `fallback` to Flash, which would drag the Router
14562
+ // route down with it. the OSS program dropped Pro from its menu instead;
14563
+ // see `OSS_MODEL_ALLOWLIST`.
14550
14564
  "deepseek-pro": {
14551
14565
  displayName: "DeepSeek Pro",
14552
14566
  resolve: "deepseek/deepseek-v4-pro",
@@ -14555,30 +14569,24 @@ var providers = {
14555
14569
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813",
14556
14570
  preferred: true
14557
14571
  },
14558
- // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
14559
- // direct `resolve` needs no version. OpenRouter instead forked the 0731
14560
- // release into its own id and left the April preview live under the
14561
- // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
14562
- // OpenRouter route can never use the bare id. it tracks the rolling
14563
- // `~deepseek/*-latest` pointer (rule 4), which follows the next in-place
14564
- // upgrade on its own rather than pinning a dated snapshot that goes stale
14565
- // every release. that pointer is NOT priced like 0731 — its listed rates
14566
- // run +40% on output and +57.5% on cache read, and it costs 12% more per
14567
- // run on authoritative spend ($0.0405 vs $0.0361). kept anyway: ~$45/yr
14568
- // buys auto-following the upgrade, and the listed gap overstates the real
14569
- // one because a rolling alias prices at its routing ceiling.
14570
- // 0731 gained a `low` rung and renamed the top to `max`, and that ladder
14571
- // now reads the same on BOTH routes — the in-place direct upgrade caught
14572
- // up to the fork. so `low`, not `high`, is position 0 either way, which is
14573
- // why the OSS effort floor in `main.ts` pins the `high` rung by name. Pro
14574
- // is the same shape via OpenRouter since 0813; only its direct route still
14575
- // starts at `high`.
14572
+ // V4.1-Flash (2026-09-10) retired `deepseek-v4-flash`; DeepSeek's /models
14573
+ // now lists the unversioned `deepseek-flash`, so the direct resolve is the
14574
+ // rolling id at the same price. OpenRouter treats V4.1 as its own id
14575
+ // (`deepseek/deepseek-v4.1-flash`, $0.15/$0.6, cache $0.003) and its
14576
+ // `~deepseek/deepseek-v4-flash-latest` pointer still served 0731 on
14577
+ // 2026-09-11, so this is a pinned id rather than the pointer and the next
14578
+ // Flash release is a catalog edit (the bump cron flags it). this target is
14579
+ // the funded OSS default: priced on the measured OSS token mix at x1.34
14580
+ // the pointer's $0.0531/run on the DeepSeek-hosted endpoint — see
14581
+ // wiki/oss-model-allowlist.md. the bare `deepseek-v4-flash` on OpenRouter
14582
+ // is still the April preview, so that route can never use it. both routes
14583
+ // publish `low, high, max`; the OSS effort floor pins `high` by name.
14576
14584
  "deepseek-flash": {
14577
14585
  displayName: "DeepSeek Flash",
14578
- resolve: "deepseek/deepseek-v4-flash",
14586
+ resolve: "deepseek/deepseek-flash",
14579
14587
  effort: ["low", "high", "max"],
14580
14588
  openRouterEffort: ["low", "high", "max"],
14581
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
14589
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
14582
14590
  },
14583
14591
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
14584
14592
  // upgrade existing users to the v4 family via the fallback chain.
@@ -14681,6 +14689,40 @@ var providers = {
14681
14689
  }
14682
14690
  }
14683
14691
  }),
14692
+ // Meta Model API — the direct route to Muse Spark. a registry entry, like
14693
+ // kimi-for-coding: models.dev carries `meta` (`https://api.meta.ai/v1`, npm
14694
+ // `@ai-sdk/openai`) and opencode 1.18.29 enables it from a bare
14695
+ // META_MODEL_API_KEY — all five ids list in `opencode models`, and a bogus key
14696
+ // reaches Meta's own auth check (`invalid_api_key`). see wiki/muse-spark.md.
14697
+ meta: provider({
14698
+ displayName: "Meta",
14699
+ envVars: ["META_MODEL_API_KEY"],
14700
+ models: {
14701
+ // the Standard tier. no `subagentModel`: the contributor tier below is
14702
+ // the same model, not a cheaper sibling.
14703
+ "muse-spark": {
14704
+ displayName: "Muse Spark",
14705
+ resolve: "meta/muse-spark-1.3",
14706
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14707
+ openRouterResolve: "openrouter/meta/muse-spark-1.3",
14708
+ preferred: true
14709
+ },
14710
+ // the Contributor tier: the same model at $0.10 / $0.20 (cache read
14711
+ // $0.002) because Meta trains on the prompts and completions. an opt-in
14712
+ // pick on the OSS menu (public code, headless runs), never the default.
14713
+ // OpenRouter only serves it when the account allows paid-model training,
14714
+ // so the runtime opens data collection for this id alone — see
14715
+ // `openRouterProvider` in opencodeShared.ts.
14716
+ "muse-spark-contributor": {
14717
+ displayName: "Muse Spark Contributor",
14718
+ description: "Meta trains on prompts and completions",
14719
+ resolve: "meta/muse-spark-1.3-contributor",
14720
+ effort: ["minimal", "low", "medium", "high", "xhigh"],
14721
+ openRouterEffort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14722
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
14723
+ }
14724
+ }
14725
+ }),
14684
14726
  opencode: provider({
14685
14727
  displayName: "OpenCode Zen",
14686
14728
  envVars: ["OPENCODE_API_KEY"],
@@ -14881,6 +14923,17 @@ var providers = {
14881
14923
  effort: ["minimal", "low", "medium", "high"],
14882
14924
  openRouterResolve: "openrouter/openai/gpt-5-nano"
14883
14925
  },
14926
+ // Zen's PAID Muse Spark, priced like Meta's own Standard tier. not the
14927
+ // `-contributor-free` id beside it, which is the data-collection variant
14928
+ // Go refuses with DataPolicyError. unverified through the harness on
14929
+ // 2026-09-11: the workspace was out of balance and a claude-sonnet-5
14930
+ // control failed identically. see wiki/muse-spark.md.
14931
+ "muse-spark": {
14932
+ displayName: "Muse Spark",
14933
+ resolve: "opencode/muse-spark-1.3",
14934
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
14935
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
14936
+ },
14884
14937
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
14885
14938
  // was alone in since `mimo-v2-pro-free` lost its model.
14886
14939
  mimo: {
@@ -15260,9 +15313,9 @@ var providers = {
15260
15313
  },
15261
15314
  grok: {
15262
15315
  displayName: "Grok",
15263
- resolve: "openrouter/x-ai/grok-4.5",
15264
- effort: ["low", "medium", "high"],
15265
- openRouterResolve: "openrouter/x-ai/grok-4.5"
15316
+ resolve: "openrouter/x-ai/grok-4.6",
15317
+ effort: ["low", "medium", "high", "xhigh"],
15318
+ openRouterResolve: "openrouter/x-ai/grok-4.6"
15266
15319
  },
15267
15320
  // dated pin, not the bare id — see `deepseek/deepseek-pro` for why
15268
15321
  // OpenRouter's unversioned `deepseek-v4-pro` is the stale April preview.
@@ -15272,13 +15325,14 @@ var providers = {
15272
15325
  effort: ["low", "high", "max"],
15273
15326
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro-0813"
15274
15327
  },
15275
- // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
15276
- // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
15328
+ // the V4.1 id, not the bare one — see `deepseek/deepseek-flash` for why
15329
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview
15330
+ // and why the `~deepseek/*-latest` pointer is no longer the target.
15277
15331
  "deepseek-flash": {
15278
15332
  displayName: "DeepSeek Flash",
15279
- resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
15333
+ resolve: "openrouter/deepseek/deepseek-v4.1-flash",
15280
15334
  effort: ["low", "high", "max"],
15281
- openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
15335
+ openRouterResolve: "openrouter/deepseek/deepseek-v4.1-flash"
15282
15336
  },
15283
15337
  // legacy alias — deepseek retires this on 2026-07-24; transparently
15284
15338
  // upgrade existing users to the v4 family via the fallback chain.
@@ -15309,6 +15363,23 @@ var providers = {
15309
15363
  displayName: "MiniMax M3",
15310
15364
  resolve: "openrouter/minimax/minimax-m3",
15311
15365
  openRouterResolve: "openrouter/minimax/minimax-m3"
15366
+ },
15367
+ // OpenRouter gates Meta models on an ACCOUNT-level 18+ confirmation
15368
+ // (openrouter.ai/settings/preferences). Pullfrog's account has it, so the
15369
+ // Router path runs; a BYOK OpenRouter key without it refuses with that
15370
+ // link before the request reaches Meta. see wiki/muse-spark.md.
15371
+ "muse-spark": {
15372
+ displayName: "Muse Spark",
15373
+ resolve: "openrouter/meta/muse-spark-1.3",
15374
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
15375
+ openRouterResolve: "openrouter/meta/muse-spark-1.3"
15376
+ },
15377
+ "muse-spark-contributor": {
15378
+ displayName: "Muse Spark Contributor",
15379
+ description: "Meta trains on prompts and completions",
15380
+ resolve: "openrouter/meta/muse-spark-1.3-contributor",
15381
+ effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
15382
+ openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
15312
15383
  }
15313
15384
  }
15314
15385
  }),
@@ -15376,10 +15447,13 @@ var providers = {
15376
15447
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
15377
15448
  effort: ["high", "xhigh"]
15378
15449
  },
15450
+ // the gateway's bare `deepseek-v4-flash` is the April preview — the same
15451
+ // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
15452
+ // this entry sat on the preview until V4.1. the gateway publishes no
15453
+ // effort ladder for the V4.1 id.
15379
15454
  "deepseek-flash": {
15380
15455
  displayName: "DeepSeek Flash",
15381
- resolve: "vercel/deepseek/deepseek-v4-flash",
15382
- effort: ["high", "xhigh"]
15456
+ resolve: "vercel/deepseek/deepseek-v4.1-flash"
15383
15457
  },
15384
15458
  glm: {
15385
15459
  displayName: "GLM",
@@ -15390,6 +15464,11 @@ var providers = {
15390
15464
  displayName: "Kimi K3",
15391
15465
  resolve: "vercel/moonshotai/kimi-k3",
15392
15466
  effort: ["low", "high", "max"]
15467
+ },
15468
+ // the gateway publishes no effort ladder for this id.
15469
+ "muse-spark": {
15470
+ displayName: "Muse Spark",
15471
+ resolve: "vercel/meta/muse-spark-1.3"
15393
15472
  }
15394
15473
  }
15395
15474
  })
@@ -15505,8 +15584,8 @@ var PROVIDER_LADDERS = {
15505
15584
  deep: "deepseek/deepseek-pro"
15506
15585
  },
15507
15586
  xai: {
15508
- minimal: "xai/grok-fast",
15509
- light: "xai/grok-fast",
15587
+ minimal: "xai/grok-4.3",
15588
+ light: "xai/grok-4.3",
15510
15589
  standard: "xai/grok",
15511
15590
  deep: "xai/grok"
15512
15591
  },
@@ -15610,15 +15689,22 @@ if (!defaultProxyAlias?.openRouterResolve) {
15610
15689
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
15611
15690
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
15612
15691
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
15692
+ const terminal = /* @__PURE__ */ new Set();
15613
15693
  for (const slug of Object.values(ladder)) {
15614
- if (!resolveDisplayAlias(slug)) throw new Error(`${name} ladder names unknown alias ${slug}`);
15694
+ const alias = resolveDisplayAlias(slug);
15695
+ if (!alias) throw new Error(`${name} ladder names unknown alias ${slug}`);
15696
+ terminal.add(alias.slug);
15615
15697
  }
15698
+ if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
15616
15699
  }
15617
15700
  var OSS_MODEL_ALLOWLIST = [
15618
15701
  "deepseek/deepseek-flash",
15619
- "deepseek/deepseek-pro",
15620
15702
  "openai/gpt-luna",
15621
- "openrouter/minimax-m2.5"
15703
+ "openrouter/minimax-m2.5",
15704
+ // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
15705
+ // traffic — fine for public code on headless runs, the human decided
15706
+ // 2026-09-11. unmeasured on a real run; not the default until it is.
15707
+ "meta/muse-spark-contributor"
15622
15708
  ];
15623
15709
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
15624
15710
  function ossFundedModelNames() {
package/dist/models.d.ts CHANGED
@@ -121,6 +121,7 @@ export declare const providers: {
121
121
  deepseek: ProviderConfig;
122
122
  moonshotai: ProviderConfig;
123
123
  "kimi-for-coding": ProviderConfig;
124
+ meta: ProviderConfig;
124
125
  opencode: ProviderConfig;
125
126
  "opencode-go": ProviderConfig;
126
127
  bedrock: ProviderConfig;
@@ -344,6 +345,12 @@ export declare const DEFAULT_PROXY_MODEL: string;
344
345
  * over 2,203 real runs ($0.4782 vs $0.0362), almost entirely on its cache-read
345
346
  * RATE — 8.5x Flash's. it also fails 2.9% of runs against Flash's 0.0%. best
346
347
  * achievable was 10.9x (cheapest OpenRouter endpoint), so no routing fixes it.
348
+ *
349
+ * DeepSeek Pro was funded and then dropped on 2026-09-11: 88% of OSS spend at
350
+ * $0.3117/run authoritative over 4,795 runs (30d), against Flash's $0.0531 —
351
+ * and DeepSeek's V4.1-Flash release says it beats V4-Pro and phases Pro out.
352
+ * a subsidised Pro pick now runs V4.1 Flash; BYOK and Router Pro are untouched.
353
+ * re-add it only after V4.1-Pro ships AND is priced on a real run.
347
354
  * see wiki/oss-model-allowlist.md.
348
355
  */
349
356
  export declare const OSS_MODEL_ALLOWLIST: readonly string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.77",
3
+ "version": "0.1.78",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {