pullfrog 0.1.94 → 0.1.96

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, pickUsesOpenRouter, providers, pullfrogMcpName, ROUTED_PROVIDERS, ROUTER_LADDER, ROUTER_TIERS, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, 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, } 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";
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.94",
11
+ version: "0.1.96",
12
12
  cliContractVersion: "1",
13
13
  type: "module",
14
14
  bin: {
@@ -74,7 +74,7 @@ var package_default = {
74
74
  undici: "^7.22.0",
75
75
  vitest: "^4.0.17",
76
76
  yaml: "^2.8.2",
77
- yes: "0.0.3",
77
+ yes: "0.2.3",
78
78
  zod: "4.3.6"
79
79
  },
80
80
  repository: {
@@ -15003,6 +15003,17 @@ var providers = {
15003
15003
  // see the big-pickle note above (#1077).
15004
15004
  isFree: true
15005
15005
  },
15006
+ // Zen's FREE stealth preview (listed 2026-10-01), the fifth promo. Zen
15007
+ // has not published its data terms yet, so the description claims none.
15008
+ "fledge-alpha": {
15009
+ displayName: "Fledge Alpha",
15010
+ description: "Stealth preview, free for a limited time",
15011
+ resolve: "opencode/fledge-alpha-free",
15012
+ effort: ["low", "high", "max"],
15013
+ // free to run, still gated on the provider's own OPENCODE_API_KEY —
15014
+ // see the big-pickle note above (#1077).
15015
+ isFree: true
15016
+ },
15006
15017
  // Zen's live free MiMo, and the second free row in a menu that big-pickle
15007
15018
  // was alone in since `mimo-v2-pro-free` lost its model.
15008
15019
  mimo: {
@@ -15065,7 +15076,11 @@ var providers = {
15065
15076
  "glm-flash": {
15066
15077
  displayName: "GLM Flash",
15067
15078
  resolve: "opencode-go/glm-5.3-flash",
15068
- effort: ["low", "high", "max"],
15079
+ // the Go endpoint intermittently rejects reasoning_effort ("native reasoning
15080
+ // control reasoning_effort is not allowed") mid-run, despite models.dev
15081
+ // advertising a ladder — so this route sends none.
15082
+ effort: [],
15083
+ openRouterEffort: ["low", "high", "max"],
15069
15084
  openRouterResolve: "openrouter/z-ai/glm-5.3-flash"
15070
15085
  },
15071
15086
  // legacy alias — the slug pinned a version instead of a brand tier and
@@ -15521,7 +15536,7 @@ var providers = {
15521
15536
  "deepseek-pro": {
15522
15537
  displayName: "DeepSeek Pro",
15523
15538
  resolve: "vercel/deepseek/deepseek-v4-pro-0813",
15524
- effort: ["none", "high", "max"]
15539
+ effort: ["none", "low", "high", "max"]
15525
15540
  },
15526
15541
  // the gateway's bare `deepseek-v4-flash` is the April preview — the same
15527
15542
  // fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
@@ -15529,7 +15544,7 @@ var providers = {
15529
15544
  "deepseek-flash": {
15530
15545
  displayName: "DeepSeek Flash",
15531
15546
  resolve: "vercel/deepseek/deepseek-v4.1-flash",
15532
- effort: ["none", "high", "max"]
15547
+ effort: ["none", "low", "high", "max"]
15533
15548
  },
15534
15549
  glm: {
15535
15550
  displayName: "GLM",
@@ -15600,8 +15615,8 @@ function routerProxyOptOut(ctx) {
15600
15615
  if (ctx.slug === null) return false;
15601
15616
  return resolveDisplayAlias(ctx.slug)?.isFree === true || modelHasStoredAuth({ model: ctx.slug, secretNames: ctx.secretNames });
15602
15617
  }
15603
- function pickUsesOpenRouter(params) {
15604
- return params.proxied && !routerProxyOptOut(params);
15618
+ function resolvePickModel(params) {
15619
+ return params.proxied && !routerProxyOptOut(params) ? resolveOpenRouterModel(params.slug) : resolveCliModel(params.slug);
15605
15620
  }
15606
15621
  var modelAliases = Object.entries(providers).flatMap(
15607
15622
  ([providerKey, config2]) => Object.entries(config2.models).map(([modelId, def]) => ({
@@ -15784,13 +15799,13 @@ for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTE
15784
15799
  if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
15785
15800
  }
15786
15801
  var OSS_MODEL_ALLOWLIST = [
15787
- "deepseek/deepseek-flash",
15788
- "openai/gpt-luna",
15789
- "openrouter/minimax-m2.5",
15790
15802
  // opt-in: 0.86x the old default on the measured mix, and Meta trains on the
15791
15803
  // traffic — fine for public code on headless runs, the human decided
15792
15804
  // 2026-09-11. unmeasured on a real run; not the default until it is.
15793
- "meta/muse-spark-contributor"
15805
+ "meta/muse-spark-contributor",
15806
+ "deepseek/deepseek-flash",
15807
+ "openai/gpt-luna",
15808
+ "openrouter/minimax-m2.5"
15794
15809
  ];
15795
15810
  var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
15796
15811
  function ossFundedModelNames() {
@@ -16124,7 +16139,7 @@ ${PR_SUMMARY_FORMAT}`
16124
16139
 
16125
16140
  Follow these rules:
16126
16141
  - note: the first create_pull_request_review submission may error with a one-time diff-coverage nudge listing unread TOC regions. retry the same call to proceed \u2014 optionally after reading the listed ranges. the pre-flight will not block again this session.
16127
- - IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Instead call \`${t("report_progress")}\` with a 1-2 sentence note explaining no review was warranted (e.g. "No new issues. Changes since last review are formatting-only."). this leaves a visible signal that the run completed.
16142
+ - IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Instead call \`${t("report_progress")}\` with \`no_review_needed: true\` and a 1-2 sentence note explaining no review was warranted (e.g. "No new issues. Changes since last review are formatting-only."). this leaves a visible signal that the run completed.
16128
16143
  - ELSE IF NEW CRITICAL ISSUES (blocks merge \u2014 bugs, security, data loss, broken core flows): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!CAUTION]\\n> This PR introduces ...\`, followed by the PR summary using the default format below.
16129
16144
  - ELSE IF NEW MUST-ADDRESS NON-CRITICAL FINDINGS (real consequences if shipped \u2014 incorrect behavior, missing validation, regressions the author should fix before merge): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!IMPORTANT]\\n> ...\`, followed by the PR summary using the default format below. Do NOT use this tier for nits, style preferences, or "consider also" suggestions.
16130
16145
  - ELSE IF NEW MINOR SUGGESTIONS ONLY (low-stakes findings, or Nitpicks only): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> \u2139\uFE0F No critical issues \u2014 minor suggestions inline.\\n\\n\` (vary the wording after \u2139\uFE0F to fit the review), followed by the PR summary using the default format below.
@@ -17008,7 +17023,12 @@ function terminalOutput(params) {
17008
17023
  const review = params.reviewUrl ? `
17009
17024
 
17010
17025
  [View the review Pullfrog posted \u2192](${params.reviewUrl})` : "";
17011
- if (params.conclusion === "success") return { title: base.title, summary: base.summary + review };
17026
+ if (params.conclusion === "success") {
17027
+ const note = params.note ? `
17028
+
17029
+ ${params.note}` : "";
17030
+ return { title: base.title, summary: base.summary + review + note };
17031
+ }
17012
17032
  return {
17013
17033
  title: base.title,
17014
17034
  summary: base.summary + logsLine(params.detailsUrl) + review + disableCheckLine(params.owner, params.repo)
@@ -17050,7 +17070,8 @@ async function finalizeRunStatusCheck(params) {
17050
17070
  owner: params.owner,
17051
17071
  repo: params.repo,
17052
17072
  detailsUrl: params.detailsUrl,
17053
- reviewUrl: params.reviewUrl
17073
+ reviewUrl: params.reviewUrl,
17074
+ note: params.note
17054
17075
  })
17055
17076
  };
17056
17077
  if (params.detailsUrl) updateParams.details_url = params.detailsUrl;
@@ -17193,7 +17214,13 @@ var codexUsageSchema = external_exports.object({
17193
17214
  limit_reached: external_exports.boolean(),
17194
17215
  primary_window: codexWindowSchema,
17195
17216
  secondary_window: codexWindowSchema
17196
- }).optional()
17217
+ }).optional(),
17218
+ credits: external_exports.object({
17219
+ has_credits: external_exports.boolean().optional(),
17220
+ unlimited: external_exports.boolean().optional(),
17221
+ overage_limit_reached: external_exports.boolean().optional()
17222
+ }).nullish(),
17223
+ spend_control: external_exports.object({ reached: external_exports.boolean().optional() }).nullish()
17197
17224
  });
17198
17225
  var unknown2 = { status: "unknown" };
17199
17226
  var SubscriptionCredentialError = class extends Error {
@@ -17261,9 +17288,12 @@ async function probeSubscription(input) {
17261
17288
  const body = await response.json().catch(() => null);
17262
17289
  if (!codex) return unknown2;
17263
17290
  const parsed = codexUsageSchema.safeParse(body);
17264
- const limit = parsed.success ? parsed.data.rate_limit : void 0;
17265
- if (!limit) return unknown2;
17291
+ if (!parsed.success || !parsed.data.rate_limit) return unknown2;
17292
+ const limit = parsed.data.rate_limit;
17266
17293
  if (limit.allowed && !limit.limit_reached) return { status: "usable" };
17294
+ const credits = parsed.data.credits;
17295
+ if ((credits?.has_credits || credits?.unlimited) && !credits.overage_limit_reached && !parsed.data.spend_control?.reached)
17296
+ return { status: "usable" };
17267
17297
  const windows = [limit.primary_window, limit.secondary_window];
17268
17298
  const full = windows.filter((window) => (window?.used_percent ?? 0) >= 100);
17269
17299
  const resets = (full.length ? full : windows).flatMap(
@@ -17311,15 +17341,24 @@ async function probeInference(input) {
17311
17341
  const error48 = external_exports.object({ error: external_exports.object({ code: external_exports.string() }) }).safeParse(await response.json().catch(() => null));
17312
17342
  return error48.success && error48.data.error.code === "insufficient_quota" ? { status: "exhausted", detail: "refused with 429: insufficient quota", resetAt: void 0 } : unknown2;
17313
17343
  }
17344
+ if (response?.status === 401 || response?.status === 403)
17345
+ return {
17346
+ status: "rejected",
17347
+ detail: `rejected with ${response.status}${await providerReason(response)}`
17348
+ };
17314
17349
  await response?.body?.cancel();
17315
17350
  if (!response) return unknown2;
17316
17351
  if (response.ok) return { status: "usable" };
17317
- if (response.status === 401 || response.status === 403)
17318
- return { status: "rejected", detail: `rejected with ${response.status}` };
17319
17352
  if (response.status === 402)
17320
17353
  return { status: "exhausted", detail: "refused with 402", resetAt: void 0 };
17321
17354
  return unknown2;
17322
17355
  }
17356
+ async function providerReason(response) {
17357
+ const body = external_exports.object({ error: external_exports.union([external_exports.string(), external_exports.object({ message: external_exports.string() })]) }).safeParse(await response.json().catch(() => null));
17358
+ if (!body.success) return "";
17359
+ const error48 = body.data.error;
17360
+ return `: ${(typeof error48 === "string" ? error48 : error48.message).slice(0, 300)}`;
17361
+ }
17323
17362
 
17324
17363
  // utils/time.ts
17325
17364
  var TIMEOUT_DISABLED = "none";
@@ -17409,7 +17448,6 @@ export {
17409
17448
  parseModel,
17410
17449
  parseTimeString,
17411
17450
  parseXaiAuthBody,
17412
- pickUsesOpenRouter,
17413
17451
  probeSubscription,
17414
17452
  providers,
17415
17453
  pullfrogMcpName,
@@ -17421,6 +17459,7 @@ export {
17421
17459
  resolveModelRung,
17422
17460
  resolveModelSlug,
17423
17461
  resolveOpenRouterModel,
17462
+ resolvePickModel,
17424
17463
  resolveRoutedModel,
17425
17464
  resolveRung,
17426
17465
  routerProxyOptOut,
@@ -33,6 +33,7 @@ export declare function EditCommentTool(ctx: ToolContext): import("fastmcp").Too
33
33
  export declare const ReportProgress: import("arktype/internal/variants/object.ts").ObjectType<{
34
34
  body: string;
35
35
  target_plan_comment?: boolean;
36
+ no_review_needed?: boolean;
36
37
  }, {}>;
37
38
  /**
38
39
  * Report progress to a GitHub comment.
@@ -61,9 +62,11 @@ export declare function reportProgress(ctx: ToolContext, params: {
61
62
  export declare function ReportProgressTool(ctx: ToolContext): import("fastmcp").Tool<any, import("@standard-schema/spec").StandardSchemaV1<{
62
63
  body: string;
63
64
  target_plan_comment?: boolean;
65
+ no_review_needed?: boolean;
64
66
  }, {
65
67
  body: string;
66
68
  target_plan_comment?: boolean;
69
+ no_review_needed?: boolean;
67
70
  }>> & {
68
71
  mutates?: boolean;
69
72
  };
package/dist/models.d.ts CHANGED
@@ -189,7 +189,7 @@ export declare function modelHasStoredAuth(params: {
189
189
  * as-configured rather than clamping to the auto tier.
190
190
  *
191
191
  * one predicate for every reader — the console picker's `customLocked`, the
192
- * effort ladder's `resolveRunning` and `pickUsesOpenRouter`. they held two
192
+ * effort ladder's `resolveRunning` and `resolvePickModel`. they held two
193
193
  * copies and the free half was missing from both, which put the whole `opencode/*` free tier (`opencode/big-pickle`
194
194
  * is `preferred`, so the most-picked model there is) behind "add a payment
195
195
  * method to run it" on a card-less Router repo, against a server that ran it.
@@ -198,13 +198,13 @@ export declare function routerProxyOptOut(ctx: {
198
198
  slug: string | null;
199
199
  secretNames: string[];
200
200
  }): boolean;
201
- /** whether a pick runs as its OpenRouter target: a proxied account (Router, the OSS subsidy)
202
- * mints for every pick `routerProxyOptOut` does not exempt. */
203
- export declare function pickUsesOpenRouter(params: {
201
+ /** the specifier a pick runs as: its OpenRouter target on a proxied account (Router, the OSS
202
+ * subsidy), which mints for every pick `routerProxyOptOut` does not exempt, else its direct one. */
203
+ export declare function resolvePickModel(params: {
204
204
  slug: string;
205
205
  proxied: boolean;
206
206
  secretNames: string[];
207
- }): boolean;
207
+ }): string | undefined;
208
208
  export declare const modelAliases: ModelAlias[];
209
209
  /**
210
210
  * `repo.model` sentinels for the two managed auto tiers. stored verbatim in
@@ -106,6 +106,7 @@ export interface ToolState {
106
106
  sha: string | undefined;
107
107
  url?: string | undefined;
108
108
  };
109
+ noReviewNeededSha?: string | undefined;
109
110
  reviewReplies?: Map<number, {
110
111
  commentId: number;
111
112
  url: string | undefined;
@@ -147,10 +148,11 @@ export interface ToolState {
147
148
  todoTracker?: TodoTracker | undefined;
148
149
  agentDiagnostic?: AgentDiagnostic | undefined;
149
150
  /**
150
- * a `PATCH /api/workflow-run/:id` came back 404 — the reservation was never
151
- * claimed, which is permanent for the life of the run (the claim happens at
152
- * setup, strictly before any PATCH). latched so the remaining calls stop
153
- * firing: one CI run spent 28 doomed round trips on it. see #1153.
151
+ * a `PATCH /api/workflow-run/:id` came back 404 — Pullfrog neither claimed a
152
+ * reservation for the run nor recorded it as a custom run, which is permanent for
153
+ * the life of the run (both happen at setup, strictly before any PATCH). latched so
154
+ * the remaining calls stop firing: one CI run spent 28 doomed round trips on it.
155
+ * see #1153.
154
156
  */
155
157
  workflowRunUnclaimed?: boolean | undefined;
156
158
  }
@@ -75,7 +75,7 @@ export declare function fetchIdTokenFromStash(creds: OidcCredentials): Promise<s
75
75
  * own retry still re-mints. Mid-run refreshes take the stashed-credentials path
76
76
  * (`opts.oidc`) and deliberately bypass this.
77
77
  */
78
- export declare const mintIdToken: yes.OpFunction<() => Promise<string>>;
78
+ export declare const mintIdToken: (() => Promise<string>) & yes.CacheMethods<undefined, undefined>;
79
79
  /**
80
80
  * ensure a GitHub token is available in the environment.
81
81
  *
@@ -9,6 +9,9 @@ import type { ToolContext } from "../mcp/server.ts";
9
9
  * `Repo.model` slug), PATCHed once at end-of-run so per-model cost analytics
10
10
  * don't parse the audit-only `payload`.
11
11
  * Keep in sync with `STRING_FIELDS` in `app/api/workflow-run/[runId]/route.ts`.
12
+ * `succeeded` and the usage fields below are this start's own report: a custom
13
+ * workflow can start the action several times in one run, and the server keeps
14
+ * one row per start, keyed by `START_KEY`, and sums them onto the run.
12
15
  */
13
16
  declare const STRING_KEYS: readonly ["prNodeId", "issueNodeId", "reviewNodeId", "planCommentNodeId", "summarySnapshot", "model", "agent", "credential"];
14
17
  /**
@@ -18,7 +21,11 @@ declare const STRING_KEYS: readonly ["prNodeId", "issueNodeId", "reviewNodeId",
18
21
  * amounts. Keep in sync with `INT_FIELDS` + `DECIMAL_FIELDS` in the server route.
19
22
  */
20
23
  declare const NUMBER_KEYS: readonly ["inputTokens", "outputTokens", "cacheReadTokens", "cacheWriteTokens", "costUsd"];
21
- export type WorkflowRunPatch = Partial<Record<(typeof STRING_KEYS)[number], string>> & Partial<Record<(typeof NUMBER_KEYS)[number], number>>;
24
+ /** one-way flags, only ever sent as `true`. Keep in sync with `BOOLEAN_FIELDS` in the server route. */
25
+ declare const FLAG_KEYS: readonly ["reviewSkipped"];
26
+ export type WorkflowRunPatch = Partial<Record<(typeof STRING_KEYS)[number], string>> & Partial<Record<(typeof NUMBER_KEYS)[number], number>> & Partial<Record<(typeof FLAG_KEYS)[number], true>> & {
27
+ succeeded?: boolean;
28
+ };
22
29
  /** PATCH workflow-run fields (Pullfrog JWT, not GitHub). */
23
30
  export declare function patchWorkflowRunFields(ctx: ToolContext, fields: WorkflowRunPatch): Promise<void>;
24
31
  /**
@@ -3,6 +3,11 @@ import type { RouterTier } from "../models.ts";
3
3
  import type { CommercialRefusal } from "./billingErrors.ts";
4
4
  import type { RepoContext } from "./github.ts";
5
5
  import type { CredentialAccess } from "./subscriptionCredentials.ts";
6
+ /**
7
+ * One per process, which is one start of the action within its GitHub run. Sent to run-context
8
+ * first, so a custom run's start is recorded before it reports, and then on each workflow-run PATCH.
9
+ */
10
+ export declare const START_KEY: `${string}-${string}-${string}-${string}-${string}`;
6
11
  export interface Mode {
7
12
  id: string;
8
13
  name: string;
@@ -108,6 +113,9 @@ export declare function fetchRunContext(params: {
108
113
  /** `payload.type` — lets the server apply this repo's per-trigger model
109
114
  * override, which it cannot derive from owner/repo alone. */
110
115
  runType?: string | undefined;
116
+ /** a plain-text prompt, which no Pullfrog dispatch sends — so the server
117
+ * can record this run without waiting for a reservation to claim it. */
118
+ plainPrompt: boolean;
111
119
  /** `payload.routing.tier` — the model router's tier, which run-context
112
120
  * applies to the Router proxy mint the same way it applies `runType`. */
113
121
  routedTier?: RouterTier | undefined;
@@ -37,6 +37,8 @@ interface ResolveRunContextDataParams {
37
37
  * because run-context is fetched first and needs it to pick this trigger's
38
38
  * model override. */
39
39
  runType?: string | undefined;
40
+ /** the prompt is plain text, never a Pullfrog dispatch payload. */
41
+ plainPrompt: boolean;
40
42
  /** the model router's tier from the payload, forwarded so run-context applies it to the proxy mint. */
41
43
  routedTier?: RouterTier | undefined;
42
44
  }
@@ -32,6 +32,14 @@
32
32
  * See wiki/review-approval.md.
33
33
  */
34
34
  export declare const RUN_STATUS_CHECK_NAME = "pullfrog";
35
+ /**
36
+ * GitHub's own Actions app. It publishes a check run per job, named after the
37
+ * job — and the generated workflow's job is also called `pullfrog`, so the
38
+ * collision is structural rather than incidental. Renaming our check is not
39
+ * available: it was tried on 2026-08-02 and blocked merges on four customer
40
+ * repos (see above), so the reuse lookup filters instead. See #1196.
41
+ */
42
+ export declare const GITHUB_ACTIONS_APP_SLUG = "github-actions";
35
43
  /** the review-verdict check. opt-in, terminal-only, and deliberately separate from the above. */
36
44
  export declare const APPROVAL_CHECK_NAME = "pullfrog-approval";
37
45
  /**
@@ -147,6 +155,8 @@ export declare function finalizeRunStatusCheck(params: {
147
155
  conclusion: RunStatusCheckConclusion;
148
156
  detailsUrl: string | undefined;
149
157
  reviewUrl?: string | undefined;
158
+ /** the run's own final report, shown on success when nothing else carries it. */
159
+ note?: string | undefined;
150
160
  }): Promise<void>;
151
161
  /**
152
162
  * Post an already-terminal check-run in one call.
@@ -163,6 +173,7 @@ export declare function createTerminalRunStatusCheck(params: {
163
173
  conclusion: RunStatusCheckConclusion;
164
174
  detailsUrl: string | undefined;
165
175
  reviewUrl?: string | undefined;
176
+ note?: string | undefined;
166
177
  }): Promise<void>;
167
178
  /**
168
179
  * Whether this check still needs finalizing.
@@ -11,7 +11,8 @@ import type { ToolContext } from "../mcp/server.ts";
11
11
  * - `pullfrog-approval` stays opt-in (`Repo.approvalCheck`, default off) and terminal-only:
12
12
  * it asserts a review verdict, which only exists once a run produces one. anchored
13
13
  * to the exact reviewed sha so a mid-run push leaves the new head unapproved until
14
- * a follow-up re-review reports.
14
+ * a follow-up re-review reports. a re-review that submits no review carries the
15
+ * prior verdict forward instead (see `carriedApproval`).
15
16
  *
16
17
  * best-effort throughout: a check-post failure (transient 5xx, closed PR, revoked
17
18
  * permission) must never flip the run's own outcome. the `workflow_run.completed` webhook
@@ -12,6 +12,7 @@ export declare class SpawnTimeoutError extends Error {
12
12
  export type SignalHandler = (signal: NodeJS.Signals) => void;
13
13
  export declare function trackChild(options: TrackChildOptions): void;
14
14
  export declare function untrackChild(child: ChildProcess): void;
15
+ export declare function isTrackedChild(child: ChildProcess): boolean;
15
16
  export declare function setSignalHandler(handler: SignalHandler | null): void;
16
17
  export declare function killTrackedChildren(): void;
17
18
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.94",
3
+ "version": "0.1.96",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {
@@ -66,7 +66,7 @@
66
66
  "undici": "^7.22.0",
67
67
  "vitest": "^4.0.17",
68
68
  "yaml": "^2.8.2",
69
- "yes": "0.0.3",
69
+ "yes": "0.2.3",
70
70
  "zod": "4.3.6"
71
71
  },
72
72
  "repository": {