pullfrog 0.1.99 → 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.
@@ -1,99 +1,67 @@
1
1
  /**
2
- * Classify + render the error thrown out of the main run try-block into a
3
- * pair of user-facing markdown bodies — one for the GitHub Actions job
4
- * summary tab, one for the PR progress comment.
2
+ * Classify + render the error thrown out of the main run try-block into the
3
+ * markdown the user reads — the PR progress comment, and the same body under a
4
+ * `### ❌ Pullfrog failed` banner in the GitHub Actions job summary.
5
5
  *
6
- * Classifications, in dispatch order (first match wins; the api-key
7
- * branch additionally folds in the activity-timeout hang body as a
8
- * sub-source so a hang masking an api-key error still surfaces the api-key
9
- * CTA):
6
+ * Every body names its cause, so none collapses to a bare "Run failed.": an
7
+ * error nothing below recognizes is shown as-is under "An unrecognized error
8
+ * occurred." The shape is `renderFailure`'s, so the copy rules hold for all of
9
+ * them — see `failureBody.ts`.
10
10
  *
11
- * 1. `BillingError` — either the proxy-token mint already threw one (402
12
- * handled inline) or the agent runtime surfaced an OpenRouter
13
- * "key budget exhausted" string mid-run. Both render via
14
- * `formatBillingErrorSummary` so the user sees actionable copy.
11
+ * Classifications, in dispatch order (first match wins):
15
12
  *
16
- * 1a. Pre-rendered bodies — a throw site that already built the markdown
13
+ * 1. Trial credits — a trial key that ran out mid-run is the account's free
14
+ * credits running out, never the Router wallet the same wire text means
15
+ * on a Router run.
16
+ *
17
+ * 1a. `BillingError` — the agent runtime surfaced an OpenRouter "key budget
18
+ * exhausted" string mid-run on a Router run. Same copy as a proxy-token 402.
19
+ *
20
+ * 1b. Pre-rendered bodies — a throw site that already built the markdown
17
21
  * (`MODEL_ACCESS_MARKER`, `SECRETS_UNAVAILABLE_MARKER`,
18
- * `ROUTER_UNFUNDED_MARKER`, `CREDENTIAL_REJECTED_MARKER`,
19
- * `CREDENTIAL_POOL_REFUSED_MARKER`) passes through verbatim on both surfaces.
22
+ * `ROUTER_UNFUNDED_MARKER`, `TRIAL_SPENT_MARKER`,
23
+ * `CREDENTIAL_REJECTED_MARKER`, `CREDENTIAL_POOL_REFUSED_MARKER`) passes
24
+ * through verbatim.
20
25
  *
21
26
  * 2. BYOK provider billing-exhausted (#835) — DeepSeek "Insufficient
22
27
  * Balance", Anthropic "credit balance is too low", OpenCode Zen
23
- * `CreditsError`, Gemini "spending cap". Checked before api-key auth
24
- * because billing-exhausted responses often carry 401 status codes
25
- * that `isApiKeyAuthError` would otherwise mis-classify.
28
+ * `CreditsError`, Gemini "spending cap", a ChatGPT workspace out of
29
+ * credits. Checked before api-key auth because billing-exhausted responses
30
+ * often carry 401 status codes that `isApiKeyAuthError` would otherwise
31
+ * mis-classify.
26
32
  *
27
33
  * 2a. Provider usage limit (#1474) — a capped subscription window or a
28
34
  * configured workspace limit; "wait or raise it", never "top up".
29
35
  *
30
36
  * 3. API-key auth error — `isApiKeyAuthError` sniffs the raw error string
31
37
  * (or the activity-timeout hang body when present, since that's where
32
- * the underlying provider error often lands); `formatApiKeyErrorSummary`
33
- * renders provider + console-link copy.
34
- *
35
- * 4. ProviderModelNotFoundError — configured model id not in the OpenCode
36
- * catalog (opencode ≥1.18 words it `Model not found: <id>`, #1470);
37
- * renders a nudge to pick a different model.
38
- *
39
- * 4a. No-provider-available (#1077) — the model IS in the catalog but the
40
- * provider declines to route it on this account's plan (OpenCode Zen's
41
- * own refusal string). Same "pick another model" CTA, different reason.
38
+ * the underlying provider error often lands).
42
39
  *
43
- * 4a'. Zen free-tier gate (#1377) — Zen 403s a free-tier request whose tool
44
- * list is missing a built-in it expects. The harness keeps `bash` listed,
45
- * but opencode's auto-compaction request carries no tools, so a long
46
- * free-Zen run can still die mid-flight on the raw upstream string.
47
- *
48
- * 4b. Context-window overflow (#1116) — terminal `Prompt is too long` /
49
- * `maximum context length is N tokens`. Actionable, so it renders on
50
- * both surfaces rather than collapsing to the one-line comment.
51
- *
52
- * 4b'. Run time limit — the agent was still working when the run's own
53
- * timeout fired. Actionable (raise the limit), so both surfaces.
40
+ * 4. Model not in OpenCode's catalog (opencode ≥1.18 words it `Model not
41
+ * found: <id>`, #1470), a provider declining the model (#1077), Zen's
42
+ * free-tier gate (#1377), context overflow (#1116), the run's time limit,
43
+ * the repo's stop script, and an agent that never posted its review.
54
44
  *
55
45
  * 4c. Transient upstream failure (#1173) — Anthropic `529 Overloaded`,
56
46
  * OpenRouter `provider_unavailable` / `timeout`, Zen `Streaming response
57
- * failed: [5xx]`. Last of the classified branches so every more specific
58
- * one wins first. Renders on both surfaces: the remedy is re-triggering,
59
- * which the user can only know if we say so.
47
+ * failed: [5xx]`, Codex's model at capacity. Last of the classified
48
+ * branches so every more specific one wins first.
60
49
  *
61
- * 5. Activity-timeout hang — `errorMessage` starts with
62
- * `"activity timeout"` or `"agent still pending"` AND none of the
63
- * above matched. The harness keeps structured diagnostic state on
64
- * `toolState.agentDiagnostic`; `formatAgentHangBody` renders that into
65
- * the job summary. The PR comment keeps that same body whenever the hang
66
- * is EXPLAINED — a classified provider error (#778, #1183) or a provider
67
- * that never returned a first token — and otherwise collapses to a
68
- * one-line `**Run failed.** [View the logs →]`, because watchdog jargon,
69
- * event counts and a benign stderr tail are operator-grade detail that
70
- * only alarm the average user.
50
+ * 5. Activity-timeout hang — `formatAgentHangBody` says whose side went
51
+ * quiet, with the agent's last output collapsed under it.
71
52
  *
72
53
  * 6. Unclassified provider error (#1474) — `errorMessage` starts with
73
- * `provider error: `. opencode prefixes every provider-side turn failure
74
- * with the provider's text; claude-code (a zero-event exit) and codex (no
75
- * turn error, no stderr) prefix only our classifier label. Either names
76
- * something the user can act on, so both surfaces get a lead line plus the
77
- * raw text in a fenced block.
54
+ * `provider error: `: the provider's own text, shown under a lead line.
78
55
  *
79
- * 7. Default — the job summary gets a plain-English lead sentence plus the
80
- * raw error in a fenced code block under the `### ❌ Pullfrog failed`
81
- * banner; the PR comment collapses to the same one-line logs link as
82
- * the hang case, since the raw internal string helps nobody on the PR.
83
- *
84
- * Net: the actionable classifications (billing, usage limit, API-key,
85
- * model-not-found, no-provider-available, context-overflow, run time limit,
86
- * transient-upstream, unclassified provider error) render identical bodies on
87
- * both surfaces; the non-actionable ones (unexplained hang, generic) keep the
88
- * forensics in the Actions job summary and show a calm one-liner in the PR
89
- * comment, whose footer already carries Pullfrog branding + rerun links.
56
+ * 7. Default — "An unrecognized error occurred." over the error itself.
90
57
  */
58
+ import type { AgentCredential } from "../agents/shared.ts";
91
59
  import type { AgentDiagnostic } from "./agentHangReport.ts";
92
60
  export type RenderedRunError = {
93
61
  summary: string;
94
62
  comment: string;
95
63
  };
96
- export declare function renderRunError(input: {
64
+ type RenderRunErrorInput = {
97
65
  errorMessage: string;
98
66
  repo: {
99
67
  owner: string;
@@ -104,4 +72,11 @@ export declare function renderRunError(input: {
104
72
  * the user's own provider credential. `payload.proxyModel` at both call
105
73
  * sites. */
106
74
  routerActive: boolean;
107
- }): RenderedRunError;
75
+ /** the model that ran: it names the provider, and the subscription when one is in play. */
76
+ model?: string | undefined;
77
+ credential?: AgentCredential | undefined;
78
+ /** the run was served by the account's free trial credits. */
79
+ trial?: boolean | undefined;
80
+ };
81
+ export declare function renderRunError(input: RenderRunErrorInput): RenderedRunError;
82
+ export {};
@@ -1,19 +1,10 @@
1
+ export declare function maskSecret(value: string): void;
1
2
  /**
2
- * `@actions/core` workflow commands that carry a credential, gated on actually
3
- * running under a runner.
4
- *
5
- * Off a runner nothing consumes these commands and `@actions/core` writes the
6
- * raw value to stdout instead — `setSecret` always, `saveState` / `setOutput`
7
- * whenever `GITHUB_STATE` / `GITHUB_OUTPUT` are unset. That is a plaintext
8
- * credential on whatever terminal is running the action, which is how an OpenAI
9
- * key reached local Codex transcripts and was disabled (2026-09).
10
- *
11
- * Route every credential-bearing call through here instead of calling `core`
12
- * directly — `nub run check:secret-commands` enforces it. Non-credential output
13
- * (the agent's own `result` text) stays ungated, because the test harness reads
14
- * it back through `GITHUB_OUTPUT` on a host with no runner.
3
+ * Every value `maskSecret` registered, replaced in `text` as the runner would in
4
+ * a log: whole, then line by line. Parts under 8 characters are skipped, or the
5
+ * `{` and `}` lines of a JSON key would blank every brace in the comment.
15
6
  */
16
- export declare function maskSecret(value: string): void;
7
+ export declare function redactSecrets(text: string): string;
17
8
  /** @see maskSecret — same gate, for state the `post:` hook reads back. */
18
9
  export declare function saveSecretState(name: string, value: string): void;
19
10
  /** @see maskSecret — same gate, for a step output carrying a credential. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.99",
3
+ "version": "0.1.101",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {