pullfrog 0.1.100 → 0.1.101

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.
@@ -6,7 +6,7 @@ export { CLI_CONTRACT_HEADER, CLI_CONTRACT_VERSION, CLI_UPGRADE_MESSAGE } from "
6
6
  export type { ConfigField, ConfigScope, ConfigValue } from "../configuration.ts";
7
7
  export { configEntrySchema, configFields, configResponseSchema, configValueSchema, } from "../configuration.ts";
8
8
  export type { AuthorPermission, AutoTier, EffortPosition, ModelAlias, ModelProvider, Payload, PayloadEvent, PayloadRouting, ProviderConfig, PushPermission, RouterSource, RouterTier, ShellPermission, ToolPermission, WriteablePayload, XrepoConfig, } from "../external.ts";
9
- export { AUTO_EFFICIENT, AUTO_INTELLIGENT, AUTO_ROUTER, autoLadder, autoRoutedSlug, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoRouted, isAutoSlug, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, isRouterTier, ladderRungs, modelAliases, modelHasStoredAuth, modelIdLabel, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, ossFundedModelNames, PROVIDER_GATEWAY_URL_ENV, parseEffortPosition, parseModel, providers, pullfrogMcpName, ROUTED_PROVIDERS, ROUTER_LADDER, ROUTER_TIERS, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolvePickModel, resolveRoutedModel, resolveRung, routerProxyOptOut, rungLabel, rungPosition, SUBSIDY_RUNG, } from "../external.ts";
9
+ export { AUTO_EFFICIENT, AUTO_INTELLIGENT, AUTO_ROUTER, autoLadder, autoRoutedSlug, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoRouted, isAutoSlug, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, isRouterTier, ladderRungs, modelAliases, modelHasStoredAuth, modelIdLabel, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, ossFundedModelNames, PROVIDER_GATEWAY_URL_ENV, parseEffortPosition, parseModel, providers, pullfrogMcpName, ROUTED_PROVIDERS, ROUTER_LADDER, ROUTER_TIERS, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolvePickModel, resolveRoutedModel, resolveRung, routerProxyOptOut, rungLabel, rungPosition, SUBSIDY_RUNG, TRIAL_FUNDED_USD_LIMIT, } from "../external.ts";
10
10
  export type { Mode } from "../modes.ts";
11
11
  export { modes } from "../modes.ts";
12
12
  export { type CommercialRefusal, commercialPaywallBody } from "../utils/billingErrors.ts";
@@ -16,9 +16,10 @@ export type { CodexAuthBody } from "../utils/codexOAuth.ts";
16
16
  export { decodeJwtExpMs, OAuthInvalidGrantError, parseCodexAuthBody, refreshCodexAuthBody, stringifyCodexAuthBody, } from "../utils/codexOAuth.ts";
17
17
  export type { CredentialVerdict } from "../utils/credentialCheck.ts";
18
18
  export { isCredentialProbeable, verifyCredential } from "../utils/credentialCheck.ts";
19
+ export { renderFailure } from "../utils/failureBody.ts";
19
20
  export type { ResourceUsage, UsageSummary } from "../utils/github.ts";
20
21
  export { isPullfrog } from "../utils/isPullfrog.ts";
21
- export { isLeapingIntoActionCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../utils/leapingComment.ts";
22
+ export { isLeapingIntoActionCommentBody, isLiveChecklistCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../utils/leapingComment.ts";
22
23
  export { MAX_LEARNINGS_LENGTH, truncateAtLineBoundary } from "../utils/learningsTruncate.ts";
23
24
  export { countOutstandingPullfrogThreads } from "../utils/outstandingThreads.ts";
24
25
  export type { CreateProgressCommentTarget, ProgressComment, ProgressCommentType, } from "../utils/progressComment.ts";
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.100",
11
+ version: "0.1.101",
12
12
  cliContractVersion: "1",
13
13
  type: "module",
14
14
  bin: {
@@ -15866,6 +15866,13 @@ if (!defaultProxyAlias?.openRouterResolve) {
15866
15866
  }
15867
15867
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
15868
15868
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
15869
+ var trialProxyAlias = resolveDisplayAlias("openai/gpt-luna");
15870
+ if (!trialProxyAlias?.openRouterResolve) {
15871
+ throw new Error("TRIAL_PROXY_MODEL: openai/gpt-luna has no openRouterResolve");
15872
+ }
15873
+ var TRIAL_PROXY_MODEL = trialProxyAlias.openRouterResolve;
15874
+ var TRIAL_PROXY_DISPLAY_NAME = trialProxyAlias.displayName;
15875
+ var TRIAL_FUNDED_USD_LIMIT = 10;
15869
15876
  for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTER_LADDER })) {
15870
15877
  const terminal = /* @__PURE__ */ new Set();
15871
15878
  for (const slug of Object.values(ladder)) {
@@ -16307,6 +16314,36 @@ ${PR_SUMMARY_FORMAT}`
16307
16314
  }
16308
16315
  var modes = computeModes("opencode");
16309
16316
 
16317
+ // utils/failureBody.ts
16318
+ function renderFailure(params) {
16319
+ const blocks = [
16320
+ params.detail ? `**${params.headline}** ${params.detail}` : `**${params.headline}**`
16321
+ ];
16322
+ if (params.list) blocks.push(params.list.map((item) => `- ${item}`).join("\n"));
16323
+ if (params.error) blocks.push(fenced(params.error));
16324
+ if (params.details) {
16325
+ blocks.push(
16326
+ `<details><summary>${params.details.summary}</summary>
16327
+
16328
+ ${fenced(params.details.text)}
16329
+
16330
+ </details>`
16331
+ );
16332
+ }
16333
+ if (params.links?.length) {
16334
+ blocks.push(params.links.map((link) => `[${link.label} \u2192](${link.url})`).join(" \xB7 "));
16335
+ }
16336
+ return blocks.join("\n\n");
16337
+ }
16338
+ function fenced(text) {
16339
+ let longest = 0;
16340
+ for (const match of text.matchAll(/`+/g)) longest = Math.max(longest, match[0].length);
16341
+ const fence = "`".repeat(Math.max(3, longest + 1));
16342
+ return `${fence}
16343
+ ${text}
16344
+ ${fence}`;
16345
+ }
16346
+
16310
16347
  // utils/billingErrors.ts
16311
16348
  function commercialPaywallBody(params) {
16312
16349
  let action;
@@ -16348,7 +16385,7 @@ function formatModelLabel(params) {
16348
16385
  }
16349
16386
  const base = alias?.isFree ? `\`${modelName}\` (free)` : `\`${modelName}\``;
16350
16387
  if (params.clamped?.reason === "trial") {
16351
- return `${base} (model usage covered by Pullfrog)`;
16388
+ return `${base} (free trial credits)`;
16352
16389
  }
16353
16390
  if (params.clamped) {
16354
16391
  const target = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
@@ -16359,13 +16396,14 @@ function formatModelLabel(params) {
16359
16396
  }
16360
16397
  return base;
16361
16398
  }
16362
- function buildTrialDisclosure(owner) {
16363
- const consoleUrl = owner ? `https://pullfrog.com/console/${owner}` : "https://pullfrog.com/console";
16399
+ function buildTrialDisclosure(params) {
16400
+ const consoleUrl = params.owner ? `https://pullfrog.com/console/${params.owner}#billing` : "https://pullfrog.com/console";
16401
+ const left = params.creditsLeftUsd === void 0 ? "" : ` ($${Math.max(0, params.creditsLeftUsd).toFixed(2)} of $${TRIAL_FUNDED_USD_LIMIT} left)`;
16364
16402
  return [
16365
16403
  "---",
16366
16404
  "",
16367
16405
  "> [!IMPORTANT]",
16368
- `> **Pullfrog covered this run's model usage.** \`DeepSeek Flash\` is fast and cheap \u2014 expect lighter work than a frontier model. This model allowance is temporary and separate from your Pullfrog plan. [Connect a model-provider subscription or API key \u2192](${consoleUrl})`
16406
+ `> **This run used your free trial credits**${left} on \`${TRIAL_PROXY_DISPLAY_NAME}\`, a fast, lightweight model. [Connect a provider \u2192](${consoleUrl}) to run the model you choose.`
16369
16407
  ].join("\n");
16370
16408
  }
16371
16409
  function buildPullfrogFooter(params) {
@@ -16388,13 +16426,13 @@ function buildPullfrogFooter(params) {
16388
16426
  `Using ${formatModelLabel({
16389
16427
  model: params.model,
16390
16428
  clamped: params.clamped,
16391
- unselectedProxyDefault: params.unselectedProxyDefault,
16429
+ unselectedProxyDefault: params.unselectedProxyDefault && !params.failed,
16392
16430
  oss: params.oss
16393
16431
  })}`
16394
16432
  );
16395
16433
  }
16396
- const allParts = [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
16397
- const disclosure = params.clamped?.reason === "trial" ? `${buildTrialDisclosure(params.owner)}
16434
+ const allParts = params.failed ? parts : [...parts, "[\u{1D54F}](https://x.com/pullfrogai)"];
16435
+ const disclosure = params.clamped?.reason === "trial" && !params.failed ? `${buildTrialDisclosure({ owner: params.owner, creditsLeftUsd: params.clamped.creditsLeftUsd })}
16398
16436
 
16399
16437
  ` : "";
16400
16438
  return `
@@ -16642,6 +16680,10 @@ function isLeapingIntoActionCommentBody(body) {
16642
16680
  const firstLine = content.split(/\r?\n/, 1)[0]?.trimEnd() ?? "";
16643
16681
  return new RegExp(`(^|\\s)${LEAPING_INTO_ACTION_PREFIX}(\\.\\.\\.)?$`).test(firstLine);
16644
16682
  }
16683
+ var TODO_SPINNER_URL = "https://uploads.pullfrog.com/Progress%20Indicator.gif";
16684
+ function isLiveChecklistCommentBody(body) {
16685
+ return body.includes(TODO_SPINNER_URL);
16686
+ }
16645
16687
 
16646
16688
  // utils/learningsTruncate.ts
16647
16689
  var MAX_LEARNINGS_LENGTH = 1e5;
@@ -16926,6 +16968,8 @@ var PROVIDER_ERROR_PATTERNS = [
16926
16968
  },
16927
16969
  // OpenAI's `You have no credits remaining` (#1474).
16928
16970
  { regex: /no credits remaining/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
16971
+ // Codex on a ChatGPT workspace: `Your workspace is out of credits. Add credits to continue.`
16972
+ { regex: /workspace is out of credits/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
16929
16973
  { regex: /credit balance is too low/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
16930
16974
  // "spending cap" (Gemini) and "spending limit" (xAI, #1076) are the same
16931
16975
  // condition in two house styles — a configured ceiling was reached.
@@ -16955,6 +16999,9 @@ var PROVIDER_ERROR_PATTERNS = [
16955
16999
  // succeeds" while the same log held nine of these. Measured on a live account
16956
17000
  // whose ChatGPT subscription was capped.
16957
17001
  { regex: /\bthe usage limit has been reached\b/i, label: PROVIDER_USAGE_LIMIT_LABEL },
17002
+ // the Codex CLI's wording for the same capped plan: `You’ve hit your usage limit. … try
17003
+ // again at 7:58 AM.` Claude's `hit your session limit` names its window and stays out.
17004
+ { regex: /\bhit your usage limit\b/i, label: PROVIDER_USAGE_LIMIT_LABEL },
16958
17005
  // the OpenRouter shapes `isRouterKeylimitExhaustedError` matches. on a Router
16959
17006
  // run those mean the PULLFROG wallet is empty and `renderRunError` returns a
16960
17007
  // `BillingError` before ever reaching this list; on a BYOK run the very same
@@ -17482,6 +17529,7 @@ export {
17482
17529
  SUBSIDY_RUNG,
17483
17530
  SubscriptionCredentialError,
17484
17531
  TIMEOUT_DISABLED,
17532
+ TRIAL_FUNDED_USD_LIMIT,
17485
17533
  autoLadder,
17486
17534
  autoRoutedSlug,
17487
17535
  buildPullfrogFooter,
@@ -17514,6 +17562,7 @@ export {
17514
17562
  isCredentialProbeable,
17515
17563
  isEffortPosition,
17516
17564
  isLeapingIntoActionCommentBody,
17565
+ isLiveChecklistCommentBody,
17517
17566
  isOssAllowedModel,
17518
17567
  isPullfrog,
17519
17568
  isRouterTier,
@@ -17535,6 +17584,7 @@ export {
17535
17584
  pullfrogMcpName,
17536
17585
  refreshCodexAuthBody,
17537
17586
  refreshXaiAuthBody,
17587
+ renderFailure,
17538
17588
  resolveAutoTier,
17539
17589
  resolveCliModel,
17540
17590
  resolveDisplayAlias,
package/dist/models.d.ts CHANGED
@@ -354,6 +354,10 @@ export declare function resolveModelRung(params: {
354
354
  useOpenRouter: boolean;
355
355
  }): string | undefined;
356
356
  export declare const DEFAULT_PROXY_MODEL: string;
357
+ export declare const TRIAL_PROXY_MODEL: string;
358
+ export declare const TRIAL_PROXY_DISPLAY_NAME: string;
359
+ /** lifetime cap, in USD, on the model usage Pullfrog funds for an account's trial runs. */
360
+ export declare const TRIAL_FUNDED_USD_LIMIT = 10;
357
361
  /**
358
362
  * the models Pullfrog is willing to fund on the OSS program. an accepted OSS
359
363
  * repo may pick any of these and run-context honors the pick; anything else
@@ -1,6 +1,7 @@
1
1
  import type { AgentCredential, AgentUsage } from "./agents/shared.ts";
2
2
  import type { PrepResult } from "./prep/types.ts";
3
3
  import type { AgentDiagnostic } from "./utils/agentHangReport.ts";
4
+ import type { ModelClamp } from "./utils/buildPullfrogFooter.ts";
4
5
  import type { DiffCoverageState } from "./utils/diffCoverage.ts";
5
6
  import { type ProgressComment, type ProgressCommentType } from "./utils/progressComment.ts";
6
7
  import type { TodoTracker } from "./utils/todoTracking.ts";
@@ -140,10 +141,7 @@ export interface ToolState {
140
141
  agent?: string | undefined;
141
142
  credential?: AgentCredential | undefined;
142
143
  unselectedProxyDefault?: boolean | undefined;
143
- modelClamped?: {
144
- from: string;
145
- reason: "card" | "noRouterPath" | "oss" | "trial";
146
- } | undefined;
144
+ modelClamped?: ModelClamp | undefined;
147
145
  oss?: boolean | undefined;
148
146
  todoTracker?: TodoTracker | undefined;
149
147
  agentDiagnostic?: AgentDiagnostic | undefined;
@@ -33,19 +33,15 @@ export type AgentDiagnostic = {
33
33
  sawModelOutput: boolean;
34
34
  };
35
35
  /**
36
- * Build a user-facing markdown body for an agent hang or failure.
36
+ * The body for a run the activity watchdog ended. Rendered into both the PR
37
+ * progress comment and the job summary; `null` when the harness left no
38
+ * diagnostic, so the caller falls back to its bare-error rendering.
37
39
  *
38
- * Rendered into both the PR progress comment and the GitHub Actions job
39
- * summary. Returns `null` when no diagnostic is available, which signals to
40
- * the caller to fall back to its bare-error rendering.
41
- *
42
- * `errorMessage` is the underlying timer / spawn reject string (e.g.
43
- * `activity timeout: no output for 301s`). The idle seconds are parsed out
44
- * of it for the hang explanation — total runtime would overstate the stall
45
- * for runs that streamed for a long time before going quiet.
40
+ * The headline says whose side went quiet, because a silent run is nearly
41
+ * always the provider's and "Pullfrog stalled" read as ours. The agent's last
42
+ * output goes in a collapsed section for whoever wants it.
46
43
  */
47
44
  export declare function formatAgentHangBody(input: {
48
45
  diagnostic: AgentDiagnostic | undefined;
49
- isHang: boolean;
50
46
  errorMessage: string;
51
47
  }): string | null;
@@ -1,9 +1,10 @@
1
+ import { type FailureLink } from "./failureBody.ts";
1
2
  import type { CredentialCandidate } from "./subscriptionCredentials.ts";
2
3
  import type { ProbeVerdict } from "./subscriptionProbe.ts";
3
4
  /** shared sentence in the four `resolveSlug` routing-slug throws. */
4
- export declare const BYOK_SLUG_MARKER = "env var is required when the model is set to";
5
+ export declare const BYOK_SLUG_MARKER = "must be set when the model is";
5
6
  /** shared sentence in the four `validate*Setup` throws. */
6
- export declare const BYOK_CONFIG_MARKER = "selected but required configuration is missing:";
7
+ export declare const BYOK_CONFIG_MARKER = "is missing required settings:";
7
8
  /**
8
9
  * A BYOK provider setup is incomplete, at either of the two points that catch it:
9
10
  * `resolveSlug` refusing a routing slug whose backing env var is unset, and the
@@ -28,14 +29,35 @@ export declare function isByokSetupError(text: string): boolean;
28
29
  * `MODEL_ACCESS_MARKER`) because blaming the user for a transient fetch failure
29
30
  * on our side is the wrong CTA — their key is configured and still stored.
30
31
  */
31
- export declare const SECRETS_UNAVAILABLE_MARKER = "couldn't load your Pullfrog secrets";
32
+ export declare const SECRETS_UNAVAILABLE_MARKER = "couldn't load your stored secrets";
32
33
  /**
33
34
  * marker for the "your Router wallet is empty AND you have no provider key"
34
35
  * body. its own marker rather than the missing-key one because
35
36
  * `formatApiKeyErrorSummary` rebuilds any body carrying `MISSING_KEY_MARKER`
36
37
  * that doesn't start with it, which would silently discard this copy.
37
38
  */
38
- export declare const ROUTER_UNFUNDED_MARKER = "your Pullfrog Router balance is empty";
39
+ export declare const ROUTER_UNFUNDED_MARKER = "Your Pullfrog Router balance is empty";
40
+ /**
41
+ * marker for the body a trial account gets once its funded credits are spent:
42
+ * at the late fallback, or when the funded key runs out mid-run. Without it the
43
+ * first is told to add an API key and the second that a Router wallet it never
44
+ * had went negative, and neither mentions the trial.
45
+ */
46
+ export declare const TRIAL_SPENT_MARKER = "reached the limit of your free trial credits";
47
+ export declare function buildTrialSpentError(params: {
48
+ owner: string;
49
+ }): string;
50
+ /** the repo's console page: its model, instructions and scripts. */
51
+ export declare function repoConsoleUrl(repo: {
52
+ owner: string;
53
+ name: string;
54
+ }): string;
55
+ export declare function pickModelLink(repo: {
56
+ owner: string;
57
+ name: string;
58
+ }): FailureLink;
59
+ /** the account console's billing card: provider keys, subscriptions and Router credit. */
60
+ export declare function providerLink(owner: string): FailureLink;
39
61
  /**
40
62
  * marker for a credential the provider explicitly REJECTED before the agent
41
63
  * started. needs a verbatim guard for the same reason as its three siblings,
@@ -76,6 +98,7 @@ export declare const CREDENTIAL_POOL_REFUSED_MARKER = "No configured credential
76
98
  */
77
99
  export declare class NoUsableCredentialError extends Error {
78
100
  }
101
+ export declare function buildSecretsUnavailableError(): string;
79
102
  /**
80
103
  * Validate that the resolved model can actually be served by the chosen
81
104
  * agent. For routing slugs (Bedrock / Vertex) the auth shape is multi-var
@@ -160,6 +183,8 @@ export declare function isMalformedKeyError(text: string): boolean;
160
183
  * Anthropic entitlement denial for Claude Pro/Max subscription auth (#1072):
161
184
  * an org admin turned off Claude Code subscription access. no credential the
162
185
  * user controls fixes it, so it gets its own copy instead of the re-auth CTA.
186
+ * The probe sees the same denial as a 403, `OAuth authentication is currently
187
+ * not allowed for this organization`, which used to be answered "sign in again".
163
188
  */
164
189
  export declare function isClaudeSubscriptionDisabledError(text: string): boolean;
165
190
  /**
@@ -178,6 +203,15 @@ export declare function isClaudeSubscriptionDisabledError(text: string): boolean
178
203
  */
179
204
  export declare function isKimiPlanTierError(text: string): boolean;
180
205
  export declare function isClaudeSessionLimitError(text: string): boolean;
206
+ /** the subscription that serves `model`'s provider, named by the env var that carries it. */
207
+ export declare function subscriptionFor(model: string | undefined): {
208
+ label: string;
209
+ command: string;
210
+ provider: string;
211
+ env: string;
212
+ } | undefined;
213
+ /** a provider id's display name, e.g. `openai` → OpenAI. */
214
+ export declare function providerDisplayName(id: string | null | undefined): string | undefined;
181
215
  /**
182
216
  * The provider rejected a credential we checked before the agent started, and
183
217
  * nothing else on the account can serve this run. Names the credential and the
@@ -201,8 +235,8 @@ export type RefusedCredential = {
201
235
  };
202
236
  /**
203
237
  * The credential pool probed every credential configured for the model and
204
- * none can serve it. One bullet per credential: the probe's own verdict, quoted,
205
- * plus the remedy its kind and status call for — never inferred from the prose.
238
+ * none can serve it. One sentence per credential, from its kind and status —
239
+ * never inferred from the prose — with the probe's own verdicts collapsed below.
206
240
  */
207
241
  export declare function buildCredentialPoolRefusedError(params: {
208
242
  model: string;
@@ -213,10 +247,16 @@ export declare function buildCredentialPoolRefusedError(params: {
213
247
  /**
214
248
  * Friendly Markdown summary for both the missing-key and invalid-key cases.
215
249
  * Used in the catch / result-failure paths in `main.ts` to overwrite the raw
216
- * agent error before it's posted to the PR progress comment.
250
+ * agent error before it's posted to the PR progress comment. `model` names the
251
+ * subscription in play — guessing it from the env once told a GPT run its Claude
252
+ * subscription was rejected — and `output`, the provider's own words, is
253
+ * collapsed under the copy.
217
254
  */
218
255
  export declare function formatApiKeyErrorSummary(params: {
219
256
  owner: string;
220
257
  name: string;
221
258
  raw: string;
259
+ model?: string | undefined;
260
+ credential?: string | undefined;
261
+ output?: string | undefined;
222
262
  }): string;
@@ -41,7 +41,9 @@ export declare class BillingError extends Error {
41
41
  * GH Actions apply whatever retry policy the workflow has configured.
42
42
  */
43
43
  export declare class TransientError extends Error {
44
- constructor(message: string);
44
+ /** the customer-facing follow-up to `message`, which is the headline. */
45
+ detail: string;
46
+ constructor(message: string, detail?: string);
45
47
  }
46
48
  /**
47
49
  * Why the org commercial gate refused a run (billing model v2), resolved by
@@ -114,6 +116,7 @@ export declare function formatBillingErrorSummary(error: BillingError, owner: st
114
116
  /**
115
117
  * Render a TransientError as user-facing markdown. Distinct framing from
116
118
  * BillingError so the user doesn't read an alarm and assume their card
117
- * failed, this branch is "our fault, retry shortly", not theirs.
119
+ * failed, this branch is "our fault, retry shortly", not theirs. Both parts are
120
+ * ours and customer-ready; the server's own wording goes to the log.
118
121
  */
119
- export declare function formatTransientErrorSummary(error: TransientError, owner: string): string;
122
+ export declare function formatTransientErrorSummary(error: TransientError): string;
@@ -1,4 +1,18 @@
1
1
  export declare const PULLFROG_DIVIDER = "<!-- PULLFROG_DIVIDER_DO_NOT_REMOVE_PLZ -->";
2
+ /**
3
+ * A run whose configured model was swapped for one Pullfrog could fund. `trial`
4
+ * carries the account's remaining trial credits, as run-context counted them
5
+ * when the run started, so the disclosure can say how much is left; undefined
6
+ * when the server predates the figure.
7
+ */
8
+ export type ModelClamp = {
9
+ from: string;
10
+ reason: "card" | "noRouterPath" | "oss";
11
+ } | {
12
+ from: string;
13
+ reason: "trial";
14
+ creditsLeftUsd: number | undefined;
15
+ };
2
16
  export interface WorkflowRunFooterInfo {
3
17
  owner: string;
4
18
  repo: string;
@@ -27,10 +41,7 @@ export interface BuildPullfrogFooterParams {
27
41
  * provider-key nudge — so the downgrade is visible rather than silently
28
42
  * presenting Kimi as the pick.
29
43
  */
30
- clamped?: {
31
- from: string;
32
- reason: "card" | "noRouterPath" | "oss" | "trial";
33
- } | undefined;
44
+ clamped?: ModelClamp | undefined;
34
45
  /**
35
46
  * true when the run used the default proxy model only because no model was
36
47
  * selected (Router billing + "auto"). the footer appends a note nudging the
@@ -47,6 +58,8 @@ export interface BuildPullfrogFooterParams {
47
58
  /** repo owner, used to deep-link the trial disclosure at that account's own
48
59
  * console rather than the generic landing page. */
49
60
  owner?: string | undefined;
61
+ /** a failure comment: no 𝕏 link, model nudge or trial disclosure under an error. */
62
+ failed?: boolean | undefined;
50
63
  }
51
64
  /**
52
65
  * build a pullfrog footer with configurable parts
@@ -2,7 +2,6 @@ import { type ToolState } from "../toolState.ts";
2
2
  interface ReportErrorParams {
3
3
  toolState: ToolState;
4
4
  error: string;
5
- title?: string;
6
5
  /**
7
6
  * When the run has no pre-existing progress comment to update (silent
8
7
  * IncrementalReview / pull_request_synchronize, mode-less polls), create
@@ -0,0 +1,27 @@
1
+ export type FailureLink = {
2
+ label: string;
3
+ url: string;
4
+ };
5
+ /**
6
+ * The one shape every failure comment takes: a bold, sentence-case headline that
7
+ * names the cause, then at most a short paragraph or a list of two or more, then
8
+ * the error or the tool's own output, then at most two links. Built here rather
9
+ * than per message so those rules hold for every message at once.
10
+ *
11
+ * `error` is shown open, for when the error IS the explanation (an unrecognized
12
+ * failure). `details` is collapsed, for output that backs up a headline we
13
+ * already wrote. Free of imports: `billingErrors.ts` reaches client bundles
14
+ * through `action/internal`.
15
+ */
16
+ export declare function renderFailure(params: {
17
+ headline: string;
18
+ detail?: string | undefined;
19
+ list?: [string, string, ...string[]] | undefined;
20
+ error?: string | undefined;
21
+ details?: {
22
+ summary: string;
23
+ text: string;
24
+ } | undefined;
25
+ links?: [] | [FailureLink] | [FailureLink, FailureLink] | undefined;
26
+ }): string;
27
+ export declare const DISCORD_LINK: FailureLink;
@@ -9,3 +9,12 @@
9
9
  */
10
10
  export declare const LEAPING_INTO_ACTION_PREFIX = "Leaping into action";
11
11
  export declare function isLeapingIntoActionCommentBody(body: string): boolean;
12
+ /** the spinner on a to-do list's in-progress item. */
13
+ export declare const TODO_SPINNER_URL = "https://uploads.pullfrog.com/Progress%20Indicator.gif";
14
+ /**
15
+ * A live to-do list: one item still carries the spinner. Every finished body — a
16
+ * final summary, a salvaged answer, an error report — renders with in-progress
17
+ * items completed, so the spinner is only ever on a list whose run is still going
18
+ * or died without writing again.
19
+ */
20
+ export declare function isLiveChecklistCommentBody(body: string): boolean;
@@ -61,6 +61,7 @@ export declare function runProxyResolution(ctx: {
61
61
  export declare function resolveTrialFallback(ctx: {
62
62
  payload: ResolvedPayload;
63
63
  configuredModel: string | undefined;
64
+ creditsLeftUsd: number | undefined;
64
65
  oidcCredentials: OidcCredentials | null;
65
66
  repo: {
66
67
  owner: string;
@@ -42,8 +42,9 @@ import type { GitHubAppPermissions } from "./github.ts";
42
42
  * wiki/autonomous-maintenance.md's "no injected instruction can cause a
43
43
  * merge" still true. Legitimate pushes go through `push_branch`, which
44
44
  * enforces the branch rules.
45
- * - `checks` is absent for the same class of reason: no human role grants it,
46
- * and it would let the agent post its own passing `pullfrog-approval` status
45
+ * - `checks` is `read`, never `write`, for the same class of reason: every role
46
+ * can read a PR's check runs, but no human role can write one, and write would
47
+ * let the agent post its own passing `pullfrog-approval` status
47
48
  * (see wiki/review-approval.md).
48
49
  * - Every qualifying role therefore receives the SAME set. The role decides
49
50
  * whether a token is minted at all, not how wide it is — `admin`, `maintain`
@@ -100,6 +100,9 @@ export interface RunContext {
100
100
  * run — the runner may mint a subsidized efficient-tier key if, and only if,
101
101
  * its own key search comes up dry. see the run-context route. */
102
102
  trialFallback?: boolean | undefined;
103
+ /** the trial account's remaining funded credits, in USD, when it is inside its
104
+ * trial at all. zero or below means the credits are used up. */
105
+ trialCreditsLeftUsd?: number | undefined;
103
106
  }
104
107
  /**
105
108
  * fetch run context from Pullfrog API
@@ -29,6 +29,8 @@ export interface RunContextData {
29
29
  * own key search comes up dry. a permission, not a routing decision — the
30
30
  * server cannot see workflow `env:` keys. see `RunContext.trialFallback`. */
31
31
  trialFallback?: boolean | undefined;
32
+ /** see `RunContext.trialCreditsLeftUsd`. */
33
+ trialCreditsLeftUsd?: number | undefined;
32
34
  }
33
35
  interface ResolveRunContextDataParams {
34
36
  octokit: OctokitWithPlugins;