pullfrog 0.1.61 → 0.1.62

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
@@ -107293,6 +107293,9 @@ function isProviderNoRoutableEndpoints(text) {
107293
107293
  function isOpenRouterKeyLimitExceeded(text) {
107294
107294
  return /Key limit exceeded \(total limit\)/i.test(text) || /openrouter\.ai\/[^\s"')]*\/keys\//i.test(text);
107295
107295
  }
107296
+ function isProviderMissingCredential(text) {
107297
+ return /API key is missing\. Pass it using the/i.test(text) || /Missing Authentication header/i.test(text);
107298
+ }
107296
107299
  function isTransientUpstreamError(text) {
107297
107300
  return /API Error:\s*5\d\d/i.test(text) || /\bOverloaded\b/.test(text) || /"error_type"\s*:\s*"(?:provider_unavailable|timeout)"/i.test(text) || /Streaming response failed:\s*\[5\d\d\]/i.test(text);
107298
107301
  }
@@ -107355,7 +107358,7 @@ var import_semver = __toESM(require_semver2(), 1);
107355
107358
  // package.json
107356
107359
  var package_default = {
107357
107360
  name: "pullfrog",
107358
- version: "0.1.61",
107361
+ version: "0.1.62",
107359
107362
  type: "module",
107360
107363
  bin: {
107361
107364
  pullfrog: "dist/cli.mjs",
@@ -108446,7 +108449,6 @@ function getUnsubmittedReview(toolState, expectsReviewOutput2 = toolState.hadPro
108446
108449
  }
108447
108450
  function expectsReviewOutput(ctx) {
108448
108451
  if (ctx.toolState.hadProgressComment) return true;
108449
- if (ctx.payload.progressComments) return false;
108450
108452
  return ctx.payload.event.silent !== true && ctx.payload.event.issue_number !== void 0;
108451
108453
  }
108452
108454
  function buildStopHookPrompt(failure2) {
@@ -108661,6 +108663,7 @@ async function runPostRunRetryLoop(params) {
108661
108663
  result = preResume;
108662
108664
  break;
108663
108665
  }
108666
+ if (onlySummaryStale) result = { ...result, output: preResume.output || result.output };
108664
108667
  gateResumeCount++;
108665
108668
  }
108666
108669
  if (gateResumeCount > 0 && result.success && hasPostRunIssues(finalIssues)) {
@@ -116005,24 +116008,23 @@ async function installOpencodeCli(params) {
116005
116008
  var AUTO_SELECT_WARNING = "select a model explicitly in the Pullfrog console (https://pullfrog.com/console) to avoid this \u2014 if the picker is locked, this run had no Pullfrog Router funding: add a card or top up your credit.";
116006
116009
  function autoSelectModel() {
116007
116010
  const authorized2 = getAuthorizedModels();
116008
- if (authorized2.size > 0) {
116009
- const servable = (a2) => {
116010
- if (!authorized2.has(a2.resolve)) return false;
116011
- const envVars = getModelEnvVars(a2.resolve);
116012
- return envVars.length === 0 || envVars.some((name) => process.env[name]);
116013
- };
116014
- const match3 = modelAliases.find((a2) => !a2.hidden && !a2.fallback && a2.preferred && servable(a2)) ?? modelAliases.find((a2) => !a2.hidden && !a2.fallback && servable(a2));
116015
- if (match3) {
116016
- log2.info(
116017
- `\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
116018
- );
116019
- log2.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
116020
- return match3.resolve;
116021
- }
116011
+ const selectable = modelAliases.filter((a2) => !a2.hidden && !a2.fallback && !a2.routing);
116012
+ const servable = selectable.filter((a2) => {
116013
+ const envVars = getModelEnvVars(a2.resolve);
116014
+ return envVars.length === 0 || envVars.some((name) => process.env[name]);
116015
+ });
116016
+ const pick4 = (list) => list.find((a2) => a2.preferred) ?? list[0];
116017
+ const match3 = pick4(servable.filter((a2) => authorized2.has(a2.resolve))) ?? pick4(servable);
116018
+ if (match3) {
116022
116019
  log2.info(
116023
- `\xBB opencode has ${authorized2.size} models but none match curated aliases \u2014 letting OpenCode auto-select`
116020
+ `\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
116024
116021
  );
116022
+ log2.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
116023
+ return match3.resolve;
116025
116024
  }
116025
+ log2.info(
116026
+ `\xBB opencode has ${authorized2.size} models but none match curated aliases and none hold a credential \u2014 letting OpenCode auto-select: ${[...authorized2].join(", ")}`
116027
+ );
116026
116028
  log2.warning(`\xBB no model resolved. letting OpenCode auto-select. ${AUTO_SELECT_WARNING}`);
116027
116029
  return void 0;
116028
116030
  }
@@ -188634,8 +188636,8 @@ function validatePushDestination(repoState, branch, cwd) {
188634
188636
  throw new Error(
188635
188637
  `Push blocked: destination does not match expected repository.
188636
188638
  Expected: ${pushUrl}
188637
- Actual: ${dest.url}
188638
- Git configuration may have been tampered with.`
188639
+ Actual: remote '${dest.remoteName}' -> ${dest.url}
188640
+ Git configuration may have been tampered with, or a url.*.insteadOf rewrite is in effect.`
188639
188641
  );
188640
188642
  }
188641
188643
  return dest;
@@ -190757,6 +190759,9 @@ async function configureRepoGit(params) {
190757
190759
  removeIncludeIfEntries(repoDir);
190758
190760
  const originUrl = `https://github.com/${params.owner}/${params.name}.git`;
190759
190761
  $("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
190762
+ $("git", ["config", "--local", "--replace-all", "remote.origin.pushurl", originUrl], {
190763
+ cwd: repoDir
190764
+ });
190760
190765
  repoState.pushUrl = originUrl;
190761
190766
  $("git", ["config", "--local", "credential.helper", ""], { cwd: repoDir });
190762
190767
  repoState.initialHead = captureInitialHead(repoDir);
@@ -191095,6 +191100,9 @@ async function checkoutPrBranch(pr, params) {
191095
191100
  $("git", ["remote", "set-url", remoteName, forkUrl], { log: false });
191096
191101
  log2.debug(`\xBB updated remote '${remoteName}' for fork ${pr.headRepoFullName}`);
191097
191102
  }
191103
+ $("git", ["config", "--local", "--replace-all", `remote.${remoteName}.pushurl`, forkUrl], {
191104
+ log: false
191105
+ });
191098
191106
  $("git", ["config", `branch.${localBranch}.pushRemote`, remoteName], { log: false });
191099
191107
  $("git", ["config", `branch.${localBranch}.merge`, `refs/heads/${pr.headRef}`], { log: false });
191100
191108
  log2.debug(`\xBB configured branch '${localBranch}' to push to '${remoteName}/${pr.headRef}'`);
@@ -196916,7 +196924,7 @@ async function handleAgentResult(ctx) {
196916
196924
  const mode = toolState.selectedMode;
196917
196925
  const isReviewMode = mode === "Review" || mode === "IncrementalReview";
196918
196926
  const payload = ctx.toolContext.payload;
196919
- const hasCommentTarget = toolState.hadProgressComment || !payload.progressComments && payload.event.issue_number !== void 0;
196927
+ const hasCommentTarget = toolState.hadProgressComment || payload.event.issue_number !== void 0;
196920
196928
  if (!isReviewMode && !toolState.wasUpdated && hasCommentTarget && !ctx.silent) {
196921
196929
  const tracker = toolState.todoTracker;
196922
196930
  if (tracker) {
@@ -197350,6 +197358,19 @@ ${input.errorMessage}
197350
197358
  \`\`\``
197351
197359
  ].join("\n");
197352
197360
  }
197361
+ function formatProviderMissingCredential(input) {
197362
+ return [
197363
+ "**No credential reached the model provider.**",
197364
+ "",
197365
+ "The run started without a key for the provider it ended up using, so the request was refused before any model work happened. Nothing was billed, and no key of yours was rejected \u2014 add a provider key, or pick a model you already have one for.",
197366
+ "",
197367
+ `[Configure model \u2192](${getApiUrl()}/console/${input.owner}/${input.name})`,
197368
+ "",
197369
+ `\`\`\`
197370
+ ${input.errorMessage}
197371
+ \`\`\``
197372
+ ].join("\n");
197373
+ }
197353
197374
  function formatProviderModelNotFoundSummary(input) {
197354
197375
  return `The configured model is no longer available in OpenCode's catalog. Pick a different model in the Pullfrog console for \`${input.owner}/${input.name}\`, or contact support if this persists.
197355
197376
 
@@ -197395,6 +197416,16 @@ ${body}`, comment: body };
197395
197416
  });
197396
197417
  return { summary: `### \u274C Pullfrog failed
197397
197418
 
197419
+ ${body}`, comment: body };
197420
+ }
197421
+ if (isProviderMissingCredential(input.errorMessage)) {
197422
+ const body = formatProviderMissingCredential({
197423
+ owner: input.repo.owner,
197424
+ name: input.repo.name,
197425
+ errorMessage: input.errorMessage
197426
+ });
197427
+ return { summary: `### \u274C Pullfrog failed
197428
+
197398
197429
  ${body}`, comment: body };
197399
197430
  }
197400
197431
  const apiKeySource = hangBody ?? input.errorMessage;
@@ -199234,7 +199265,7 @@ async function runCli4(input) {
199234
199265
  }
199235
199266
 
199236
199267
  // cli.ts
199237
- var VERSION10 = "0.1.61";
199268
+ var VERSION10 = "0.1.62";
199238
199269
  var bin = basename2(process.argv[1] || "");
199239
199270
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
199240
199271
  var rawArgs = process.argv.slice(2);
package/dist/index.js CHANGED
@@ -105126,6 +105126,9 @@ function isProviderNoRoutableEndpoints(text) {
105126
105126
  function isOpenRouterKeyLimitExceeded(text) {
105127
105127
  return /Key limit exceeded \(total limit\)/i.test(text) || /openrouter\.ai\/[^\s"')]*\/keys\//i.test(text);
105128
105128
  }
105129
+ function isProviderMissingCredential(text) {
105130
+ return /API key is missing\. Pass it using the/i.test(text) || /Missing Authentication header/i.test(text);
105131
+ }
105129
105132
  function isTransientUpstreamError(text) {
105130
105133
  return /API Error:\s*5\d\d/i.test(text) || /\bOverloaded\b/.test(text) || /"error_type"\s*:\s*"(?:provider_unavailable|timeout)"/i.test(text) || /Streaming response failed:\s*\[5\d\d\]/i.test(text);
105131
105134
  }
@@ -105188,7 +105191,7 @@ var import_semver = __toESM(require_semver2(), 1);
105188
105191
  // package.json
105189
105192
  var package_default = {
105190
105193
  name: "pullfrog",
105191
- version: "0.1.61",
105194
+ version: "0.1.62",
105192
105195
  type: "module",
105193
105196
  bin: {
105194
105197
  pullfrog: "dist/cli.mjs",
@@ -106279,7 +106282,6 @@ function getUnsubmittedReview(toolState, expectsReviewOutput2 = toolState.hadPro
106279
106282
  }
106280
106283
  function expectsReviewOutput(ctx) {
106281
106284
  if (ctx.toolState.hadProgressComment) return true;
106282
- if (ctx.payload.progressComments) return false;
106283
106285
  return ctx.payload.event.silent !== true && ctx.payload.event.issue_number !== void 0;
106284
106286
  }
106285
106287
  function buildStopHookPrompt(failure2) {
@@ -106494,6 +106496,7 @@ async function runPostRunRetryLoop(params) {
106494
106496
  result = preResume;
106495
106497
  break;
106496
106498
  }
106499
+ if (onlySummaryStale) result = { ...result, output: preResume.output || result.output };
106497
106500
  gateResumeCount++;
106498
106501
  }
106499
106502
  if (gateResumeCount > 0 && result.success && hasPostRunIssues(finalIssues)) {
@@ -113885,24 +113888,23 @@ async function installOpencodeCli(params) {
113885
113888
  var AUTO_SELECT_WARNING = "select a model explicitly in the Pullfrog console (https://pullfrog.com/console) to avoid this \u2014 if the picker is locked, this run had no Pullfrog Router funding: add a card or top up your credit.";
113886
113889
  function autoSelectModel() {
113887
113890
  const authorized2 = getAuthorizedModels();
113888
- if (authorized2.size > 0) {
113889
- const servable = (a) => {
113890
- if (!authorized2.has(a.resolve)) return false;
113891
- const envVars = getModelEnvVars(a.resolve);
113892
- return envVars.length === 0 || envVars.some((name) => process.env[name]);
113893
- };
113894
- const match3 = modelAliases.find((a) => !a.hidden && !a.fallback && a.preferred && servable(a)) ?? modelAliases.find((a) => !a.hidden && !a.fallback && servable(a));
113895
- if (match3) {
113896
- log.info(
113897
- `\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
113898
- );
113899
- log.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
113900
- return match3.resolve;
113901
- }
113891
+ const selectable = modelAliases.filter((a) => !a.hidden && !a.fallback && !a.routing);
113892
+ const servable = selectable.filter((a) => {
113893
+ const envVars = getModelEnvVars(a.resolve);
113894
+ return envVars.length === 0 || envVars.some((name) => process.env[name]);
113895
+ });
113896
+ const pick4 = (list) => list.find((a) => a.preferred) ?? list[0];
113897
+ const match3 = pick4(servable.filter((a) => authorized2.has(a.resolve))) ?? pick4(servable);
113898
+ if (match3) {
113902
113899
  log.info(
113903
- `\xBB opencode has ${authorized2.size} models but none match curated aliases \u2014 letting OpenCode auto-select`
113900
+ `\xBB model: ${match3.resolve} (auto-selected${match3.preferred ? " \u2014 preferred" : ""} curated match)`
113904
113901
  );
113902
+ log.warning(`\xBB model auto-selected. ${AUTO_SELECT_WARNING}`);
113903
+ return match3.resolve;
113905
113904
  }
113905
+ log.info(
113906
+ `\xBB opencode has ${authorized2.size} models but none match curated aliases and none hold a credential \u2014 letting OpenCode auto-select: ${[...authorized2].join(", ")}`
113907
+ );
113906
113908
  log.warning(`\xBB no model resolved. letting OpenCode auto-select. ${AUTO_SELECT_WARNING}`);
113907
113909
  return void 0;
113908
113910
  }
@@ -186514,8 +186516,8 @@ function validatePushDestination(repoState, branch, cwd) {
186514
186516
  throw new Error(
186515
186517
  `Push blocked: destination does not match expected repository.
186516
186518
  Expected: ${pushUrl}
186517
- Actual: ${dest.url}
186518
- Git configuration may have been tampered with.`
186519
+ Actual: remote '${dest.remoteName}' -> ${dest.url}
186520
+ Git configuration may have been tampered with, or a url.*.insteadOf rewrite is in effect.`
186519
186521
  );
186520
186522
  }
186521
186523
  return dest;
@@ -188637,6 +188639,9 @@ async function configureRepoGit(params) {
188637
188639
  removeIncludeIfEntries(repoDir);
188638
188640
  const originUrl = `https://github.com/${params.owner}/${params.name}.git`;
188639
188641
  $("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
188642
+ $("git", ["config", "--local", "--replace-all", "remote.origin.pushurl", originUrl], {
188643
+ cwd: repoDir
188644
+ });
188640
188645
  repoState.pushUrl = originUrl;
188641
188646
  $("git", ["config", "--local", "credential.helper", ""], { cwd: repoDir });
188642
188647
  repoState.initialHead = captureInitialHead(repoDir);
@@ -188975,6 +188980,9 @@ async function checkoutPrBranch(pr, params) {
188975
188980
  $("git", ["remote", "set-url", remoteName, forkUrl], { log: false });
188976
188981
  log.debug(`\xBB updated remote '${remoteName}' for fork ${pr.headRepoFullName}`);
188977
188982
  }
188983
+ $("git", ["config", "--local", "--replace-all", `remote.${remoteName}.pushurl`, forkUrl], {
188984
+ log: false
188985
+ });
188978
188986
  $("git", ["config", `branch.${localBranch}.pushRemote`, remoteName], { log: false });
188979
188987
  $("git", ["config", `branch.${localBranch}.merge`, `refs/heads/${pr.headRef}`], { log: false });
188980
188988
  log.debug(`\xBB configured branch '${localBranch}' to push to '${remoteName}/${pr.headRef}'`);
@@ -194796,7 +194804,7 @@ async function handleAgentResult(ctx) {
194796
194804
  const mode = toolState.selectedMode;
194797
194805
  const isReviewMode = mode === "Review" || mode === "IncrementalReview";
194798
194806
  const payload = ctx.toolContext.payload;
194799
- const hasCommentTarget = toolState.hadProgressComment || !payload.progressComments && payload.event.issue_number !== void 0;
194807
+ const hasCommentTarget = toolState.hadProgressComment || payload.event.issue_number !== void 0;
194800
194808
  if (!isReviewMode && !toolState.wasUpdated && hasCommentTarget && !ctx.silent) {
194801
194809
  const tracker = toolState.todoTracker;
194802
194810
  if (tracker) {
@@ -195230,6 +195238,19 @@ ${input.errorMessage}
195230
195238
  \`\`\``
195231
195239
  ].join("\n");
195232
195240
  }
195241
+ function formatProviderMissingCredential(input) {
195242
+ return [
195243
+ "**No credential reached the model provider.**",
195244
+ "",
195245
+ "The run started without a key for the provider it ended up using, so the request was refused before any model work happened. Nothing was billed, and no key of yours was rejected \u2014 add a provider key, or pick a model you already have one for.",
195246
+ "",
195247
+ `[Configure model \u2192](${getApiUrl()}/console/${input.owner}/${input.name})`,
195248
+ "",
195249
+ `\`\`\`
195250
+ ${input.errorMessage}
195251
+ \`\`\``
195252
+ ].join("\n");
195253
+ }
195233
195254
  function formatProviderModelNotFoundSummary(input) {
195234
195255
  return `The configured model is no longer available in OpenCode's catalog. Pick a different model in the Pullfrog console for \`${input.owner}/${input.name}\`, or contact support if this persists.
195235
195256
 
@@ -195275,6 +195296,16 @@ ${body}`, comment: body };
195275
195296
  });
195276
195297
  return { summary: `### \u274C Pullfrog failed
195277
195298
 
195299
+ ${body}`, comment: body };
195300
+ }
195301
+ if (isProviderMissingCredential(input.errorMessage)) {
195302
+ const body = formatProviderMissingCredential({
195303
+ owner: input.repo.owner,
195304
+ name: input.repo.name,
195305
+ errorMessage: input.errorMessage
195306
+ });
195307
+ return { summary: `### \u274C Pullfrog failed
195308
+
195278
195309
  ${body}`, comment: body };
195279
195310
  }
195280
195311
  const apiKeySource = hangBody ?? input.errorMessage;
@@ -50,6 +50,12 @@ export declare function isProviderNoRoutableEndpoints(text: string): boolean;
50
50
  * …/settings/credits`) carries no `/keys/` path and correctly stays out.
51
51
  */
52
52
  export declare function isOpenRouterKeyLimitExceeded(text: string): boolean;
53
+ /**
54
+ * the provider was reached with NO credential at all — the AI SDK's shared `loadApiKey`
55
+ * refusal, so it is provider-agnostic. NOT `isApiKeyAuthError`, which is a key we hold
56
+ * being rejected: "rotate your key" names a credential that does not exist here.
57
+ */
58
+ export declare function isProviderMissingCredential(text: string): boolean;
53
59
  /**
54
60
  * The upstream is having a moment: Anthropic's `API Error: 529 Overloaded`,
55
61
  * OpenRouter's `provider_unavailable` / `timeout`, OpenCode Zen's `Streaming
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.61",
3
+ "version": "0.1.62",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "pullfrog": "dist/cli.mjs",