pullfrog 0.1.85 → 0.1.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -84177,7 +84177,7 @@ var require_Element = __commonJS({
84177
84177
  var FilteredElementList = require_FilteredElementList();
84178
84178
  var DOMException2 = require_DOMException();
84179
84179
  var DOMTokenList = require_DOMTokenList();
84180
- var select3 = require_select();
84180
+ var select2 = require_select();
84181
84181
  var ContainerNode = require_ContainerNode();
84182
84182
  var ChildNode = require_ChildNode();
84183
84183
  var NonDocumentTypeChildNode = require_NonDocumentTypeChildNode();
@@ -84938,7 +84938,7 @@ var require_Element = __commonJS({
84938
84938
  this.className = v;
84939
84939
  } },
84940
84940
  matches: { value: function(selector) {
84941
- return select3.matches(this, selector);
84941
+ return select2.matches(this, selector);
84942
84942
  } },
84943
84943
  closest: { value: function(selector) {
84944
84944
  var el = this;
@@ -84951,10 +84951,10 @@ var require_Element = __commonJS({
84951
84951
  return null;
84952
84952
  } },
84953
84953
  querySelector: { value: function(selector) {
84954
- return select3(selector, this)[0];
84954
+ return select2(selector, this)[0];
84955
84955
  } },
84956
84956
  querySelectorAll: { value: function(selector) {
84957
- var nodes = select3(selector, this);
84957
+ var nodes = select2(selector, this);
84958
84958
  return nodes.item ? nodes : new NodeList(nodes);
84959
84959
  } }
84960
84960
  });
@@ -85482,7 +85482,7 @@ var require_DocumentFragment = __commonJS({
85482
85482
  var NodeList = require_NodeList();
85483
85483
  var ContainerNode = require_ContainerNode();
85484
85484
  var Element = require_Element();
85485
- var select3 = require_select();
85485
+ var select2 = require_select();
85486
85486
  var utils = require_utils8();
85487
85487
  function DocumentFragment(doc) {
85488
85488
  ContainerNode.call(this);
@@ -85511,7 +85511,7 @@ var require_DocumentFragment = __commonJS({
85511
85511
  context.isHTML = true;
85512
85512
  context.getElementsByTagName = Element.prototype.getElementsByTagName;
85513
85513
  context.nextElement = Object.getOwnPropertyDescriptor(Element.prototype, "firstElementChild").get;
85514
- var nodes = select3(selector, context);
85514
+ var nodes = select2(selector, context);
85515
85515
  return nodes.item ? nodes : new NodeList(nodes);
85516
85516
  } },
85517
85517
  // Utility methods
@@ -88626,7 +88626,7 @@ var require_Document = __commonJS({
88626
88626
  var NodeIterator = require_NodeIterator();
88627
88627
  var NodeFilter = require_NodeFilter();
88628
88628
  var URL2 = require_URL();
88629
- var select3 = require_select();
88629
+ var select2 = require_select();
88630
88630
  var events = require_events3();
88631
88631
  var xml = require_xmlnames();
88632
88632
  var html = require_htmlelts();
@@ -89187,10 +89187,10 @@ var require_Document = __commonJS({
89187
89187
  return this._templateDocCache;
89188
89188
  } },
89189
89189
  querySelector: { value: function(selector) {
89190
- return select3(selector, this)[0];
89190
+ return select2(selector, this)[0];
89191
89191
  } },
89192
89192
  querySelectorAll: { value: function(selector) {
89193
- var nodes = select3(selector, this);
89193
+ var nodes = select2(selector, this);
89194
89194
  return nodes.item ? nodes : new NodeList(nodes);
89195
89195
  } }
89196
89196
  });
@@ -107103,7 +107103,7 @@ var import_picocolors = __toESM(require_picocolors(), 1);
107103
107103
  // package.json
107104
107104
  var package_default = {
107105
107105
  name: "pullfrog",
107106
- version: "0.1.85",
107106
+ version: "0.1.87",
107107
107107
  cliContractVersion: "1",
107108
107108
  type: "module",
107109
107109
  bin: {
@@ -107131,7 +107131,7 @@ var package_default = {
107131
107131
  },
107132
107132
  devDependencies: {
107133
107133
  "@actions/core": "^1.11.1",
107134
- "@anthropic-ai/claude-code": "2.1.280",
107134
+ "@anthropic-ai/claude-code": "2.1.284",
107135
107135
  "@ark/fs": "0.56.0",
107136
107136
  "@ark/util": "0.56.0",
107137
107137
  "@clack/prompts": "^1.2.0",
@@ -109181,9 +109181,9 @@ var providers = {
109181
109181
  },
109182
109182
  "claude-sonnet": {
109183
109183
  displayName: "Claude Sonnet",
109184
- resolve: "anthropic/claude-sonnet-5",
109184
+ resolve: "anthropic/claude-sonnet-5-5",
109185
109185
  effort: ["low", "medium", "high", "xhigh", "max"],
109186
- openRouterResolve: "openrouter/anthropic/claude-sonnet-5"
109186
+ openRouterResolve: "openrouter/anthropic/claude-sonnet-5.5"
109187
109187
  },
109188
109188
  "claude-haiku": {
109189
109189
  displayName: "Claude Haiku",
@@ -109600,9 +109600,9 @@ var providers = {
109600
109600
  },
109601
109601
  "claude-sonnet": {
109602
109602
  displayName: "Claude Sonnet",
109603
- resolve: "opencode/claude-sonnet-5",
109603
+ resolve: "opencode/claude-sonnet-5-5",
109604
109604
  effort: ["low", "medium", "high", "xhigh", "max"],
109605
- openRouterResolve: "openrouter/anthropic/claude-sonnet-5"
109605
+ openRouterResolve: "openrouter/anthropic/claude-sonnet-5.5"
109606
109606
  },
109607
109607
  "claude-haiku": {
109608
109608
  displayName: "Claude Haiku",
@@ -110310,8 +110310,8 @@ var providers = {
110310
110310
  },
110311
110311
  "claude-sonnet": {
110312
110312
  displayName: "Claude Sonnet",
110313
- resolve: "vercel/anthropic/claude-sonnet-5",
110314
- effort: ["none", "low", "medium", "high", "xhigh", "max"]
110313
+ resolve: "vercel/anthropic/claude-sonnet-5.5",
110314
+ effort: ["low", "medium", "high", "xhigh", "max"]
110315
110315
  },
110316
110316
  "claude-haiku": {
110317
110317
  displayName: "Claude Haiku",
@@ -112888,7 +112888,7 @@ function buildAgentsJson() {
112888
112888
  [REVIEWER_AGENT_NAME]: {
112889
112889
  description: "Read-only review subagent for lens-based code review (correctness, security, billing-subsystem, etc.). Reads only \u2014 no writes, no state-changing shell or MCP calls, no nested subagent dispatch.",
112890
112890
  prompt: REVIEWER_SYSTEM_PROMPT,
112891
- model: "claude-sonnet-5"
112891
+ model: "claude-sonnet-5-5"
112892
112892
  }
112893
112893
  };
112894
112894
  return JSON.stringify(agents2);
@@ -113518,17 +113518,6 @@ import { join as join6 } from "node:path";
113518
113518
  var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
113519
113519
  var XAI_AUTH_ENV = "GROK_AUTH_JSON";
113520
113520
  var installedSubscriptionPaths = /* @__PURE__ */ new Map();
113521
- function clearInstalledSubscription(name) {
113522
- const path4 = installedSubscriptionPaths.get(name);
113523
- if (!path4 || !existsSync5(path4)) return;
113524
- const value2 = JSON.parse(readFileSync3(path4, "utf8"));
113525
- if (!value2 || typeof value2 !== "object") return;
113526
- if (name === "CODEX_AUTH_JSON" && "openai" in value2) delete value2.openai;
113527
- if (name === "GROK_AUTH_JSON" && "xai" in value2) delete value2.xai;
113528
- writeFileSync5(path4, `${JSON.stringify(value2)}
113529
- `, { mode: 384 });
113530
- installedSubscriptionPaths.delete(name);
113531
- }
113532
113521
  var PULLFROG_DATA_DIR = "/var/lib/pullfrog";
113533
113522
  function isRejectedChain(body) {
113534
113523
  if (!body.refresh_rejected_at) return false;
@@ -113859,8 +113848,8 @@ async function writeBackEntry(apiToken, entry) {
113859
113848
  }
113860
113849
  try {
113861
113850
  const poolState = core2.getState("credential_receipts");
113862
- const receipts2 = external_exports.record(external_exports.string(), external_exports.string()).parse(JSON.parse(poolState || "{}"));
113863
- const receipt = receipts2[entry.secretName];
113851
+ const receipts = external_exports.record(external_exports.string(), external_exports.string()).parse(JSON.parse(poolState || "{}"));
113852
+ const receipt = receipts[entry.secretName];
113864
113853
  if (poolState && !receipt) return;
113865
113854
  const response = await apiFetch({
113866
113855
  path: receipt ? "/api/runtime/credentials" : "/api/runtime/secret",
@@ -198136,304 +198125,6 @@ async function checkConfiguredCredentials(params) {
198136
198125
  return replacement ? { kind: "fellBack", ...outcome, replacement } : { kind: "dead", ...outcome };
198137
198126
  }
198138
198127
 
198139
- // utils/normalizeEnv.ts
198140
- function hasControlCharacter(value2) {
198141
- return [...value2].some((ch) => {
198142
- const code = ch.charCodeAt(0);
198143
- return code < 32 || code === 127;
198144
- });
198145
- }
198146
- function sanitizeSecret(key, value2) {
198147
- const trimmed = value2.trim();
198148
- if (trimmed.length === 0) {
198149
- log2.warning(
198150
- `\xBB ${key} is whitespace-only \u2014 leaving env var unchanged. check your secret value.`
198151
- );
198152
- return null;
198153
- }
198154
- if (key.endsWith("_API_KEY") && hasControlCharacter(trimmed)) {
198155
- log2.warning(
198156
- `\xBB ${key} contains a line break or control character and cannot be sent as an HTTP header \u2014 leaving env var unchanged. re-save the secret as a single line.`
198157
- );
198158
- return null;
198159
- }
198160
- if (trimmed !== value2) {
198161
- log2.warning(
198162
- `\xBB stripped whitespace from ${key} (whitespace in secret values breaks GitHub Actions log masking)`
198163
- );
198164
- }
198165
- maskSecret(trimmed);
198166
- return trimmed;
198167
- }
198168
- function normalizeEnv() {
198169
- const upperKeys = /* @__PURE__ */ new Map();
198170
- for (const key of Object.keys(process.env)) {
198171
- const upper2 = key.toUpperCase();
198172
- const existing = upperKeys.get(upper2) || [];
198173
- existing.push(key);
198174
- upperKeys.set(upper2, existing);
198175
- }
198176
- for (const [upperKey, keys] of upperKeys) {
198177
- if (keys.length === 1) {
198178
- const key = keys[0];
198179
- if (key !== upperKey) {
198180
- process.env[upperKey] = process.env[key];
198181
- delete process.env[key];
198182
- }
198183
- continue;
198184
- }
198185
- const values = keys.map((k2) => process.env[k2]);
198186
- const uniqueValues = new Set(values);
198187
- if (uniqueValues.size > 1) {
198188
- log2.warning(
198189
- `env var conflict: ${keys.join(", ")} have different values. using uppercase ${upperKey}.`
198190
- );
198191
- }
198192
- const preferredKey = keys.find((k2) => k2 === upperKey) || keys[0];
198193
- const preferredValue = process.env[preferredKey];
198194
- for (const key of keys) {
198195
- delete process.env[key];
198196
- }
198197
- process.env[upperKey] = preferredValue;
198198
- }
198199
- for (const key of Object.keys(process.env)) {
198200
- if (!isSensitiveEnvName(key)) continue;
198201
- const value2 = process.env[key];
198202
- if (typeof value2 !== "string" || value2.length === 0) continue;
198203
- const sanitized = sanitizeSecret(key, value2);
198204
- if (sanitized !== null) process.env[key] = sanitized;
198205
- }
198206
- }
198207
-
198208
- // utils/subscriptionProbe.ts
198209
- var identitySchema = external_exports.object({
198210
- email: external_exports.string().email().optional(),
198211
- sub: external_exports.string().optional(),
198212
- user_id: external_exports.string().optional(),
198213
- account_id: external_exports.string().optional(),
198214
- email_verified: external_exports.boolean().optional()
198215
- });
198216
- var codexUsageSchema = external_exports.object({
198217
- rate_limit: external_exports.object({ allowed: external_exports.boolean(), limit_reached: external_exports.boolean() }).optional()
198218
- });
198219
- async function readSubscriptionEndpoint(input) {
198220
- const headers = new Headers({ authorization: `Bearer ${input.token}` });
198221
- if (input.accountId) headers.set("ChatGPT-Account-Id", input.accountId);
198222
- if (input.grokBilling) headers.set("x-xai-token-auth", "xai-grok-cli");
198223
- return fetch(input.url, {
198224
- headers,
198225
- redirect: "error",
198226
- signal: AbortSignal.timeout(1e4)
198227
- }).catch(() => null);
198228
- }
198229
- async function probeSubscription(input) {
198230
- if (input.name === "CLAUDE_CODE_OAUTH_TOKEN") {
198231
- const result = await preflightClaudeSubscription({ token: input.value, model: input.model });
198232
- return result.usable ? "usable" : "rejected";
198233
- }
198234
- const codex2 = input.name === "CODEX_AUTH_JSON" ? parseCodexAuthBody(input.value) : null;
198235
- const grok = input.name === "GROK_AUTH_JSON" ? parseXaiAuthBody(input.value) : null;
198236
- const auth2 = codex2 ?? grok;
198237
- if (!auth2 || auth2.refresh_rejected_at) return "rejected";
198238
- if (grok && input.model)
198239
- return probeInference({
198240
- name: "XAI_API_KEY",
198241
- value: grok.tokens.access_token,
198242
- model: input.model
198243
- });
198244
- const response = await readSubscriptionEndpoint({
198245
- url: codex2 ? "https://chatgpt.com/backend-api/wham/usage" : "https://cli-chat-proxy.grok.com/v1/billing?format=credits",
198246
- token: auth2.tokens.access_token,
198247
- accountId: codex2?.tokens.account_id,
198248
- grokBilling: !!grok
198249
- });
198250
- if (response?.status === 401) return "rejected";
198251
- if (!response?.ok) return "unknown";
198252
- const body = await response.json().catch(() => null);
198253
- if (codex2) {
198254
- const parsed2 = codexUsageSchema.safeParse(body);
198255
- const limit = parsed2.success ? parsed2.data.rate_limit : void 0;
198256
- if (!limit) return "unknown";
198257
- return limit.allowed && !limit.limit_reached ? "usable" : "rejected";
198258
- }
198259
- return "unknown";
198260
- }
198261
- async function probeInference(input) {
198262
- const anthropic = input.name === "ANTHROPIC_API_KEY";
198263
- const openai = input.name === "OPENAI_API_KEY";
198264
- if (!anthropic && !openai && input.name !== "XAI_API_KEY") {
198265
- const result = await verifyCredential({ envVar: input.name, value: input.value });
198266
- return result === "dead" ? "rejected" : result === "alive" ? "usable" : "unknown";
198267
- }
198268
- const headers = new Headers({ "content-type": "application/json" });
198269
- if (anthropic) {
198270
- headers.set("x-api-key", input.value);
198271
- headers.set("anthropic-version", "2023-06-01");
198272
- } else headers.set("authorization", `Bearer ${input.value}`);
198273
- const response = await fetch(
198274
- anthropic ? "https://api.anthropic.com/v1/messages" : openai ? "https://api.openai.com/v1/responses" : "https://api.x.ai/v1/chat/completions",
198275
- {
198276
- method: "POST",
198277
- headers,
198278
- body: JSON.stringify(
198279
- openai ? { model: input.model, input: "Reply OK.", max_output_tokens: 16, store: false } : {
198280
- model: input.model,
198281
- messages: [{ role: "user", content: "Reply OK." }],
198282
- max_tokens: 1
198283
- }
198284
- ),
198285
- redirect: "error",
198286
- signal: AbortSignal.timeout(1e4)
198287
- }
198288
- ).catch(() => null);
198289
- if (response?.status === 400 && input.name === "XAI_API_KEY") {
198290
- const error49 = external_exports.object({ error: external_exports.string() }).safeParse(await response.json().catch(() => null));
198291
- return error49.success && error49.data.error.startsWith("Incorrect API key provided.") ? "rejected" : "unknown";
198292
- }
198293
- await response?.body?.cancel();
198294
- if (!response) return "unknown";
198295
- if (response.ok) return "usable";
198296
- return [401, 402, 403, 429].includes(response.status) ? "rejected" : "unknown";
198297
- }
198298
-
198299
- // utils/credentialPool.ts
198300
- var receipts = {};
198301
- var workflowCredentials = {};
198302
- function saveReceipts() {
198303
- for (const receipt of Object.values(receipts)) maskSecret(receipt);
198304
- saveSecretState("credential_receipts", JSON.stringify(receipts));
198305
- }
198306
- var select2 = op(
198307
- async (input) => {
198308
- const response = await apiFetch({
198309
- path: "/api/runtime/credentials",
198310
- method: "POST",
198311
- headers: {
198312
- authorization: `Bearer ${input.access.token}`,
198313
- "content-type": "application/json"
198314
- },
198315
- body: JSON.stringify({ id: input.candidate.id }),
198316
- signal: AbortSignal.timeout(35e3)
198317
- });
198318
- if (response.status === 404) return null;
198319
- if (!response.ok)
198320
- throw new Error("could not load a configured credential; no fallback was charged", {
198321
- cause: response.status
198322
- });
198323
- return selectedCredentialSchema.parse(await response.json());
198324
- },
198325
- {
198326
- retries: [250, 1e3],
198327
- bail: (error49) => error49 instanceof Error && typeof error49.cause === "number" && error49.cause >= 400 && error49.cause < 500
198328
- }
198329
- );
198330
- function subscriptionForModel(model) {
198331
- if (!model.includes("/")) return null;
198332
- const provider2 = getModelProvider(model);
198333
- return provider2 === "anthropic" ? "CLAUDE_CODE_OAUTH_TOKEN" : provider2 === "openai" ? "CODEX_AUTH_JSON" : provider2 === "xai" ? "GROK_AUTH_JSON" : null;
198334
- }
198335
- async function initializeCredentialPool(ctx, model) {
198336
- const access = ctx.credentialAccess;
198337
- if (!access) return;
198338
- maskSecret(access.token);
198339
- const names = /* @__PURE__ */ new Set([
198340
- ...access.candidates.map((candidate) => candidate.name),
198341
- ...subscriptionNameSchema.options,
198342
- "ANTHROPIC_API_KEY",
198343
- "OPENAI_API_KEY",
198344
- "XAI_API_KEY"
198345
- ]);
198346
- for (const name of names) {
198347
- const value2 = process.env[name];
198348
- if (value2) workflowCredentials[name] = value2;
198349
- }
198350
- for (const name of subscriptionNameSchema.options) {
198351
- if (model && subscriptionForModel(model) !== name) continue;
198352
- if (workflowCredentials[name]) continue;
198353
- const candidate = access.candidates.find((item) => item.name === name);
198354
- if (!candidate) continue;
198355
- const selected = await select2({ access, candidate }).catch(() => {
198356
- log2.warning(`\xBB could not load ${name} for model discovery; selection will retry if needed`);
198357
- return null;
198358
- });
198359
- if (!selected) continue;
198360
- const value2 = sanitizeSecret(name, selected.value);
198361
- if (!value2) continue;
198362
- process.env[name] = value2;
198363
- receipts[name] = selected.receipt;
198364
- }
198365
- saveReceipts();
198366
- }
198367
- function resolvePoolModel(input) {
198368
- const agent2 = resolveAgent({
198369
- model: void 0,
198370
- proxyModel: void 0,
198371
- codexAgent: input.codexAgent
198372
- });
198373
- if (agent2.name === "opencode") return autoSelectModel();
198374
- const provider2 = agent2.name === "claude" ? "anthropic" : "openai";
198375
- return modelAliases.find(
198376
- (alias) => alias.provider === provider2 && alias.preferred && !alias.hidden && !alias.fallback && !alias.routing
198377
- )?.resolve;
198378
- }
198379
- async function selectConfiguredCredential(input) {
198380
- const access = input.ctx.credentialAccess;
198381
- const model = input.model;
198382
- if (!access || !model?.includes("/") || getProviderGatewayUrl(model)) return false;
198383
- const subscription = subscriptionForModel(model);
198384
- const names = getModelEnvVars(model).filter((name) => name !== subscription);
198385
- if (subscription) names.unshift(subscription);
198386
- const candidates = access.candidates.filter((candidate) => names.includes(candidate.name));
198387
- const workflow = names.filter((name) => workflowCredentials[name]);
198388
- if (!candidates.length && !workflow.length) return false;
198389
- for (const name of workflow) {
198390
- const value2 = workflowCredentials[name];
198391
- if (await usable({ name, value: value2, model })) {
198392
- activate({ names, name, value: value2, receipt: void 0 });
198393
- return true;
198394
- }
198395
- }
198396
- for (const candidate of candidates) {
198397
- const selected = await select2({ access, candidate });
198398
- if (!selected) continue;
198399
- if (await usable({ ...selected, model })) {
198400
- activate({ names, ...selected });
198401
- log2.info(`\xBB selected ${candidate.name} from ${candidate.source} scope`);
198402
- return true;
198403
- }
198404
- log2.info(
198405
- `\xBB ${candidate.name} from ${candidate.source} scope unavailable; trying the next credential`
198406
- );
198407
- }
198408
- throw new Error(
198409
- `all configured credentials for ${model} were rejected or exhausted; no other model or provider was selected`
198410
- );
198411
- }
198412
- async function usable(input) {
198413
- const subscription = subscriptionNameSchema.safeParse(input.name);
198414
- if (subscription.success)
198415
- return await probeSubscription({
198416
- name: subscription.data,
198417
- value: input.value,
198418
- model: stripProviderPrefix(input.model)
198419
- }) !== "rejected";
198420
- return await probeInference({ ...input, model: stripProviderPrefix(input.model) }) !== "rejected";
198421
- }
198422
- function activate(input) {
198423
- for (const name of input.names) {
198424
- delete process.env[name];
198425
- delete receipts[name];
198426
- if (name === "CODEX_AUTH_JSON" || name === "GROK_AUTH_JSON") clearInstalledSubscription(name);
198427
- }
198428
- const value2 = sanitizeSecret(input.name, input.value);
198429
- if (!value2) throw new Error("configured credential was empty");
198430
- process.env[input.name] = value2;
198431
- if (input.receipt) receipts[input.name] = input.receipt;
198432
- installCodexAuth();
198433
- installXaiAuth();
198434
- saveReceipts();
198435
- }
198436
-
198437
198128
  // utils/gitAuthServer.ts
198438
198129
  import { randomUUID as randomUUID5 } from "node:crypto";
198439
198130
  import { writeFileSync as writeFileSync15 } from "node:fs";
@@ -199137,6 +198828,75 @@ function buildModelAccessError(input) {
199137
198828
  return [headline, "", why, "", cta].join("\n");
199138
198829
  }
199139
198830
 
198831
+ // utils/normalizeEnv.ts
198832
+ function hasControlCharacter(value2) {
198833
+ return [...value2].some((ch) => {
198834
+ const code = ch.charCodeAt(0);
198835
+ return code < 32 || code === 127;
198836
+ });
198837
+ }
198838
+ function sanitizeSecret(key, value2) {
198839
+ const trimmed = value2.trim();
198840
+ if (trimmed.length === 0) {
198841
+ log2.warning(
198842
+ `\xBB ${key} is whitespace-only \u2014 leaving env var unchanged. check your secret value.`
198843
+ );
198844
+ return null;
198845
+ }
198846
+ if (key.endsWith("_API_KEY") && hasControlCharacter(trimmed)) {
198847
+ log2.warning(
198848
+ `\xBB ${key} contains a line break or control character and cannot be sent as an HTTP header \u2014 leaving env var unchanged. re-save the secret as a single line.`
198849
+ );
198850
+ return null;
198851
+ }
198852
+ if (trimmed !== value2) {
198853
+ log2.warning(
198854
+ `\xBB stripped whitespace from ${key} (whitespace in secret values breaks GitHub Actions log masking)`
198855
+ );
198856
+ }
198857
+ maskSecret(trimmed);
198858
+ return trimmed;
198859
+ }
198860
+ function normalizeEnv() {
198861
+ const upperKeys = /* @__PURE__ */ new Map();
198862
+ for (const key of Object.keys(process.env)) {
198863
+ const upper2 = key.toUpperCase();
198864
+ const existing = upperKeys.get(upper2) || [];
198865
+ existing.push(key);
198866
+ upperKeys.set(upper2, existing);
198867
+ }
198868
+ for (const [upperKey, keys] of upperKeys) {
198869
+ if (keys.length === 1) {
198870
+ const key = keys[0];
198871
+ if (key !== upperKey) {
198872
+ process.env[upperKey] = process.env[key];
198873
+ delete process.env[key];
198874
+ }
198875
+ continue;
198876
+ }
198877
+ const values = keys.map((k2) => process.env[k2]);
198878
+ const uniqueValues = new Set(values);
198879
+ if (uniqueValues.size > 1) {
198880
+ log2.warning(
198881
+ `env var conflict: ${keys.join(", ")} have different values. using uppercase ${upperKey}.`
198882
+ );
198883
+ }
198884
+ const preferredKey = keys.find((k2) => k2 === upperKey) || keys[0];
198885
+ const preferredValue = process.env[preferredKey];
198886
+ for (const key of keys) {
198887
+ delete process.env[key];
198888
+ }
198889
+ process.env[upperKey] = preferredValue;
198890
+ }
198891
+ for (const key of Object.keys(process.env)) {
198892
+ if (!isSensitiveEnvName(key)) continue;
198893
+ const value2 = process.env[key];
198894
+ if (typeof value2 !== "string" || value2.length === 0) continue;
198895
+ const sanitized = sanitizeSecret(key, value2);
198896
+ if (sanitized !== null) process.env[key] = sanitized;
198897
+ }
198898
+ }
198899
+
199140
198900
  // utils/overrides.ts
199141
198901
  var DENIED_OVERRIDE_NAMES = /* @__PURE__ */ new Set([
199142
198902
  "GITHUB_TOKEN",
@@ -200091,8 +199851,7 @@ async function fetchRunContext(params) {
200091
199851
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
200092
199852
  try {
200093
199853
  const headers = {
200094
- Authorization: `Bearer ${params.token}`,
200095
- "X-Pullfrog-Credential-Pools": "1"
199854
+ Authorization: `Bearer ${params.token}`
200096
199855
  };
200097
199856
  if (params.oidcToken) {
200098
199857
  headers["X-GitHub-OIDC-Token"] = params.oidcToken;
@@ -201362,7 +201121,6 @@ async function main() {
201362
201121
  const preIntrospectionDirty = repoDir ? await dirtyTrackedPaths({ cwd: repoDir }) : null;
201363
201122
  const opencodeCliPath = await agents.opencode.install();
201364
201123
  captureBaselineModels(opencodeCliPath);
201365
- await initializeCredentialPool(runContext, resolveModel({ slug: payload.model }));
201366
201124
  if (runContext.dbSecrets) {
201367
201125
  for (const [key, value2] of Object.entries(runContext.dbSecrets)) {
201368
201126
  if (!process.env[key]) {
@@ -201446,27 +201204,14 @@ async function main() {
201446
201204
  }
201447
201205
  const gitAuthServer = __using(_stack2, await startGitAuthServer(tmpdir4), true);
201448
201206
  setGitAuthServer(gitAuthServer);
201449
- let configuredModel = resolveModel({ slug: payload.model });
201450
- if (!configuredModel && !payload.proxyModel && runContext.credentialAccess?.candidates.length) {
201451
- configuredModel = resolvePoolModel({
201452
- codexAgent: runContext.repoSettings.codexAgent || payload.codexArm === true
201453
- });
201454
- }
201455
- let poolSelected = !payload.proxyModel && await selectConfiguredCredential({
201456
- ctx: runContext,
201457
- model: configuredModel
201458
- });
201459
201207
  const access = decideModelAccess({
201460
201208
  modelExplicit: payload.modelExplicit ?? false,
201461
201209
  model: payload.model,
201462
201210
  oss: runContext.oss,
201463
201211
  proxyActive: !!payload.proxyModel,
201464
201212
  subsidyTarget: runContext.proxyModel,
201465
- resolvedModel: configuredModel,
201466
- authorized: /* @__PURE__ */ new Set([
201467
- ...getAuthorizedModels(),
201468
- ...poolSelected && configuredModel ? [configuredModel] : []
201469
- ])
201213
+ resolvedModel: resolveModel({ slug: payload.model }),
201214
+ authorized: getAuthorizedModels()
201470
201215
  });
201471
201216
  if (access.kind === "error") {
201472
201217
  throw new Error(
@@ -201479,25 +201224,12 @@ async function main() {
201479
201224
  );
201480
201225
  }
201481
201226
  if (access.kind === "proxy") payload.proxyModel = access.target;
201482
- if (access.kind === "byok") {
201483
- payload.proxyModel = void 0;
201484
- if (!poolSelected)
201485
- poolSelected = await selectConfiguredCredential({
201486
- ctx: runContext,
201487
- model: configuredModel
201488
- });
201489
- }
201490
- if (poolSelected) {
201491
- const before = repoDir ? await dirtyTrackedPaths({ cwd: repoDir }) : null;
201492
- captureAuthorizedModels(opencodeCliPath);
201493
- if (before && repoDir)
201494
- await restoreDirtiedSince({ before, actor: "model introspection", cwd: repoDir });
201495
- }
201227
+ if (access.kind === "byok") payload.proxyModel = void 0;
201496
201228
  if (runContext.oss && payload.proxyModel) {
201497
201229
  payload.effort = ossEffortFloor({ payload });
201498
201230
  }
201499
- if (payload.proxyModel) configuredModel = void 0;
201500
- const credentials = payload.proxyModel || poolSelected ? { kind: "ok" } : await checkConfiguredCredentials({
201231
+ const configuredModel = payload.proxyModel ? void 0 : resolveModel({ slug: payload.model });
201232
+ const credentials = payload.proxyModel ? { kind: "ok" } : await checkConfiguredCredentials({
201501
201233
  model: configuredModel,
201502
201234
  authorized: getAuthorizedModels()
201503
201235
  });
@@ -201828,12 +201560,12 @@ ${instructions.user}` : null,
201828
201560
  if (payload.timeout === TIMEOUT_DISABLED) {
201829
201561
  result = await Promise.race([agentPromise, activityTimeout.promise]);
201830
201562
  } else {
201831
- const usable2 = resolveTimeoutMs(payload.timeout);
201832
- if (payload.timeout && usable2 === null) {
201563
+ const usable = resolveTimeoutMs(payload.timeout);
201564
+ if (payload.timeout && usable === null) {
201833
201565
  log2.warning(`invalid timeout "${payload.timeout}" (use --notimeout to disable), using 1h`);
201834
201566
  }
201835
- const timeoutMs = usable2 ?? 36e5;
201836
- const actualTimeout = usable2 !== null ? payload.timeout : "1h";
201567
+ const timeoutMs = usable ?? 36e5;
201568
+ const actualTimeout = usable !== null ? payload.timeout : "1h";
201837
201569
  let timeoutId;
201838
201570
  const timeoutPromise = new Promise((_4, reject) => {
201839
201571
  timeoutId = setTimeout(() => {
@@ -202461,7 +202193,7 @@ function resolveTarget2(repo) {
202461
202193
  return { owner: match3[1], repo: match3[2] };
202462
202194
  }
202463
202195
  function cliVersion() {
202464
- const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.85");
202196
+ const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec("0.1.87");
202465
202197
  if (!parts) return "0.0.0";
202466
202198
  return `${Number(parts[1])}.${Number(parts[2])}.${Number(parts[3])}`;
202467
202199
  }
@@ -202628,7 +202360,7 @@ async function runCli8(input) {
202628
202360
  }
202629
202361
 
202630
202362
  // cli.ts
202631
- var VERSION10 = "0.1.85";
202363
+ var VERSION10 = "0.1.87";
202632
202364
  var bin = basename2(process.argv[1] || "");
202633
202365
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
202634
202366
  var rawArgs = process.argv.slice(2);