pullfrog 0.1.74 → 0.1.76

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, ProviderConfig, PushPermission, ShellPermission, ToolPermission, WriteablePayload, XrepoConfig, } from "../external.ts";
9
- export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, modelAliases, modelHasStoredAuth, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, ossFundedModelNames, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, rungLabel, rungPosition, SUBSIDY_RUNG, } from "../external.ts";
9
+ export { AUTO_EFFICIENT, AUTO_INTELLIGENT, DEFAULT_EFFORT_POSITION, DEFAULT_PROXY_MODEL, defaultAutoTier, EFFORT_ALIASES, getAutoSelectHintModel, getModelEffortLevels, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, isAutoTier, isCardGatedModel, isEffortPosition, isOssAllowedModel, modelAliases, modelHasStoredAuth, OSS_MODEL_ALLOWLIST, OSS_RECOMMENDED_MODEL, offeredRungs, ossFundedModelNames, PROVIDER_GATEWAY_URL_ENV, parseEffortPosition, parseModel, providers, pullfrogMcpName, resolveAutoTier, resolveCliModel, resolveDisplayAlias, resolveModelRung, resolveModelSlug, resolveOpenRouterModel, resolveRung, 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 { 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.74",
11
+ version: "0.1.76",
12
12
  cliContractVersion: "1",
13
13
  type: "module",
14
14
  bin: {
@@ -628,7 +628,7 @@ __export(core_exports2, {
628
628
  parse: () => parse,
629
629
  parseAsync: () => parseAsync,
630
630
  prettifyError: () => prettifyError,
631
- process: () => process,
631
+ process: () => process2,
632
632
  regexes: () => regexes_exports,
633
633
  registry: () => registry,
634
634
  safeDecode: () => safeDecode,
@@ -11029,7 +11029,7 @@ function initializeContext(params) {
11029
11029
  external: params?.external ?? void 0
11030
11030
  };
11031
11031
  }
11032
- function process(schema, ctx, _params = { path: [], schemaPath: [] }) {
11032
+ function process2(schema, ctx, _params = { path: [], schemaPath: [] }) {
11033
11033
  var _a2;
11034
11034
  const def = schema._zod.def;
11035
11035
  const seen = ctx.seen.get(schema);
@@ -11066,7 +11066,7 @@ function process(schema, ctx, _params = { path: [], schemaPath: [] }) {
11066
11066
  if (parent) {
11067
11067
  if (!result.ref)
11068
11068
  result.ref = parent;
11069
- process(parent, ctx, params);
11069
+ process2(parent, ctx, params);
11070
11070
  ctx.seen.get(parent).isParent = true;
11071
11071
  }
11072
11072
  }
@@ -11347,14 +11347,14 @@ function isTransforming(_schema, _ctx) {
11347
11347
  }
11348
11348
  var createToJSONSchemaMethod = (schema, processors = {}) => (params) => {
11349
11349
  const ctx = initializeContext({ ...params, processors });
11350
- process(schema, ctx);
11350
+ process2(schema, ctx);
11351
11351
  extractDefs(ctx, schema);
11352
11352
  return finalize(ctx, schema);
11353
11353
  };
11354
11354
  var createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params) => {
11355
11355
  const { libraryOptions, target } = params ?? {};
11356
11356
  const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors });
11357
- process(schema, ctx);
11357
+ process2(schema, ctx);
11358
11358
  extractDefs(ctx, schema);
11359
11359
  return finalize(ctx, schema);
11360
11360
  };
@@ -11611,7 +11611,7 @@ var arrayProcessor = (schema, ctx, _json, params) => {
11611
11611
  if (typeof maximum === "number")
11612
11612
  json2.maxItems = maximum;
11613
11613
  json2.type = "array";
11614
- json2.items = process(def.element, ctx, { ...params, path: [...params.path, "items"] });
11614
+ json2.items = process2(def.element, ctx, { ...params, path: [...params.path, "items"] });
11615
11615
  };
11616
11616
  var objectProcessor = (schema, ctx, _json, params) => {
11617
11617
  const json2 = _json;
@@ -11620,7 +11620,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
11620
11620
  json2.properties = {};
11621
11621
  const shape = def.shape;
11622
11622
  for (const key in shape) {
11623
- json2.properties[key] = process(shape[key], ctx, {
11623
+ json2.properties[key] = process2(shape[key], ctx, {
11624
11624
  ...params,
11625
11625
  path: [...params.path, "properties", key]
11626
11626
  });
@@ -11643,7 +11643,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
11643
11643
  if (ctx.io === "output")
11644
11644
  json2.additionalProperties = false;
11645
11645
  } else if (def.catchall) {
11646
- json2.additionalProperties = process(def.catchall, ctx, {
11646
+ json2.additionalProperties = process2(def.catchall, ctx, {
11647
11647
  ...params,
11648
11648
  path: [...params.path, "additionalProperties"]
11649
11649
  });
@@ -11652,7 +11652,7 @@ var objectProcessor = (schema, ctx, _json, params) => {
11652
11652
  var unionProcessor = (schema, ctx, json2, params) => {
11653
11653
  const def = schema._zod.def;
11654
11654
  const isExclusive = def.inclusive === false;
11655
- const options = def.options.map((x, i) => process(x, ctx, {
11655
+ const options = def.options.map((x, i) => process2(x, ctx, {
11656
11656
  ...params,
11657
11657
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
11658
11658
  }));
@@ -11664,11 +11664,11 @@ var unionProcessor = (schema, ctx, json2, params) => {
11664
11664
  };
11665
11665
  var intersectionProcessor = (schema, ctx, json2, params) => {
11666
11666
  const def = schema._zod.def;
11667
- const a = process(def.left, ctx, {
11667
+ const a = process2(def.left, ctx, {
11668
11668
  ...params,
11669
11669
  path: [...params.path, "allOf", 0]
11670
11670
  });
11671
- const b = process(def.right, ctx, {
11671
+ const b = process2(def.right, ctx, {
11672
11672
  ...params,
11673
11673
  path: [...params.path, "allOf", 1]
11674
11674
  });
@@ -11685,11 +11685,11 @@ var tupleProcessor = (schema, ctx, _json, params) => {
11685
11685
  json2.type = "array";
11686
11686
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
11687
11687
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
11688
- const prefixItems = def.items.map((x, i) => process(x, ctx, {
11688
+ const prefixItems = def.items.map((x, i) => process2(x, ctx, {
11689
11689
  ...params,
11690
11690
  path: [...params.path, prefixPath, i]
11691
11691
  }));
11692
- const rest = def.rest ? process(def.rest, ctx, {
11692
+ const rest = def.rest ? process2(def.rest, ctx, {
11693
11693
  ...params,
11694
11694
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
11695
11695
  }) : null;
@@ -11729,7 +11729,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
11729
11729
  const keyBag = keyType._zod.bag;
11730
11730
  const patterns = keyBag?.patterns;
11731
11731
  if (def.mode === "loose" && patterns && patterns.size > 0) {
11732
- const valueSchema = process(def.valueType, ctx, {
11732
+ const valueSchema = process2(def.valueType, ctx, {
11733
11733
  ...params,
11734
11734
  path: [...params.path, "patternProperties", "*"]
11735
11735
  });
@@ -11739,12 +11739,12 @@ var recordProcessor = (schema, ctx, _json, params) => {
11739
11739
  }
11740
11740
  } else {
11741
11741
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
11742
- json2.propertyNames = process(def.keyType, ctx, {
11742
+ json2.propertyNames = process2(def.keyType, ctx, {
11743
11743
  ...params,
11744
11744
  path: [...params.path, "propertyNames"]
11745
11745
  });
11746
11746
  }
11747
- json2.additionalProperties = process(def.valueType, ctx, {
11747
+ json2.additionalProperties = process2(def.valueType, ctx, {
11748
11748
  ...params,
11749
11749
  path: [...params.path, "additionalProperties"]
11750
11750
  });
@@ -11759,7 +11759,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
11759
11759
  };
11760
11760
  var nullableProcessor = (schema, ctx, json2, params) => {
11761
11761
  const def = schema._zod.def;
11762
- const inner = process(def.innerType, ctx, params);
11762
+ const inner = process2(def.innerType, ctx, params);
11763
11763
  const seen = ctx.seen.get(schema);
11764
11764
  if (ctx.target === "openapi-3.0") {
11765
11765
  seen.ref = def.innerType;
@@ -11770,20 +11770,20 @@ var nullableProcessor = (schema, ctx, json2, params) => {
11770
11770
  };
11771
11771
  var nonoptionalProcessor = (schema, ctx, _json, params) => {
11772
11772
  const def = schema._zod.def;
11773
- process(def.innerType, ctx, params);
11773
+ process2(def.innerType, ctx, params);
11774
11774
  const seen = ctx.seen.get(schema);
11775
11775
  seen.ref = def.innerType;
11776
11776
  };
11777
11777
  var defaultProcessor = (schema, ctx, json2, params) => {
11778
11778
  const def = schema._zod.def;
11779
- process(def.innerType, ctx, params);
11779
+ process2(def.innerType, ctx, params);
11780
11780
  const seen = ctx.seen.get(schema);
11781
11781
  seen.ref = def.innerType;
11782
11782
  json2.default = JSON.parse(JSON.stringify(def.defaultValue));
11783
11783
  };
11784
11784
  var prefaultProcessor = (schema, ctx, json2, params) => {
11785
11785
  const def = schema._zod.def;
11786
- process(def.innerType, ctx, params);
11786
+ process2(def.innerType, ctx, params);
11787
11787
  const seen = ctx.seen.get(schema);
11788
11788
  seen.ref = def.innerType;
11789
11789
  if (ctx.io === "input")
@@ -11791,7 +11791,7 @@ var prefaultProcessor = (schema, ctx, json2, params) => {
11791
11791
  };
11792
11792
  var catchProcessor = (schema, ctx, json2, params) => {
11793
11793
  const def = schema._zod.def;
11794
- process(def.innerType, ctx, params);
11794
+ process2(def.innerType, ctx, params);
11795
11795
  const seen = ctx.seen.get(schema);
11796
11796
  seen.ref = def.innerType;
11797
11797
  let catchValue;
@@ -11805,32 +11805,32 @@ var catchProcessor = (schema, ctx, json2, params) => {
11805
11805
  var pipeProcessor = (schema, ctx, _json, params) => {
11806
11806
  const def = schema._zod.def;
11807
11807
  const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
11808
- process(innerType, ctx, params);
11808
+ process2(innerType, ctx, params);
11809
11809
  const seen = ctx.seen.get(schema);
11810
11810
  seen.ref = innerType;
11811
11811
  };
11812
11812
  var readonlyProcessor = (schema, ctx, json2, params) => {
11813
11813
  const def = schema._zod.def;
11814
- process(def.innerType, ctx, params);
11814
+ process2(def.innerType, ctx, params);
11815
11815
  const seen = ctx.seen.get(schema);
11816
11816
  seen.ref = def.innerType;
11817
11817
  json2.readOnly = true;
11818
11818
  };
11819
11819
  var promiseProcessor = (schema, ctx, _json, params) => {
11820
11820
  const def = schema._zod.def;
11821
- process(def.innerType, ctx, params);
11821
+ process2(def.innerType, ctx, params);
11822
11822
  const seen = ctx.seen.get(schema);
11823
11823
  seen.ref = def.innerType;
11824
11824
  };
11825
11825
  var optionalProcessor = (schema, ctx, _json, params) => {
11826
11826
  const def = schema._zod.def;
11827
- process(def.innerType, ctx, params);
11827
+ process2(def.innerType, ctx, params);
11828
11828
  const seen = ctx.seen.get(schema);
11829
11829
  seen.ref = def.innerType;
11830
11830
  };
11831
11831
  var lazyProcessor = (schema, ctx, _json, params) => {
11832
11832
  const innerType = schema._zod.innerType;
11833
- process(innerType, ctx, params);
11833
+ process2(innerType, ctx, params);
11834
11834
  const seen = ctx.seen.get(schema);
11835
11835
  seen.ref = innerType;
11836
11836
  };
@@ -11882,7 +11882,7 @@ function toJSONSchema(input, params) {
11882
11882
  const defs = {};
11883
11883
  for (const entry of registry2._idmap.entries()) {
11884
11884
  const [_, schema] = entry;
11885
- process(schema, ctx2);
11885
+ process2(schema, ctx2);
11886
11886
  }
11887
11887
  const schemas = {};
11888
11888
  const external = {
@@ -11905,7 +11905,7 @@ function toJSONSchema(input, params) {
11905
11905
  return { schemas };
11906
11906
  }
11907
11907
  const ctx = initializeContext({ ...params, processors: allProcessors });
11908
- process(input, ctx);
11908
+ process2(input, ctx);
11909
11909
  extractDefs(ctx, input);
11910
11910
  return finalize(ctx, input);
11911
11911
  }
@@ -11963,7 +11963,7 @@ var JSONSchemaGenerator = class {
11963
11963
  * This must be called before emit().
11964
11964
  */
11965
11965
  process(schema, _params = { path: [], schemaPath: [] }) {
11966
- return process(schema, this.ctx, _params);
11966
+ return process2(schema, this.ctx, _params);
11967
11967
  }
11968
11968
  /**
11969
11969
  * Emit the final JSON Schema after processing.
@@ -14023,6 +14023,20 @@ var repoConfigFields = [
14023
14023
  nullable: true,
14024
14024
  description: "additional instructions for planning"
14025
14025
  },
14026
+ {
14027
+ key: "prompts.address-reviews",
14028
+ field: "AddressReviews",
14029
+ kind: "prompt",
14030
+ nullable: true,
14031
+ description: "additional instructions for addressing review feedback"
14032
+ },
14033
+ {
14034
+ key: "prompts.fix-ci",
14035
+ field: "Fix",
14036
+ kind: "prompt",
14037
+ nullable: true,
14038
+ description: "additional instructions for fixing CI failures"
14039
+ },
14026
14040
  { key: "mention.enabled", field: "mention", kind: "toggle", description: "respond to mentions" },
14027
14041
  {
14028
14042
  key: "mention.instructions",
@@ -15529,6 +15543,10 @@ function isOssAllowedModel(slug) {
15529
15543
  function getAutoSelectHintModel() {
15530
15544
  return defaultProxyDisplayName;
15531
15545
  }
15546
+ var PROVIDER_GATEWAY_URL_ENV = {
15547
+ anthropic: "ANTHROPIC_BASE_URL",
15548
+ openai: "OPENAI_BASE_URL"
15549
+ };
15532
15550
 
15533
15551
  // external.ts
15534
15552
  var pullfrogMcpName = "pullfrog";
@@ -15661,26 +15679,24 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
15661
15679
 
15662
15680
  2. Checkout the PR branch via \`${t("checkout_pr")}\`.
15663
15681
 
15664
- 3. Fetch review comments via \`${t("get_review_comments")}\`.
15682
+ 3. Fetch review comments via \`${t("get_review_comments")}\` and read the full conversation in each relevant thread.
15665
15683
 
15666
- 4. For each comment:
15667
- - understand the feedback
15684
+ 4. For each thread:
15685
+ - **check intent first**: questions, explanations, and disagreement call for a reply, not a code change. Change code only when explicitly requested. Automatic review feedback on Pullfrog-authored PRs (\`address_scope: all\`) remains actionable without a separate request; later replies can narrow or withdraw that permission.
15686
+ - under \`address_scope: mentions\`, unmentioned threads are context only unless the user's review-body request explicitly includes them
15668
15687
  - **verify the finding yourself** against the actual code before deciding whether to apply \u2014 every comment (human or agent) is a hypothesis, not a directive. agent reviewers especially are fallible.
15669
- - you are searching for a solution that is **complete, minimal, and elegant** \u2014 you may need to think hard to find it. do not over-engineer, do not be over-defensive, **do not write AI slop**. reviewers bias toward *recommending additions*, and that bias has a recognizable slop texture: defensive checks for impossible cases, extra abstractions used once, comments restating obvious code, tests asserting tautologies, "just-in-case" guards, error handlers for cases the type system already rules out. reject those. evaluate whether applying the finding would leave the code more **sound, correct, AND elegant**; two-out-of-three is a signal to look harder for a fix that gets all three. if a request would add bloat \u2014 ceremony without commensurate correctness benefit \u2014 push back in your reply rather than mechanically applying it.
15670
- - if the request stands, make the code change using your native tools; otherwise reply explaining why
15688
+ - keep requested changes **sound, minimal, and elegant**. Reject defensive checks for impossible cases, single-use abstractions, redundant comments, and tautological tests rather than mechanically applying reviewer suggestions.
15689
+ - if intent permits a code change and the finding stands, implement it using your native tools; otherwise reply without editing
15671
15690
  - record what was done (or why nothing was done)
15672
15691
 
15673
15692
  5. Quality check:
15674
- - re-call \`${t("get_review_comments")}\` with \`fresh: true\` before committing: reviewers keep commenting while you work, and any thread it now returns that you have not addressed is in scope for this run.
15675
- - test changes, then review the diff before committing \u2014 verify only intended changes are present, no debug artifacts remain, no fix turned out to be bloat in context (revert any that did), and the changes are clean enough that a senior engineer would approve without hesitation
15676
- - ${commitStep}
15693
+ - re-call \`${t("get_review_comments")}\` with \`fresh: true\` before finishing, even when only replying. Apply the same scope and intent checks to new comments; respect requests to stop or change direction before committing.
15694
+ - if code changed, test and review the diff, remove unintended changes or bloat, then ${commitStep}
15677
15695
 
15678
- 6. Finalize. Reply + resolve are paired write actions: do BOTH or NEITHER for each thread.
15679
- - ${finalizeStep} (same push/prepush guidance as Build mode in *SYSTEM*)
15680
- - **if the push/commit fails**, call \`${t("report_progress")}\` with the exact error and STOP \u2014 do NOT reply or resolve any thread until the fix is live on the remote. Resolving a thread without the fix landing misleads the reviewer.
15681
- - **once the fix is live on the remote**, for each thread you acted on:
15682
- - reply ONCE via \`${t("reply_to_review_comment")}\`. The \`comment_id\` parameter takes the root comment's numeric \`id=\` (from the first \`comment author=...\` tag in the \`${t("get_review_comments")}\` output) \u2014 NOT the \`thread=\` value; that's a separate GraphQL ID used by resolve. The runtime dedupes identical bodies within a session.
15683
- - **immediately** call \`${t("resolve_review_thread")}\` with that thread's \`thread=\` value as \`thread_id\`. Resolve every thread where you (a) made the requested code change in full \u2014 partial fixes leave the thread open \u2014 OR (b) replied with a substantive answer the user explicitly asked for. Do NOT resolve threads where you pushed back on the request and the disagreement is unresolved; leave those open for the human to mediate.
15696
+ 6. Finalize:
15697
+ - **only if code changed**, ${finalizeStep} (same push/prepush guidance as Build mode in *SYSTEM*). If push/commit fails, report the exact error and STOP without claiming a fix or resolving its threads.
15698
+ - reply ONCE per relevant thread via \`${t("reply_to_review_comment")}\`, including when no code changed. The \`comment_id\` is the root comment's numeric \`id=\`, NOT the \`thread=\` value from \`${t("get_review_comments")}\`. The runtime dedupes identical bodies within a session.
15699
+ - resolve a thread via \`${t("resolve_review_thread")}\` (using \`thread=\` as \`thread_id\`) only after its requested fix is fully on the remote, or the user explicitly asks to resolve it. Leave discussion-only replies, partial fixes, and disagreements open.
15684
15700
  - call \`${t("report_progress")}\` with a brief summary. If your last \`${t("get_review_comments")}\` turned up threads you did not address, name them there \u2014 a review arriving this late is suppressed as a duplicate and nothing else will pick it up.`
15685
15701
  },
15686
15702
  // Review and IncrementalReview route the minimum reviewfrog specialists
@@ -16594,6 +16610,7 @@ export {
16594
16610
  OAuthInvalidGrantError,
16595
16611
  OSS_MODEL_ALLOWLIST,
16596
16612
  OSS_RECOMMENDED_MODEL,
16613
+ PROVIDER_GATEWAY_URL_ENV,
16597
16614
  PULLFROG_DIVIDER,
16598
16615
  RUN_STATUS_CHECK_NAME,
16599
16616
  SUBSIDY_RUNG,
@@ -32,6 +32,11 @@ export declare function runSandboxed(params: {
32
32
  env: Record<string, string | undefined>;
33
33
  cwd: string;
34
34
  timeout: number;
35
+ /** live-stream chunks as they arrive, on top of the buffered `output`.
36
+ * lifecycle hooks use this to keep a long `pnpm test` visible in the
37
+ * workflow log instead of silent until it exits. */
38
+ onStdout?: (chunk: string) => void;
39
+ onStderr?: (chunk: string) => void;
35
40
  }): Promise<{
36
41
  output: string;
37
42
  exitCode: number;
package/dist/models.d.ts CHANGED
@@ -376,6 +376,27 @@ export declare const OPENAI_COMPATIBLE_CONTEXT_ENV = "OPENAI_COMPATIBLE_CONTEXT"
376
376
  * `context` + `output` together, so the pair is validated and emitted as a unit.
377
377
  */
378
378
  export declare const OPENAI_COMPATIBLE_MAX_OUTPUT_ENV = "OPENAI_COMPATIBLE_MAX_OUTPUT";
379
+ /**
380
+ * Providers whose endpoint can be re-pointed at a customer gateway, and the env
381
+ * var that does it. Deliberately a short explicit map rather than a derived
382
+ * `<PROVIDER>_BASE_URL` rule: only a provider we have confirmed reachable
383
+ * through a proxy belongs here, and three of them must never be.
384
+ * `openai-compatible` already owns its endpoint via OPENAI_COMPATIBLE_BASE_URL,
385
+ * `azure` derives one from AZURE_RESOURCE_NAME, and bedrock/vertex authenticate
386
+ * against a cloud SDK rather than a URL.
387
+ *
388
+ * models.dev declares no base-URL env var for any catalogued provider (2 of 213
389
+ * do, and neither is one of these), so nothing reads these names on its own —
390
+ * `providerGatewayOverride` is what makes them mean anything to opencode and
391
+ * `gatewayProvider` to codex, while claude-code reads ANTHROPIC_BASE_URL itself.
392
+ *
393
+ * Adding a provider that ALREADY has a block in `buildSecurityConfig` needs a
394
+ * merge, not an entry here: that spread replaces the whole key, so listing
395
+ * `openrouter` would silently drop `kimiOpenRouterProviderOverrides()`.
396
+ */
397
+ export declare const PROVIDER_GATEWAY_URL_ENV: Record<string, string>;
398
+ /** the customer gateway a model's provider is re-pointed at, if any. */
399
+ export declare function getProviderGatewayUrl(specifier: string | undefined): string | undefined;
379
400
  /**
380
401
  * the Bedrock model ID passed to claude-code or opencode is whatever the
381
402
  * user set in `BEDROCK_MODEL_ID` — Pullfrog never resolves or upgrades it.
@@ -1,6 +1,19 @@
1
+ import type { ShellPermission } from "../external.ts";
1
2
  export interface ExecuteLifecycleHookParams {
2
3
  event: string;
3
4
  script: string | null;
5
+ /**
6
+ * the repo's shell permission, which decides the hook's environment on the
7
+ * same terms as the `shell` tool: `enabled` inherits the full process env,
8
+ * anything else gets the default-deny allowlist (safe set + the repo's
9
+ * `envAllowlist`).
10
+ *
11
+ * hooks are maintainer-authored, but the code they invoke is not — after
12
+ * `checkout_pr` on a fork PR, a `prepushScript` of `pnpm test` runs the
13
+ * contributor's script and test files. so the hook is treated as untrusted
14
+ * execution and gets the same sandbox + env scrub as `shell`.
15
+ */
16
+ shell: ShellPermission;
4
17
  /**
5
18
  * when true, after the hook runs (success or failure), discard tracked-file
6
19
  * mods so the agent doesn't see hook-generated drift (e.g. `pnpm install`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.74",
3
+ "version": "0.1.76",
4
4
  "cliContractVersion": "1",
5
5
  "type": "module",
6
6
  "bin": {