pullfrog 0.1.51 → 0.1.53

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
@@ -3871,9 +3871,9 @@ var require_constants2 = __commonJS({
3871
3871
  }
3872
3872
  })();
3873
3873
  var channel;
3874
- var structuredClone = globalThis.structuredClone ?? // https://github.com/nodejs/node/blob/b27ae24dcc4251bad726d9d84baf678d1f707fed/lib/internal/structured_clone.js
3874
+ var structuredClone2 = globalThis.structuredClone ?? // https://github.com/nodejs/node/blob/b27ae24dcc4251bad726d9d84baf678d1f707fed/lib/internal/structured_clone.js
3875
3875
  // structuredClone was added in v17.0.0, but fetch supports v16.8
3876
- function structuredClone2(value2, options = void 0) {
3876
+ function structuredClone3(value2, options = void 0) {
3877
3877
  if (arguments.length === 0) {
3878
3878
  throw new TypeError("missing argument");
3879
3879
  }
@@ -3887,7 +3887,7 @@ var require_constants2 = __commonJS({
3887
3887
  };
3888
3888
  module.exports = {
3889
3889
  DOMException: DOMException2,
3890
- structuredClone,
3890
+ structuredClone: structuredClone2,
3891
3891
  subresource,
3892
3892
  forbiddenMethods,
3893
3893
  requestBodyHeader,
@@ -5592,7 +5592,7 @@ var require_body = __commonJS({
5592
5592
  var { FormData: FormData2 } = require_formdata();
5593
5593
  var { kState } = require_symbols2();
5594
5594
  var { webidl } = require_webidl();
5595
- var { DOMException: DOMException2, structuredClone } = require_constants2();
5595
+ var { DOMException: DOMException2, structuredClone: structuredClone2 } = require_constants2();
5596
5596
  var { Blob: Blob2, File: NativeFile } = __require("buffer");
5597
5597
  var { kBodyUsed } = require_symbols();
5598
5598
  var assert3 = __require("assert");
@@ -5756,7 +5756,7 @@ Content-Type: ${value2.type || "application/octet-stream"}\r
5756
5756
  }
5757
5757
  function cloneBody(body) {
5758
5758
  const [out1, out2] = body.stream.tee();
5759
- const out2Clone = structuredClone(out2, { transfer: [out2] });
5759
+ const out2Clone = structuredClone2(out2, { transfer: [out2] });
5760
5760
  const [, finalClone] = out2Clone.tee();
5761
5761
  body.stream = out1;
5762
5762
  return {
@@ -20066,10 +20066,10 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``);
20066
20066
  (0, command_1.issueCommand)("error", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
20067
20067
  }
20068
20068
  exports.error = error49;
20069
- function warning2(message, properties = {}) {
20069
+ function warning3(message, properties = {}) {
20070
20070
  (0, command_1.issueCommand)("warning", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
20071
20071
  }
20072
- exports.warning = warning2;
20072
+ exports.warning = warning3;
20073
20073
  function notice(message, properties = {}) {
20074
20074
  (0, command_1.issueCommand)("notice", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message);
20075
20075
  }
@@ -66680,7 +66680,7 @@ function initializeContext(params) {
66680
66680
  external: params?.external ?? void 0
66681
66681
  };
66682
66682
  }
66683
- function process2(schema2, ctx, _params = { path: [], schemaPath: [] }) {
66683
+ function process3(schema2, ctx, _params = { path: [], schemaPath: [] }) {
66684
66684
  var _a2;
66685
66685
  const def = schema2._zod.def;
66686
66686
  const seen = ctx.seen.get(schema2);
@@ -66717,7 +66717,7 @@ function process2(schema2, ctx, _params = { path: [], schemaPath: [] }) {
66717
66717
  if (parent) {
66718
66718
  if (!result.ref)
66719
66719
  result.ref = parent;
66720
- process2(parent, ctx, params);
66720
+ process3(parent, ctx, params);
66721
66721
  ctx.seen.get(parent).isParent = true;
66722
66722
  }
66723
66723
  }
@@ -67002,14 +67002,14 @@ var init_to_json_schema = __esm({
67002
67002
  init_registries();
67003
67003
  createToJSONSchemaMethod = (schema2, processors = {}) => (params) => {
67004
67004
  const ctx = initializeContext({ ...params, processors });
67005
- process2(schema2, ctx);
67005
+ process3(schema2, ctx);
67006
67006
  extractDefs(ctx, schema2);
67007
67007
  return finalize(ctx, schema2);
67008
67008
  };
67009
67009
  createStandardJSONSchemaMethod = (schema2, io, processors = {}) => (params) => {
67010
67010
  const { libraryOptions, target } = params ?? {};
67011
67011
  const ctx = initializeContext({ ...libraryOptions ?? {}, target, io, processors });
67012
- process2(schema2, ctx);
67012
+ process3(schema2, ctx);
67013
67013
  extractDefs(ctx, schema2);
67014
67014
  return finalize(ctx, schema2);
67015
67015
  };
@@ -67024,7 +67024,7 @@ function toJSONSchema(input, params) {
67024
67024
  const defs = {};
67025
67025
  for (const entry of registry4._idmap.entries()) {
67026
67026
  const [_2, schema2] = entry;
67027
- process2(schema2, ctx2);
67027
+ process3(schema2, ctx2);
67028
67028
  }
67029
67029
  const schemas = {};
67030
67030
  const external = {
@@ -67047,7 +67047,7 @@ function toJSONSchema(input, params) {
67047
67047
  return { schemas };
67048
67048
  }
67049
67049
  const ctx = initializeContext({ ...params, processors: allProcessors });
67050
- process2(input, ctx);
67050
+ process3(input, ctx);
67051
67051
  extractDefs(ctx, input);
67052
67052
  return finalize(ctx, input);
67053
67053
  }
@@ -67307,7 +67307,7 @@ var init_json_schema_processors = __esm({
67307
67307
  if (typeof maximum === "number")
67308
67308
  json4.maxItems = maximum;
67309
67309
  json4.type = "array";
67310
- json4.items = process2(def.element, ctx, { ...params, path: [...params.path, "items"] });
67310
+ json4.items = process3(def.element, ctx, { ...params, path: [...params.path, "items"] });
67311
67311
  };
67312
67312
  objectProcessor = (schema2, ctx, _json, params) => {
67313
67313
  const json4 = _json;
@@ -67316,7 +67316,7 @@ var init_json_schema_processors = __esm({
67316
67316
  json4.properties = {};
67317
67317
  const shape = def.shape;
67318
67318
  for (const key in shape) {
67319
- json4.properties[key] = process2(shape[key], ctx, {
67319
+ json4.properties[key] = process3(shape[key], ctx, {
67320
67320
  ...params,
67321
67321
  path: [...params.path, "properties", key]
67322
67322
  });
@@ -67339,7 +67339,7 @@ var init_json_schema_processors = __esm({
67339
67339
  if (ctx.io === "output")
67340
67340
  json4.additionalProperties = false;
67341
67341
  } else if (def.catchall) {
67342
- json4.additionalProperties = process2(def.catchall, ctx, {
67342
+ json4.additionalProperties = process3(def.catchall, ctx, {
67343
67343
  ...params,
67344
67344
  path: [...params.path, "additionalProperties"]
67345
67345
  });
@@ -67348,7 +67348,7 @@ var init_json_schema_processors = __esm({
67348
67348
  unionProcessor = (schema2, ctx, json4, params) => {
67349
67349
  const def = schema2._zod.def;
67350
67350
  const isExclusive = def.inclusive === false;
67351
- const options = def.options.map((x, i) => process2(x, ctx, {
67351
+ const options = def.options.map((x, i) => process3(x, ctx, {
67352
67352
  ...params,
67353
67353
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
67354
67354
  }));
@@ -67360,11 +67360,11 @@ var init_json_schema_processors = __esm({
67360
67360
  };
67361
67361
  intersectionProcessor = (schema2, ctx, json4, params) => {
67362
67362
  const def = schema2._zod.def;
67363
- const a = process2(def.left, ctx, {
67363
+ const a = process3(def.left, ctx, {
67364
67364
  ...params,
67365
67365
  path: [...params.path, "allOf", 0]
67366
67366
  });
67367
- const b = process2(def.right, ctx, {
67367
+ const b = process3(def.right, ctx, {
67368
67368
  ...params,
67369
67369
  path: [...params.path, "allOf", 1]
67370
67370
  });
@@ -67381,11 +67381,11 @@ var init_json_schema_processors = __esm({
67381
67381
  json4.type = "array";
67382
67382
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
67383
67383
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
67384
- const prefixItems = def.items.map((x, i) => process2(x, ctx, {
67384
+ const prefixItems = def.items.map((x, i) => process3(x, ctx, {
67385
67385
  ...params,
67386
67386
  path: [...params.path, prefixPath, i]
67387
67387
  }));
67388
- const rest = def.rest ? process2(def.rest, ctx, {
67388
+ const rest = def.rest ? process3(def.rest, ctx, {
67389
67389
  ...params,
67390
67390
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
67391
67391
  }) : null;
@@ -67425,7 +67425,7 @@ var init_json_schema_processors = __esm({
67425
67425
  const keyBag = keyType._zod.bag;
67426
67426
  const patterns = keyBag?.patterns;
67427
67427
  if (def.mode === "loose" && patterns && patterns.size > 0) {
67428
- const valueSchema = process2(def.valueType, ctx, {
67428
+ const valueSchema = process3(def.valueType, ctx, {
67429
67429
  ...params,
67430
67430
  path: [...params.path, "patternProperties", "*"]
67431
67431
  });
@@ -67435,12 +67435,12 @@ var init_json_schema_processors = __esm({
67435
67435
  }
67436
67436
  } else {
67437
67437
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
67438
- json4.propertyNames = process2(def.keyType, ctx, {
67438
+ json4.propertyNames = process3(def.keyType, ctx, {
67439
67439
  ...params,
67440
67440
  path: [...params.path, "propertyNames"]
67441
67441
  });
67442
67442
  }
67443
- json4.additionalProperties = process2(def.valueType, ctx, {
67443
+ json4.additionalProperties = process3(def.valueType, ctx, {
67444
67444
  ...params,
67445
67445
  path: [...params.path, "additionalProperties"]
67446
67446
  });
@@ -67455,7 +67455,7 @@ var init_json_schema_processors = __esm({
67455
67455
  };
67456
67456
  nullableProcessor = (schema2, ctx, json4, params) => {
67457
67457
  const def = schema2._zod.def;
67458
- const inner = process2(def.innerType, ctx, params);
67458
+ const inner = process3(def.innerType, ctx, params);
67459
67459
  const seen = ctx.seen.get(schema2);
67460
67460
  if (ctx.target === "openapi-3.0") {
67461
67461
  seen.ref = def.innerType;
@@ -67466,20 +67466,20 @@ var init_json_schema_processors = __esm({
67466
67466
  };
67467
67467
  nonoptionalProcessor = (schema2, ctx, _json, params) => {
67468
67468
  const def = schema2._zod.def;
67469
- process2(def.innerType, ctx, params);
67469
+ process3(def.innerType, ctx, params);
67470
67470
  const seen = ctx.seen.get(schema2);
67471
67471
  seen.ref = def.innerType;
67472
67472
  };
67473
67473
  defaultProcessor = (schema2, ctx, json4, params) => {
67474
67474
  const def = schema2._zod.def;
67475
- process2(def.innerType, ctx, params);
67475
+ process3(def.innerType, ctx, params);
67476
67476
  const seen = ctx.seen.get(schema2);
67477
67477
  seen.ref = def.innerType;
67478
67478
  json4.default = JSON.parse(JSON.stringify(def.defaultValue));
67479
67479
  };
67480
67480
  prefaultProcessor = (schema2, ctx, json4, params) => {
67481
67481
  const def = schema2._zod.def;
67482
- process2(def.innerType, ctx, params);
67482
+ process3(def.innerType, ctx, params);
67483
67483
  const seen = ctx.seen.get(schema2);
67484
67484
  seen.ref = def.innerType;
67485
67485
  if (ctx.io === "input")
@@ -67487,7 +67487,7 @@ var init_json_schema_processors = __esm({
67487
67487
  };
67488
67488
  catchProcessor = (schema2, ctx, json4, params) => {
67489
67489
  const def = schema2._zod.def;
67490
- process2(def.innerType, ctx, params);
67490
+ process3(def.innerType, ctx, params);
67491
67491
  const seen = ctx.seen.get(schema2);
67492
67492
  seen.ref = def.innerType;
67493
67493
  let catchValue;
@@ -67501,32 +67501,32 @@ var init_json_schema_processors = __esm({
67501
67501
  pipeProcessor = (schema2, ctx, _json, params) => {
67502
67502
  const def = schema2._zod.def;
67503
67503
  const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
67504
- process2(innerType, ctx, params);
67504
+ process3(innerType, ctx, params);
67505
67505
  const seen = ctx.seen.get(schema2);
67506
67506
  seen.ref = innerType;
67507
67507
  };
67508
67508
  readonlyProcessor = (schema2, ctx, json4, params) => {
67509
67509
  const def = schema2._zod.def;
67510
- process2(def.innerType, ctx, params);
67510
+ process3(def.innerType, ctx, params);
67511
67511
  const seen = ctx.seen.get(schema2);
67512
67512
  seen.ref = def.innerType;
67513
67513
  json4.readOnly = true;
67514
67514
  };
67515
67515
  promiseProcessor = (schema2, ctx, _json, params) => {
67516
67516
  const def = schema2._zod.def;
67517
- process2(def.innerType, ctx, params);
67517
+ process3(def.innerType, ctx, params);
67518
67518
  const seen = ctx.seen.get(schema2);
67519
67519
  seen.ref = def.innerType;
67520
67520
  };
67521
67521
  optionalProcessor = (schema2, ctx, _json, params) => {
67522
67522
  const def = schema2._zod.def;
67523
- process2(def.innerType, ctx, params);
67523
+ process3(def.innerType, ctx, params);
67524
67524
  const seen = ctx.seen.get(schema2);
67525
67525
  seen.ref = def.innerType;
67526
67526
  };
67527
67527
  lazyProcessor = (schema2, ctx, _json, params) => {
67528
67528
  const innerType = schema2._zod.innerType;
67529
- process2(innerType, ctx, params);
67529
+ process3(innerType, ctx, params);
67530
67530
  const seen = ctx.seen.get(schema2);
67531
67531
  seen.ref = innerType;
67532
67532
  };
@@ -67632,7 +67632,7 @@ var init_json_schema_generator = __esm({
67632
67632
  * This must be called before emit().
67633
67633
  */
67634
67634
  process(schema2, _params = { path: [], schemaPath: [] }) {
67635
- return process2(schema2, this.ctx, _params);
67635
+ return process3(schema2, this.ctx, _params);
67636
67636
  }
67637
67637
  /**
67638
67638
  * Emit the final JSON Schema after processing.
@@ -67925,7 +67925,7 @@ __export(core_exports2, {
67925
67925
  parse: () => parse,
67926
67926
  parseAsync: () => parseAsync,
67927
67927
  prettifyError: () => prettifyError,
67928
- process: () => process2,
67928
+ process: () => process3,
67929
67929
  regexes: () => regexes_exports,
67930
67930
  registry: () => registry2,
67931
67931
  safeDecode: () => safeDecode,
@@ -101738,6 +101738,299 @@ import { existsSync as existsSync8, readdirSync as readdirSync2 } from "node:fs"
101738
101738
  import { readFile as readFile5 } from "node:fs/promises";
101739
101739
  import { join as join26 } from "node:path";
101740
101740
 
101741
+ // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/commands.mjs
101742
+ function dashDashArg(agent2, agentCommand) {
101743
+ return (args2) => {
101744
+ if (args2.length > 1) {
101745
+ return [agent2, agentCommand, args2[0], "--", ...args2.slice(1)];
101746
+ } else {
101747
+ return [agent2, agentCommand, args2[0]];
101748
+ }
101749
+ };
101750
+ }
101751
+ function denoExecute() {
101752
+ return (args2) => {
101753
+ return ["deno", "run", `npm:${args2[0]}`, ...args2.slice(1)];
101754
+ };
101755
+ }
101756
+ var npm = {
101757
+ "agent": ["npm", 0],
101758
+ "run": dashDashArg("npm", "run"),
101759
+ "install": ["npm", "i", 0],
101760
+ "frozen": ["npm", "ci", 0],
101761
+ "global": ["npm", "i", "-g", 0],
101762
+ "add": ["npm", "i", 0],
101763
+ "upgrade": ["npm", "update", 0],
101764
+ "upgrade-interactive": null,
101765
+ "dedupe": ["npm", "dedupe", 0],
101766
+ "execute": ["npx", 0],
101767
+ "execute-local": ["npx", 0],
101768
+ "uninstall": ["npm", "uninstall", 0],
101769
+ "global_uninstall": ["npm", "uninstall", "-g", 0]
101770
+ };
101771
+ var yarn = {
101772
+ "agent": ["yarn", 0],
101773
+ "run": ["yarn", "run", 0],
101774
+ "install": ["yarn", "install", 0],
101775
+ "frozen": ["yarn", "install", "--frozen-lockfile", 0],
101776
+ "global": ["yarn", "global", "add", 0],
101777
+ "add": ["yarn", "add", 0],
101778
+ "upgrade": ["yarn", "upgrade", 0],
101779
+ "upgrade-interactive": ["yarn", "upgrade-interactive", 0],
101780
+ "dedupe": null,
101781
+ "execute": ["npx", 0],
101782
+ "execute-local": dashDashArg("yarn", "exec"),
101783
+ "uninstall": ["yarn", "remove", 0],
101784
+ "global_uninstall": ["yarn", "global", "remove", 0]
101785
+ };
101786
+ var yarnBerry = {
101787
+ ...yarn,
101788
+ "frozen": ["yarn", "install", "--immutable", 0],
101789
+ "upgrade": ["yarn", "up", 0],
101790
+ "upgrade-interactive": ["yarn", "up", "-i", 0],
101791
+ "dedupe": ["yarn", "dedupe", 0],
101792
+ "execute": ["yarn", "dlx", 0],
101793
+ "execute-local": ["yarn", "exec", 0],
101794
+ // Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821
101795
+ "global": ["npm", "i", "-g", 0],
101796
+ "global_uninstall": ["npm", "uninstall", "-g", 0]
101797
+ };
101798
+ var pnpm = {
101799
+ "agent": ["pnpm", 0],
101800
+ "run": ["pnpm", "run", 0],
101801
+ "install": ["pnpm", "i", 0],
101802
+ "frozen": ["pnpm", "i", "--frozen-lockfile", 0],
101803
+ "global": ["pnpm", "add", "-g", 0],
101804
+ "add": ["pnpm", "add", 0],
101805
+ "upgrade": ["pnpm", "update", 0],
101806
+ "upgrade-interactive": ["pnpm", "update", "-i", 0],
101807
+ "dedupe": ["pnpm", "dedupe", 0],
101808
+ "execute": ["pnpm", "dlx", 0],
101809
+ "execute-local": ["pnpm", "exec", 0],
101810
+ "uninstall": ["pnpm", "remove", 0],
101811
+ "global_uninstall": ["pnpm", "remove", "--global", 0]
101812
+ };
101813
+ var bun = {
101814
+ "agent": ["bun", 0],
101815
+ "run": ["bun", "run", 0],
101816
+ "install": ["bun", "install", 0],
101817
+ "frozen": ["bun", "install", "--frozen-lockfile", 0],
101818
+ "global": ["bun", "add", "-g", 0],
101819
+ "add": ["bun", "add", 0],
101820
+ "upgrade": ["bun", "update", 0],
101821
+ "upgrade-interactive": ["bun", "update", "-i", 0],
101822
+ "dedupe": null,
101823
+ "execute": ["bun", "x", 0],
101824
+ "execute-local": ["bun", "x", 0],
101825
+ "uninstall": ["bun", "remove", 0],
101826
+ "global_uninstall": ["bun", "remove", "-g", 0]
101827
+ };
101828
+ var deno = {
101829
+ "agent": ["deno", 0],
101830
+ "run": ["deno", "task", 0],
101831
+ "install": ["deno", "install", 0],
101832
+ "frozen": ["deno", "install", "--frozen", 0],
101833
+ "global": ["deno", "install", "-g", 0],
101834
+ "add": ["deno", "add", 0],
101835
+ "upgrade": ["deno", "outdated", "--update", 0],
101836
+ "upgrade-interactive": ["deno", "outdated", "--update", 0],
101837
+ "dedupe": null,
101838
+ "execute": denoExecute(),
101839
+ "execute-local": ["deno", "task", "--eval", 0],
101840
+ "uninstall": ["deno", "remove", 0],
101841
+ "global_uninstall": ["deno", "uninstall", "-g", 0]
101842
+ };
101843
+ var COMMANDS = {
101844
+ "npm": npm,
101845
+ "yarn": yarn,
101846
+ "yarn@berry": yarnBerry,
101847
+ "pnpm": pnpm,
101848
+ // pnpm v6.x or below
101849
+ "pnpm@6": {
101850
+ ...pnpm,
101851
+ run: dashDashArg("pnpm", "run")
101852
+ },
101853
+ "bun": bun,
101854
+ "deno": deno
101855
+ };
101856
+ function resolveCommand(agent2, command, args2) {
101857
+ const value2 = COMMANDS[agent2][command];
101858
+ return constructCommand(value2, args2);
101859
+ }
101860
+ function constructCommand(value2, args2) {
101861
+ if (value2 == null)
101862
+ return null;
101863
+ const list = typeof value2 === "function" ? value2(args2) : value2.flatMap((v) => {
101864
+ if (typeof v === "number")
101865
+ return args2;
101866
+ return [v];
101867
+ });
101868
+ return {
101869
+ command: list[0],
101870
+ args: list.slice(1)
101871
+ };
101872
+ }
101873
+
101874
+ // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/constants.mjs
101875
+ var AGENTS = [
101876
+ "npm",
101877
+ "yarn",
101878
+ "yarn@berry",
101879
+ "pnpm",
101880
+ "pnpm@6",
101881
+ "bun",
101882
+ "deno"
101883
+ ];
101884
+ var LOCKS = {
101885
+ "bun.lock": "bun",
101886
+ "bun.lockb": "bun",
101887
+ "deno.lock": "deno",
101888
+ "pnpm-lock.yaml": "pnpm",
101889
+ "pnpm-workspace.yaml": "pnpm",
101890
+ "yarn.lock": "yarn",
101891
+ "package-lock.json": "npm",
101892
+ "npm-shrinkwrap.json": "npm"
101893
+ };
101894
+ var INSTALL_METADATA = {
101895
+ "node_modules/.deno/": "deno",
101896
+ "node_modules/.pnpm/": "pnpm",
101897
+ "node_modules/.yarn-state.yml": "yarn",
101898
+ // yarn v2+ (node-modules)
101899
+ "node_modules/.yarn_integrity": "yarn",
101900
+ // yarn v1
101901
+ "node_modules/.package-lock.json": "npm",
101902
+ ".pnp.cjs": "yarn",
101903
+ // yarn v3+ (pnp)
101904
+ ".pnp.js": "yarn",
101905
+ // yarn v2 (pnp)
101906
+ "bun.lock": "bun",
101907
+ "bun.lockb": "bun"
101908
+ };
101909
+
101910
+ // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/detect.mjs
101911
+ import fs from "node:fs/promises";
101912
+ import path from "node:path";
101913
+ import process2 from "node:process";
101914
+ async function pathExists(path22, type2) {
101915
+ try {
101916
+ const stat = await fs.stat(path22);
101917
+ return type2 === "file" ? stat.isFile() : stat.isDirectory();
101918
+ } catch {
101919
+ return false;
101920
+ }
101921
+ }
101922
+ function* lookup(cwd = process2.cwd()) {
101923
+ let directory = path.resolve(cwd);
101924
+ const { root } = path.parse(directory);
101925
+ while (directory && directory !== root) {
101926
+ yield directory;
101927
+ directory = path.dirname(directory);
101928
+ }
101929
+ }
101930
+ async function parsePackageJson(filepath, options) {
101931
+ if (!filepath || !await pathExists(filepath, "file"))
101932
+ return null;
101933
+ return await handlePackageManager(filepath, options);
101934
+ }
101935
+ async function detect(options = {}) {
101936
+ const {
101937
+ cwd,
101938
+ strategies = ["lockfile", "packageManager-field", "devEngines-field"]
101939
+ } = options;
101940
+ let stopDir;
101941
+ if (typeof options.stopDir === "string") {
101942
+ const resolved = path.resolve(options.stopDir);
101943
+ stopDir = (dir) => dir === resolved;
101944
+ } else {
101945
+ stopDir = options.stopDir;
101946
+ }
101947
+ for (const directory of lookup(cwd)) {
101948
+ for (const strategy of strategies) {
101949
+ switch (strategy) {
101950
+ case "lockfile": {
101951
+ for (const lock of Object.keys(LOCKS)) {
101952
+ if (await pathExists(path.join(directory, lock), "file")) {
101953
+ const name = LOCKS[lock];
101954
+ const result = await parsePackageJson(path.join(directory, "package.json"), options);
101955
+ if (result)
101956
+ return result;
101957
+ else
101958
+ return { name, agent: name };
101959
+ }
101960
+ }
101961
+ break;
101962
+ }
101963
+ case "packageManager-field":
101964
+ case "devEngines-field": {
101965
+ const result = await parsePackageJson(path.join(directory, "package.json"), options);
101966
+ if (result)
101967
+ return result;
101968
+ break;
101969
+ }
101970
+ case "install-metadata": {
101971
+ for (const metadata of Object.keys(INSTALL_METADATA)) {
101972
+ const fileOrDir = metadata.endsWith("/") ? "dir" : "file";
101973
+ if (await pathExists(path.join(directory, metadata), fileOrDir)) {
101974
+ const name = INSTALL_METADATA[metadata];
101975
+ const agent2 = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name;
101976
+ return { name, agent: agent2 };
101977
+ }
101978
+ }
101979
+ break;
101980
+ }
101981
+ }
101982
+ }
101983
+ if (stopDir?.(directory))
101984
+ break;
101985
+ }
101986
+ return null;
101987
+ }
101988
+ function getNameAndVer(pkg) {
101989
+ const handelVer = (version3) => version3?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version3;
101990
+ if (typeof pkg.packageManager === "string") {
101991
+ const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@");
101992
+ return { name, ver: handelVer(ver) };
101993
+ }
101994
+ if (typeof pkg.devEngines?.packageManager?.name === "string") {
101995
+ return {
101996
+ name: pkg.devEngines.packageManager.name,
101997
+ ver: handelVer(pkg.devEngines.packageManager.version)
101998
+ };
101999
+ }
102000
+ return void 0;
102001
+ }
102002
+ async function handlePackageManager(filepath, options) {
102003
+ try {
102004
+ const content = await fs.readFile(filepath, "utf8");
102005
+ const pkg = options.packageJsonParser ? await options.packageJsonParser(content, filepath) : JSON.parse(content);
102006
+ let agent2;
102007
+ const nameAndVer = getNameAndVer(pkg);
102008
+ if (nameAndVer) {
102009
+ const name = nameAndVer.name;
102010
+ const ver = nameAndVer.ver;
102011
+ let version3 = ver;
102012
+ if (name === "yarn" && ver && Number.parseInt(ver) > 1) {
102013
+ agent2 = "yarn@berry";
102014
+ version3 = "berry";
102015
+ return { name, agent: agent2, version: version3 };
102016
+ } else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) {
102017
+ agent2 = "pnpm@6";
102018
+ return { name, agent: agent2, version: version3 };
102019
+ } else if (AGENTS.includes(name)) {
102020
+ agent2 = name;
102021
+ return { name, agent: agent2, version: version3 };
102022
+ } else {
102023
+ return options.onUnknown?.(pkg.packageManager) ?? null;
102024
+ }
102025
+ }
102026
+ } catch {
102027
+ }
102028
+ return null;
102029
+ }
102030
+ function isMetadataYarnClassic(metadataPath) {
102031
+ return metadataPath.endsWith(".yarn_integrity");
102032
+ }
102033
+
101741
102034
  // agents/claude.ts
101742
102035
  import { execFileSync as execFileSync3 } from "node:child_process";
101743
102036
  import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "node:fs";
@@ -101773,6 +102066,12 @@ function resolveRung(params) {
101773
102066
  const clamped = Math.min(1, Math.max(0, params.position));
101774
102067
  return rungs[Math.floor(clamped * (rungs.length - 1))];
101775
102068
  }
102069
+ function rungPosition(params) {
102070
+ const rungs = offeredRungs(params.published);
102071
+ const index = rungs.indexOf(params.rung);
102072
+ if (index === -1) return void 0;
102073
+ return rungs.length > 1 ? index / (rungs.length - 1) : 0;
102074
+ }
101776
102075
 
101777
102076
  // models.ts
101778
102077
  function provider(config3) {
@@ -101826,7 +102125,11 @@ var providers = {
101826
102125
  envVars: ["OPENAI_API_KEY"],
101827
102126
  managedCredentials: ["CODEX_AUTH_JSON"],
101828
102127
  models: {
101829
- gpt: {
102128
+ // Sol/Terra/Luna are OpenAI's durable capability tiers, so they ARE the
102129
+ // brand-tier names the slug convention asks for — the pre-5.6 `gpt` /
102130
+ // `gpt-pro` / `gpt-mini` slugs are holdovers from the retired GPT / GPT Pro
102131
+ // / GPT Mini tiering and are carried below as deprecated aliases.
102132
+ "gpt-sol": {
101830
102133
  displayName: "GPT Sol",
101831
102134
  resolve: "openai/gpt-5.6-sol",
101832
102135
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -101837,24 +102140,23 @@ var providers = {
101837
102140
  // Sol served at reasoning.mode=pro — same $/token as Sol, just more tokens
101838
102141
  // burned; not a pricier premium tier. models.dev has no -pro id, so direct-key
101839
102142
  // (BYOK) resolves to plain Sol; only the Router/OpenRouter path gets sol-pro.
101840
- "gpt-pro": {
102143
+ "gpt-sol-pro": {
101841
102144
  displayName: "GPT Sol Pro",
101842
102145
  description: "Maximum reasoning effort",
101843
102146
  resolve: "openai/gpt-5.6-sol",
101844
102147
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
101845
102148
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
101846
- subagentModel: "gpt"
102149
+ subagentModel: "gpt-sol"
101847
102150
  },
101848
- // gpt-5.6's balanced mid-tier (Sol/Terra/Luna are durable capability tiers,
101849
- // not version bumps). selectable on its own and doubles as `gpt`'s cheaper
101850
- // lens-fanout subagent — replaces the old hidden gpt-5.4 subagent target.
102151
+ // gpt-5.6's balanced mid-tier. selectable on its own and doubles as Sol's
102152
+ // cheaper lens-fanout subagent replaces the old hidden gpt-5.4 target.
101851
102153
  "gpt-terra": {
101852
102154
  displayName: "GPT Terra",
101853
102155
  resolve: "openai/gpt-5.6-terra",
101854
102156
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
101855
102157
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
101856
102158
  },
101857
- "gpt-mini": {
102159
+ "gpt-luna": {
101858
102160
  displayName: "GPT Luna",
101859
102161
  resolve: "openai/gpt-5.6-luna",
101860
102162
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -101869,20 +102171,40 @@ var providers = {
101869
102171
  displayName: "GPT Codex",
101870
102172
  resolve: "openai/gpt-5.3-codex",
101871
102173
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
101872
- fallback: "openai/gpt"
102174
+ fallback: "openai/gpt-sol"
101873
102175
  },
101874
102176
  "gpt-codex-mini": {
101875
102177
  displayName: "GPT Codex Mini",
101876
102178
  resolve: "openai/gpt-5.1-codex-mini",
101877
102179
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
101878
- fallback: "openai/gpt-mini"
102180
+ fallback: "openai/gpt-luna"
102181
+ },
102182
+ // pre-5.6 tier slugs. the tiers themselves were renamed Sol/Sol Pro/Luna,
102183
+ // so these fold forward rather than describing anything that still runs.
102184
+ gpt: {
102185
+ displayName: "GPT",
102186
+ resolve: "openai/gpt-5.6-sol",
102187
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102188
+ fallback: "openai/gpt-sol"
102189
+ },
102190
+ "gpt-pro": {
102191
+ displayName: "GPT Pro",
102192
+ resolve: "openai/gpt-5.6-sol",
102193
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102194
+ fallback: "openai/gpt-sol-pro"
102195
+ },
102196
+ "gpt-mini": {
102197
+ displayName: "GPT Mini",
102198
+ resolve: "openai/gpt-5.6-luna",
102199
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
102200
+ fallback: "openai/gpt-luna"
101879
102201
  },
101880
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
102202
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
101881
102203
  "gpt-5.4": {
101882
102204
  displayName: "GPT 5.4",
101883
102205
  resolve: "openai/gpt-5.4",
101884
102206
  openRouterResolve: "openrouter/openai/gpt-5.4",
101885
- fallback: "openai/gpt"
102207
+ fallback: "openai/gpt-sol"
101886
102208
  },
101887
102209
  o3: {
101888
102210
  displayName: "O3",
@@ -101910,9 +102232,9 @@ var providers = {
101910
102232
  },
101911
102233
  "gemini-flash": {
101912
102234
  displayName: "Gemini Flash",
101913
- resolve: "google/gemini-3.5-flash",
102235
+ resolve: "google/gemini-3.6-flash",
101914
102236
  effort: ["minimal", "low", "medium", "high"],
101915
- openRouterResolve: "openrouter/google/gemini-3.5-flash"
102237
+ openRouterResolve: "openrouter/google/gemini-3.6-flash"
101916
102238
  }
101917
102239
  }
101918
102240
  }),
@@ -101922,26 +102244,26 @@ var providers = {
101922
102244
  models: {
101923
102245
  grok: {
101924
102246
  displayName: "Grok",
101925
- resolve: "xai/grok-4.3",
101926
- effort: ["none", "low", "medium", "high"],
101927
- openRouterResolve: "openrouter/x-ai/grok-4.3",
102247
+ resolve: "xai/grok-4.5",
102248
+ effort: ["low", "medium", "high"],
102249
+ openRouterResolve: "openrouter/x-ai/grok-4.5",
101928
102250
  preferred: true
101929
102251
  },
101930
102252
  // legacy aliases — xAI retired the entire fast/code-fast line on
101931
102253
  // 2026-05-15 (https://docs.x.ai/developers/migration/may-15-deprecation)
101932
102254
  // and now redirects every deprecated text-model slug to grok-4.3 at
101933
102255
  // standard pricing. fall back to the live `xai/grok` so the alias
101934
- // chain resolves to grok-4.3 for both direct-key and OpenRouter users.
102256
+ // chain resolves to grok-4.5 for both direct-key and OpenRouter users.
101935
102257
  "grok-fast": {
101936
102258
  displayName: "Grok Fast",
101937
102259
  resolve: "xai/grok-4-1-fast",
101938
- openRouterResolve: "openrouter/x-ai/grok-4.3",
102260
+ openRouterResolve: "openrouter/x-ai/grok-4.5",
101939
102261
  fallback: "xai/grok"
101940
102262
  },
101941
102263
  "grok-code-fast": {
101942
102264
  displayName: "Grok Code Fast",
101943
102265
  resolve: "xai/grok-code-fast-1",
101944
- openRouterResolve: "openrouter/x-ai/grok-4.3",
102266
+ openRouterResolve: "openrouter/x-ai/grok-4.5",
101945
102267
  fallback: "xai/grok"
101946
102268
  }
101947
102269
  }
@@ -101958,12 +102280,25 @@ var providers = {
101958
102280
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro",
101959
102281
  preferred: true
101960
102282
  },
102283
+ // DeepSeek upgrades the `deepseek-v4-flash` API model in place, so the
102284
+ // direct `resolve` needs no version. OpenRouter instead forked the 0731
102285
+ // release into its own id and left the April preview live under the
102286
+ // unversioned one at a HIGHER price ($0.14/$0.28 vs $0.09/$0.18) — so the
102287
+ // OpenRouter route can never use the bare id. it tracks the rolling
102288
+ // `~deepseek/*-latest` pointer (rule 4), which resolves to 0731 at the
102289
+ // same price today and follows the next in-place upgrade on its own,
102290
+ // rather than pinning a dated snapshot that goes stale every release.
102291
+ // 0731 gained a `low` rung and renamed the top to `max`, unlike Pro
102292
+ // (`high, max` direct / `high, xhigh` via OpenRouter). that ladder now
102293
+ // reads the same on BOTH routes — the in-place direct upgrade caught up
102294
+ // to the fork — so `low`, not `high`, is position 0 either way, which is
102295
+ // why the OSS effort floor in `main.ts` pins the `high` rung by name.
101961
102296
  "deepseek-flash": {
101962
102297
  displayName: "DeepSeek Flash",
101963
102298
  resolve: "deepseek/deepseek-v4-flash",
101964
- effort: ["high", "max"],
101965
- openRouterEffort: ["high", "xhigh"],
101966
- openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
102299
+ effort: ["low", "high", "max"],
102300
+ openRouterEffort: ["low", "high", "max"],
102301
+ openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
101967
102302
  },
101968
102303
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
101969
102304
  // upgrade existing users to the v4 family via the fallback chain.
@@ -102032,30 +102367,30 @@ var providers = {
102032
102367
  resolve: "opencode/claude-haiku-4-5",
102033
102368
  openRouterResolve: "openrouter/anthropic/claude-haiku-4.5"
102034
102369
  },
102035
- gpt: {
102370
+ "gpt-sol": {
102036
102371
  displayName: "GPT Sol",
102037
102372
  resolve: "opencode/gpt-5.6-sol",
102038
102373
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102039
102374
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102040
102375
  subagentModel: "gpt-terra"
102041
102376
  },
102042
- // see openai/gpt-pro — Zen has no -pro id, so direct resolves to plain Sol.
102043
- "gpt-pro": {
102377
+ // see openai/gpt-sol-pro — Zen has no -pro id, so direct resolves to plain Sol.
102378
+ "gpt-sol-pro": {
102044
102379
  displayName: "GPT Sol Pro",
102045
102380
  description: "Maximum reasoning effort",
102046
102381
  resolve: "opencode/gpt-5.6-sol",
102047
102382
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102048
102383
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102049
- subagentModel: "gpt"
102384
+ subagentModel: "gpt-sol"
102050
102385
  },
102051
- // gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
102386
+ // gpt-5.6 balanced mid-tier — selectable + Sol's subagent. see openai above.
102052
102387
  "gpt-terra": {
102053
102388
  displayName: "GPT Terra",
102054
102389
  resolve: "opencode/gpt-5.6-terra",
102055
102390
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102056
102391
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
102057
102392
  },
102058
- "gpt-mini": {
102393
+ "gpt-luna": {
102059
102394
  displayName: "GPT Luna",
102060
102395
  resolve: "opencode/gpt-5.6-luna",
102061
102396
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -102066,20 +102401,39 @@ var providers = {
102066
102401
  displayName: "GPT Codex",
102067
102402
  resolve: "opencode/gpt-5.3-codex",
102068
102403
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
102069
- fallback: "opencode/gpt"
102404
+ fallback: "opencode/gpt-sol"
102070
102405
  },
102071
102406
  "gpt-codex-mini": {
102072
102407
  displayName: "GPT Codex Mini",
102073
102408
  resolve: "opencode/gpt-5.1-codex-mini",
102074
102409
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
102075
- fallback: "opencode/gpt-mini"
102410
+ fallback: "opencode/gpt-luna"
102411
+ },
102412
+ // pre-5.6 tier slugs — see openai provider above.
102413
+ gpt: {
102414
+ displayName: "GPT",
102415
+ resolve: "opencode/gpt-5.6-sol",
102416
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102417
+ fallback: "opencode/gpt-sol"
102418
+ },
102419
+ "gpt-pro": {
102420
+ displayName: "GPT Pro",
102421
+ resolve: "opencode/gpt-5.6-sol",
102422
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102423
+ fallback: "opencode/gpt-sol-pro"
102076
102424
  },
102077
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
102425
+ "gpt-mini": {
102426
+ displayName: "GPT Mini",
102427
+ resolve: "opencode/gpt-5.6-luna",
102428
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
102429
+ fallback: "opencode/gpt-luna"
102430
+ },
102431
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
102078
102432
  "gpt-5.4": {
102079
102433
  displayName: "GPT 5.4",
102080
102434
  resolve: "opencode/gpt-5.4",
102081
102435
  openRouterResolve: "openrouter/openai/gpt-5.4",
102082
- fallback: "opencode/gpt"
102436
+ fallback: "opencode/gpt-sol"
102083
102437
  },
102084
102438
  "gemini-pro": {
102085
102439
  displayName: "Gemini Pro",
@@ -102090,21 +102444,19 @@ var providers = {
102090
102444
  },
102091
102445
  "gemini-flash": {
102092
102446
  displayName: "Gemini Flash",
102093
- resolve: "opencode/gemini-3.5-flash",
102447
+ resolve: "opencode/gemini-3.6-flash",
102094
102448
  effort: ["minimal", "low", "medium", "high"],
102095
- openRouterResolve: "openrouter/google/gemini-3.5-flash"
102449
+ openRouterResolve: "openrouter/google/gemini-3.6-flash"
102096
102450
  },
102097
102451
  "kimi-k2": {
102098
102452
  displayName: "Kimi K2",
102099
- // opencode Zen serves only up to k2.6; the OpenRouter fallback (used for
102100
- // router/oss proxy runs) takes the newer k2.7-code.
102101
- resolve: "opencode/kimi-k2.6",
102453
+ resolve: "opencode/kimi-k2.7-code",
102102
102454
  openRouterResolve: "openrouter/moonshotai/kimi-k2.7-code"
102103
102455
  },
102104
- // Zen serves m2.5; the funded OpenRouter path tracks the current m2.7.
102456
+ // slug pins the m2 line for DB stability; resolve tracks the current m2.7.
102105
102457
  "minimax-m2.5": {
102106
102458
  displayName: "MiniMax M2",
102107
- resolve: "opencode/minimax-m2.5",
102459
+ resolve: "opencode/minimax-m2.7",
102108
102460
  openRouterResolve: "openrouter/minimax/minimax-m2.7"
102109
102461
  },
102110
102462
  "gpt-5-nano": {
@@ -102235,30 +102587,30 @@ var providers = {
102235
102587
  // alias): after the Sol/Terra/Luna rename, ~gpt-mini-latest no longer maps
102236
102588
  // to Luna, so rolling aliases would silently diverge `gpt`/`gpt-mini` from
102237
102589
  // the chosen tiers across funding paths.
102238
- gpt: {
102590
+ "gpt-sol": {
102239
102591
  displayName: "GPT Sol",
102240
102592
  resolve: "openrouter/openai/gpt-5.6-sol",
102241
102593
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102242
102594
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102243
102595
  subagentModel: "gpt-terra"
102244
102596
  },
102245
- // see openai/gpt-pro. openrouter serves sol-pro directly on both routes.
102246
- "gpt-pro": {
102597
+ // see openai/gpt-sol-pro. openrouter serves sol-pro directly on both routes.
102598
+ "gpt-sol-pro": {
102247
102599
  displayName: "GPT Sol Pro",
102248
102600
  description: "Maximum reasoning effort",
102249
102601
  resolve: "openrouter/openai/gpt-5.6-sol-pro",
102250
102602
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102251
102603
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102252
- subagentModel: "gpt"
102604
+ subagentModel: "gpt-sol"
102253
102605
  },
102254
- // gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
102606
+ // gpt-5.6 balanced mid-tier — selectable + Sol's subagent. see openai above.
102255
102607
  "gpt-terra": {
102256
102608
  displayName: "GPT Terra",
102257
102609
  resolve: "openrouter/openai/gpt-5.6-terra",
102258
102610
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102259
102611
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
102260
102612
  },
102261
- "gpt-mini": {
102613
+ "gpt-luna": {
102262
102614
  displayName: "GPT Luna",
102263
102615
  resolve: "openrouter/openai/gpt-5.6-luna",
102264
102616
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -102269,20 +102621,39 @@ var providers = {
102269
102621
  displayName: "GPT Codex",
102270
102622
  resolve: "openrouter/openai/gpt-5.3-codex",
102271
102623
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
102272
- fallback: "openrouter/gpt"
102624
+ fallback: "openrouter/gpt-sol"
102273
102625
  },
102274
102626
  "gpt-codex-mini": {
102275
102627
  displayName: "GPT Codex Mini",
102276
102628
  resolve: "openrouter/openai/gpt-5.1-codex-mini",
102277
102629
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
102278
- fallback: "openrouter/gpt-mini"
102630
+ fallback: "openrouter/gpt-luna"
102631
+ },
102632
+ // pre-5.6 tier slugs — see openai provider above.
102633
+ gpt: {
102634
+ displayName: "GPT",
102635
+ resolve: "openrouter/openai/gpt-5.6-sol",
102636
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102637
+ fallback: "openrouter/gpt-sol"
102279
102638
  },
102280
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
102639
+ "gpt-pro": {
102640
+ displayName: "GPT Pro",
102641
+ resolve: "openrouter/openai/gpt-5.6-sol-pro",
102642
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102643
+ fallback: "openrouter/gpt-sol-pro"
102644
+ },
102645
+ "gpt-mini": {
102646
+ displayName: "GPT Mini",
102647
+ resolve: "openrouter/openai/gpt-5.6-luna",
102648
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
102649
+ fallback: "openrouter/gpt-luna"
102650
+ },
102651
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
102281
102652
  "gpt-5.4": {
102282
102653
  displayName: "GPT 5.4",
102283
102654
  resolve: "openrouter/openai/gpt-5.4",
102284
102655
  openRouterResolve: "openrouter/openai/gpt-5.4",
102285
- fallback: "openrouter/gpt"
102656
+ fallback: "openrouter/gpt-sol"
102286
102657
  },
102287
102658
  "o4-mini": {
102288
102659
  displayName: "O4 Mini",
@@ -102305,9 +102676,9 @@ var providers = {
102305
102676
  },
102306
102677
  grok: {
102307
102678
  displayName: "Grok",
102308
- resolve: "openrouter/x-ai/grok-4.3",
102309
- effort: ["none", "low", "medium", "high"],
102310
- openRouterResolve: "openrouter/x-ai/grok-4.3"
102679
+ resolve: "openrouter/x-ai/grok-4.5",
102680
+ effort: ["low", "medium", "high"],
102681
+ openRouterResolve: "openrouter/x-ai/grok-4.5"
102311
102682
  },
102312
102683
  "deepseek-pro": {
102313
102684
  displayName: "DeepSeek Pro",
@@ -102315,11 +102686,13 @@ var providers = {
102315
102686
  effort: ["high", "xhigh"],
102316
102687
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro"
102317
102688
  },
102689
+ // rolling pointer, not the bare id — see `deepseek/deepseek-flash` for why
102690
+ // OpenRouter's unversioned `deepseek-v4-flash` is the stale April preview.
102318
102691
  "deepseek-flash": {
102319
102692
  displayName: "DeepSeek Flash",
102320
- resolve: "openrouter/deepseek/deepseek-v4-flash",
102321
- effort: ["high", "xhigh"],
102322
- openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
102693
+ resolve: "openrouter/~deepseek/deepseek-v4-flash-latest",
102694
+ effort: ["low", "high", "max"],
102695
+ openRouterResolve: "openrouter/~deepseek/deepseek-v4-flash-latest"
102323
102696
  },
102324
102697
  // legacy alias — deepseek retires this on 2026-07-24; transparently
102325
102698
  // upgrade existing users to the v4 family via the fallback chain.
@@ -102400,7 +102773,7 @@ var modelAliases = Object.entries(providers).flatMap(
102400
102773
  var AUTO_EFFICIENT = "auto/efficient";
102401
102774
  var AUTO_INTELLIGENT = "auto/intelligent";
102402
102775
  var AUTO_TIER_TARGET = {
102403
- [AUTO_EFFICIENT]: "deepseek/deepseek-pro",
102776
+ [AUTO_EFFICIENT]: "deepseek/deepseek-flash",
102404
102777
  [AUTO_INTELLIGENT]: "anthropic/claude-opus"
102405
102778
  };
102406
102779
  function isAutoTier(slug2) {
@@ -102449,6 +102822,26 @@ if (!defaultProxyAlias?.openRouterResolve) {
102449
102822
  }
102450
102823
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
102451
102824
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
102825
+ var OSS_MODEL_ALLOWLIST = [
102826
+ "deepseek/deepseek-flash",
102827
+ "deepseek/deepseek-pro",
102828
+ "openai/gpt-luna",
102829
+ "openrouter/minimax-m2.5",
102830
+ "moonshotai/kimi-k2"
102831
+ ];
102832
+ var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
102833
+ var ossAllowedTargets = new Set(
102834
+ OSS_MODEL_ALLOWLIST.map((slug2) => {
102835
+ const target = resolveOpenRouterModel(slug2);
102836
+ if (!target) throw new Error(`OSS_MODEL_ALLOWLIST: ${slug2} has no openRouterResolve`);
102837
+ return target;
102838
+ })
102839
+ );
102840
+ function isOssAllowedModel(slug2) {
102841
+ if (!slug2) return false;
102842
+ const target = resolveOpenRouterModel(slug2);
102843
+ return target !== void 0 && ossAllowedTargets.has(target);
102844
+ }
102452
102845
  var BEDROCK_MODEL_ID_ENV = "BEDROCK_MODEL_ID";
102453
102846
  var VERTEX_MODEL_ID_ENV = "VERTEX_MODEL_ID";
102454
102847
  var OPENAI_COMPATIBLE_PROVIDER = "openai-compatible";
@@ -103054,7 +103447,21 @@ var PROVIDER_ERROR_PATTERNS = [
103054
103447
  { regex: /\bFreeUsageLimitError\b/, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103055
103448
  { regex: /Insufficient balance/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103056
103449
  { regex: /credit balance is too low/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103057
- { regex: /spending cap/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103450
+ // "spending cap" (Gemini) and "spending limit" (xAI, #1076) are the same
103451
+ // condition in two house styles — a configured ceiling was reached.
103452
+ { regex: /spending (?:cap|limit)/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103453
+ // xAI exhausts credits and the monthly ceiling in one 403 whose status code
103454
+ // sits nowhere near a `status:` key, so no status pattern below fires (#1076).
103455
+ { regex: /used all available credits/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103456
+ // the OpenRouter shapes `isRouterKeylimitExhaustedError` matches. on a Router
103457
+ // run those mean the PULLFROG wallet is empty and `renderRunError` returns a
103458
+ // `BillingError` before ever reaching this list; on a BYOK run the very same
103459
+ // wire text means the user's OWN OpenRouter wallet is empty, and this entry is
103460
+ // what gives them the right dashboard instead of ours. see #1135.
103461
+ {
103462
+ regex: /requires more credits|Key limit exceeded \(total limit\)/i,
103463
+ label: PROVIDER_BILLING_EXHAUSTED_LABEL
103464
+ },
103058
103465
  // auth patterns must come BEFORE rate-limit patterns. OpenRouter 401 error
103059
103466
  // payloads carry `x-ratelimit-*` response headers in the dump, and the
103060
103467
  // free-form rate-limit regex below would otherwise win on word-boundary
@@ -103150,6 +103557,12 @@ function resolveRunAlias(ctx) {
103150
103557
  if (!model) return void 0;
103151
103558
  return modelAliases.find((a) => !a.fallback && a.resolve === model) ?? matchHostedAnthropicAlias(model);
103152
103559
  }
103560
+ function ossEffortFloor(ctx) {
103561
+ const alias = resolveRunAlias(ctx);
103562
+ const published = alias?.openRouterEffort ?? alias?.effort;
103563
+ if (!published) return 0;
103564
+ return rungPosition({ rung: "high", published }) ?? 0;
103565
+ }
103153
103566
  function resolveRunEffort(ctx) {
103154
103567
  const configured = ctx.payload.effort !== void 0;
103155
103568
  const position = ctx.payload.effort ?? DEFAULT_EFFORT_POSITION;
@@ -103180,7 +103593,7 @@ var import_semver = __toESM(require_semver2(), 1);
103180
103593
  // package.json
103181
103594
  var package_default = {
103182
103595
  name: "pullfrog",
103183
- version: "0.1.51",
103596
+ version: "0.1.53",
103184
103597
  type: "module",
103185
103598
  bin: {
103186
103599
  pullfrog: "dist/cli.mjs",
@@ -110795,6 +111208,41 @@ function bootstrapPullfrogDataDir() {
110795
111208
  }
110796
111209
  }
110797
111210
 
111211
+ // utils/worktree.ts
111212
+ async function dirtyTrackedPaths() {
111213
+ const result = await spawn3({
111214
+ cmd: "git",
111215
+ args: ["diff", "--name-only", "HEAD"],
111216
+ env: process.env,
111217
+ activityTimeout: 0
111218
+ });
111219
+ if (result.exitCode !== 0) {
111220
+ throw new Error(
111221
+ `git diff --name-only HEAD failed (exit ${result.exitCode}): ${result.stderr.trim() || "(no stderr)"}`
111222
+ );
111223
+ }
111224
+ return new Set(result.stdout.split("\n").filter(Boolean));
111225
+ }
111226
+ async function restoreDirtiedSince(params) {
111227
+ const dirtied = [...await dirtyTrackedPaths()].filter((path4) => !params.before.has(path4));
111228
+ if (dirtied.length === 0) return;
111229
+ const result = await spawn3({
111230
+ cmd: "git",
111231
+ args: ["restore", "--staged", "--worktree", "--", ...dirtied],
111232
+ env: process.env,
111233
+ activityTimeout: 0
111234
+ });
111235
+ if (result.exitCode !== 0) {
111236
+ log.warning(
111237
+ `\xBB failed to restore ${dirtied.length} tracked file(s) modified by ${params.actor}: ${result.stderr.trim() || "(no stderr)"}`
111238
+ );
111239
+ return;
111240
+ }
111241
+ log.info(
111242
+ `\xBB restored ${dirtied.length} tracked file(s) modified by ${params.actor}: ${dirtied.join(", ")}`
111243
+ );
111244
+ }
111245
+
110798
111246
  // agents/opencodePlugin.ts
110799
111247
  var PULLFROG_BUS_EVENT_TYPE = "pullfrog_bus_event";
110800
111248
  var PULLFROG_OPENCODE_GATE_PLUGIN_FILENAME = "pullfrog-subagent-gate.ts";
@@ -111680,6 +112128,7 @@ var opencode = agent({
111680
112128
  }
111681
112129
  log.debug(`\xBB starting Pullfrog (OpenCode, in-process SDK): ${cliPath}`);
111682
112130
  log.debug(`\xBB working directory: ${repoDir}`);
112131
+ const preBootDirty = await dirtyTrackedPaths();
111683
112132
  const server = await bootOpencodeServer({ cliPath, env: env2, cwd: repoDir });
111684
112133
  const dispatcher = new import_undici.Agent({ headersTimeout: 0, bodyTimeout: 0, connectTimeout: 0 });
111685
112134
  const fetchWithoutTimeout = (input, init) => {
@@ -111700,6 +112149,7 @@ var opencode = agent({
111700
112149
  fetch: fetchWithoutTimeout
111701
112150
  });
111702
112151
  const sessionResp = await client2.session.create({ title: "Pullfrog" });
112152
+ await restoreDirtiedSince({ before: preBootDirty, actor: "agent startup" });
111703
112153
  if (sessionResp.error || !sessionResp.data) {
111704
112154
  const msg = sessionResp.error ? formatPromptError(sessionResp.error) : "session.create returned no data";
111705
112155
  return {
@@ -118428,7 +118878,7 @@ var Server = class extends Protocol {
118428
118878
  };
118429
118879
 
118430
118880
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
118431
- import process3 from "node:process";
118881
+ import process4 from "node:process";
118432
118882
 
118433
118883
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
118434
118884
  var ReadBuffer = class {
@@ -118460,7 +118910,7 @@ function serializeMessage(message) {
118460
118910
 
118461
118911
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
118462
118912
  var StdioServerTransport = class {
118463
- constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
118913
+ constructor(_stdin = process4.stdin, _stdout = process4.stdout) {
118464
118914
  this._stdin = _stdin;
118465
118915
  this._stdout = _stdout;
118466
118916
  this._readBuffer = new ReadBuffer();
@@ -121895,7 +122345,7 @@ var Hono2 = class extends Hono {
121895
122345
  import { createRequire } from "node:module";
121896
122346
  import { randomUUID as randomUUID2 } from "node:crypto";
121897
122347
  import { URL as URL$1 } from "node:url";
121898
- import fs from "fs";
122348
+ import fs2 from "fs";
121899
122349
  import http from "http";
121900
122350
  import https from "https";
121901
122351
  var __create2 = Object.create;
@@ -136463,17 +136913,17 @@ var startHTTPServer = async ({ apiKey, authenticate, cors, createServer: createS
136463
136913
  if (sslCa || sslCert || sslKey) {
136464
136914
  const options = {};
136465
136915
  if (sslCa) try {
136466
- options.ca = fs.readFileSync(sslCa);
136916
+ options.ca = fs2.readFileSync(sslCa);
136467
136917
  } catch (error$1) {
136468
136918
  throw new Error(`Failed to read CA file '${sslCa}': ${error$1.message}`);
136469
136919
  }
136470
136920
  if (sslCert) try {
136471
- options.cert = fs.readFileSync(sslCert);
136921
+ options.cert = fs2.readFileSync(sslCert);
136472
136922
  } catch (error$1) {
136473
136923
  throw new Error(`Failed to read certificate file '${sslCert}': ${error$1.message}`);
136474
136924
  }
136475
136925
  if (sslKey) try {
136476
- options.key = fs.readFileSync(sslKey);
136926
+ options.key = fs2.readFileSync(sslKey);
136477
136927
  } catch (error$1) {
136478
136928
  throw new Error(`Failed to read key file '${sslKey}': ${error$1.message}`);
136479
136929
  }
@@ -144900,6 +145350,24 @@ function isSafeEnvVar(key) {
144900
145350
  if (SAFE_ENV_NAMES.has(key)) return true;
144901
145351
  return SAFE_ENV_PREFIXES.some((p2) => key.startsWith(p2));
144902
145352
  }
145353
+ var WORKFLOW_COMMAND_ENV_NAMES = [
145354
+ "GITHUB_ENV",
145355
+ "GITHUB_PATH",
145356
+ "GITHUB_OUTPUT",
145357
+ "GITHUB_STATE",
145358
+ "GITHUB_STEP_SUMMARY",
145359
+ // dropping the five paths above but keeping RUNNER_TEMP would be theatre:
145360
+ // the file-command files live in `$RUNNER_TEMP/_runner_file_commands/`, so the
145361
+ // directory is one `ls` away. nothing in the install path reads it (only our
145362
+ // own leak-surface wipe in `setup.ts`, which runs in the parent), and package
145363
+ // managers use TMPDIR.
145364
+ "RUNNER_TEMP"
145365
+ ];
145366
+ function filterEnvForUntrustedCode() {
145367
+ const env2 = filterEnv();
145368
+ for (const name of WORKFLOW_COMMAND_ENV_NAMES) delete env2[name];
145369
+ return env2;
145370
+ }
144903
145371
  function filterEnv() {
144904
145372
  const filtered = {};
144905
145373
  for (const [key, value2] of Object.entries(process.env)) {
@@ -153093,6 +153561,8 @@ import { join as join9 } from "node:path";
153093
153561
 
153094
153562
  // utils/shell.ts
153095
153563
  import { spawnSync as spawnSync5 } from "node:child_process";
153564
+ var MAX_BUFFER_BYTES = 32 * 1024 * 1024;
153565
+ var MAX_ERROR_DETAIL_CHARS = 2e4;
153096
153566
  function $2(cmd, args2, options) {
153097
153567
  const encoding = options?.encoding ?? "utf-8";
153098
153568
  const env2 = resolveEnv(options?.env);
@@ -153100,7 +153570,8 @@ function $2(cmd, args2, options) {
153100
153570
  stdio: ["ignore", "pipe", "pipe"],
153101
153571
  encoding,
153102
153572
  cwd: options?.cwd,
153103
- env: env2
153573
+ env: env2,
153574
+ maxBuffer: MAX_BUFFER_BYTES
153104
153575
  });
153105
153576
  const stdout = result.stdout ?? "";
153106
153577
  const stderr = result.stderr ?? "";
@@ -153118,6 +153589,11 @@ function $2(cmd, args2, options) {
153118
153589
  }
153119
153590
  }
153120
153591
  if (result.status !== 0) {
153592
+ if (result.error && "code" in result.error && result.error.code === "ENOBUFS") {
153593
+ throw new Error(
153594
+ `Command produced more than ${MAX_BUFFER_BYTES / 1024 / 1024}MB of output and was terminated: ${cmd} ${args2.join(" ")}`
153595
+ );
153596
+ }
153121
153597
  const errorResult = {
153122
153598
  status: result.status ?? -1,
153123
153599
  stdout,
@@ -153127,7 +153603,7 @@ function $2(cmd, args2, options) {
153127
153603
  options.onError(errorResult);
153128
153604
  return stdout.trim();
153129
153605
  }
153130
- const detail = [stderr, stdout].map((s) => s.trim()).filter(Boolean).join("\n");
153606
+ const detail = [stderr, stdout].map((s) => s.trim()).filter(Boolean).join("\n").slice(0, MAX_ERROR_DETAIL_CHARS);
153131
153607
  throw new Error(
153132
153608
  `Command failed with exit code ${errorResult.status}: ${detail || "Unknown error"}`
153133
153609
  );
@@ -153136,6 +153612,10 @@ function $2(cmd, args2, options) {
153136
153612
  }
153137
153613
 
153138
153614
  // utils/gitAuth.ts
153615
+ var TRANSIENT_AUTH_PATTERNS = [
153616
+ /Invalid username or token/,
153617
+ /Authentication failed for 'https:\/\/github\.com\//
153618
+ ];
153139
153619
  var gitBinary;
153140
153620
  function hashFile(path4) {
153141
153621
  return createHash("sha256").update(readFileSync3(path4)).digest("hex");
@@ -153252,6 +153732,17 @@ async function $gitFetchWithDeepen(args2, options, label) {
153252
153732
  return await $git("fetch", args2, options);
153253
153733
  } catch (err) {
153254
153734
  const msg = err instanceof Error ? err.message : String(err);
153735
+ if (TRANSIENT_AUTH_PATTERNS.some((p2) => p2.test(msg)) && options.refreshGitToken) {
153736
+ log.info(
153737
+ `\xBB ${label ?? "git fetch"} hit an auth error, re-minting the git token and retrying`
153738
+ );
153739
+ const fresh = await options.refreshGitToken(options.token);
153740
+ return await $gitFetchWithDeepen(
153741
+ args2,
153742
+ { ...options, token: fresh, refreshGitToken: void 0 },
153743
+ label
153744
+ );
153745
+ }
153255
153746
  const isShallowUnreachable = SHALLOW_UNREACHABLE_PATTERNS.some((p2) => p2.test(msg));
153256
153747
  if (!isShallowUnreachable) throw err;
153257
153748
  const isShallow = $2("git", ["rev-parse", "--is-shallow-repository"], { log: false }).trim() === "true";
@@ -153371,10 +153862,12 @@ function computeIncrementalDiff(params) {
153371
153862
  ],
153372
153863
  { log: false }
153373
153864
  );
153374
- return postProcessRangeDiff(raw2);
153865
+ const processed = postProcessRangeDiff(raw2);
153866
+ return processed === null ? { status: "empty" } : { status: "ok", diff: processed };
153375
153867
  } catch (e) {
153376
- log.debug(`\xBB range-diff failed: ${e instanceof Error ? e.message : String(e)}`);
153377
- return null;
153868
+ const reason = e instanceof Error ? e.message : String(e);
153869
+ log.warning(`\xBB incremental diff unavailable: range-diff failed: ${reason}`);
153870
+ return { status: "unavailable", reason };
153378
153871
  }
153379
153872
  }
153380
153873
  function isDiffPrefix(ch) {
@@ -154806,7 +155299,7 @@ throttling.VERSION = VERSION;
154806
155299
  throttling.triggersNotification = triggersNotification;
154807
155300
 
154808
155301
  // node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
154809
- function getUserAgent() {
155302
+ function getUserAgent2() {
154810
155303
  if (typeof navigator === "object" && "userAgent" in navigator) {
154811
155304
  return navigator.userAgent;
154812
155305
  }
@@ -154924,7 +155417,7 @@ var before_after_hook_default = { Singular, Collection };
154924
155417
 
154925
155418
  // node_modules/.pnpm/@octokit+endpoint@11.0.1/node_modules/@octokit/endpoint/dist-bundle/index.js
154926
155419
  var VERSION2 = "0.0.0-development";
154927
- var userAgent = `octokit-endpoint.js/${VERSION2} ${getUserAgent()}`;
155420
+ var userAgent = `octokit-endpoint.js/${VERSION2} ${getUserAgent2()}`;
154928
155421
  var DEFAULTS = {
154929
155422
  method: "GET",
154930
155423
  baseUrl: "https://api.github.com",
@@ -155281,7 +155774,7 @@ var RequestError = class extends Error {
155281
155774
  var VERSION3 = "10.0.5";
155282
155775
  var defaults_default = {
155283
155776
  headers: {
155284
- "user-agent": `octokit-request.js/${VERSION3} ${getUserAgent()}`
155777
+ "user-agent": `octokit-request.js/${VERSION3} ${getUserAgent2()}`
155285
155778
  }
155286
155779
  };
155287
155780
  function isPlainObject4(value2) {
@@ -155546,7 +156039,7 @@ function withDefaults3(request2, newDefaults) {
155546
156039
  }
155547
156040
  var graphql2 = withDefaults3(request, {
155548
156041
  headers: {
155549
- "user-agent": `octokit-graphql.js/${VERSION4} ${getUserAgent()}`
156042
+ "user-agent": `octokit-graphql.js/${VERSION4} ${getUserAgent2()}`
155550
156043
  },
155551
156044
  method: "POST",
155552
156045
  url: "/graphql"
@@ -155626,7 +156119,7 @@ function createLogger(logger = {}) {
155626
156119
  }
155627
156120
  return logger;
155628
156121
  }
155629
- var userAgentTrail = `octokit-core.js/${VERSION5} ${getUserAgent()}`;
156122
+ var userAgentTrail = `octokit-core.js/${VERSION5} ${getUserAgent2()}`;
155630
156123
  var Octokit = class {
155631
156124
  static VERSION = VERSION5;
155632
156125
  static defaults(defaults) {
@@ -158594,8 +159087,13 @@ function createOctokit(token, refreshAuth) {
158594
159087
  var readOctokitByToken = /* @__PURE__ */ new Map();
158595
159088
  function resolveRepoCtx(ctx, repo) {
158596
159089
  const owner = ctx.repo.owner;
158597
- const name = repo ?? ctx.repo.name;
158598
- const state = requireRepoState(ctx.toolState, owner, name);
159090
+ const name = repo?.trim() || ctx.repo.name;
159091
+ const state = ctx.toolState.repos.get(repoKey(owner, name));
159092
+ if (!state) {
159093
+ throw new Error(
159094
+ ctx.xrepo ? `repo ${repoKey(owner, name)} is not a registered checkout \u2014 use checkout_repo first` : `repo ${repoKey(owner, name)} is not a registered checkout \u2014 this run is single-repo, so omit \`repo\` to target ${owner}/${ctx.repo.name}`
159095
+ );
159096
+ }
158599
159097
  if (state.access !== "read") {
158600
159098
  return {
158601
159099
  owner,
@@ -159312,10 +159810,6 @@ var TRANSIENT_PATTERNS = [
159312
159810
  /HTTP 429/,
159313
159811
  /returned error: 429/i
159314
159812
  ];
159315
- var TRANSIENT_AUTH_PATTERNS = [
159316
- /Invalid username or token/,
159317
- /Authentication failed for 'https:\/\/github\.com\//
159318
- ];
159319
159813
  function classifyPushError(msg) {
159320
159814
  if (CONCURRENT_PUSH_PATTERNS.some((p2) => msg.includes(p2))) return "concurrent-push";
159321
159815
  if (TRANSIENT_AUTH_PATTERNS.some((p2) => p2.test(msg))) return "transient-auth";
@@ -159814,7 +160308,11 @@ function GitFetchTool(ctx) {
159814
160308
  if (params.depth !== void 0) {
159815
160309
  fetchArgs.push(`--depth=${params.depth}`);
159816
160310
  }
159817
- await $gitFetchWithDeepen(fetchArgs, { token: rc.gitToken, cwd: rc.dir }, "git_fetch");
160311
+ await $gitFetchWithDeepen(
160312
+ fetchArgs,
160313
+ { token: rc.gitToken, cwd: rc.dir, refreshGitToken: rc.refreshGitToken },
160314
+ "git_fetch"
160315
+ );
159818
160316
  return { success: true, ref: params.ref };
159819
160317
  })
159820
160318
  });
@@ -159903,7 +160401,7 @@ function formatModelLabel(params) {
159903
160401
  const ossBase = `\`${displayName}\` (free via [Pullfrog for OSS](https://pullfrog.com/for-oss))`;
159904
160402
  if (params.clamped?.reason !== "oss") return ossBase;
159905
160403
  const configured = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
159906
- return `${ossBase} (${configured} not used \u2014 the program covers this model; add its [provider key](https://docs.pullfrog.com/models) to run your pick)`;
160404
+ return `${ossBase} (${configured} not used \u2014 pick one of the [funded models](https://docs.pullfrog.com/models#pullfrog-for-oss) or add a [provider key](https://docs.pullfrog.com/keys) to run your own)`;
159907
160405
  }
159908
160406
  const base = alias?.isFree ? `\`${displayName}\` (free)` : `\`${displayName}\``;
159909
160407
  if (params.fallbackFrom) {
@@ -161451,7 +161949,7 @@ async function ensureBeforeShaReachable(params) {
161451
161949
  }), true);
161452
161950
  await $gitFetchWithDeepen(
161453
161951
  ["--no-tags", ...params.isShallow ? ["--depth=1"] : [], "origin", tempBranch],
161454
- { token: params.gitToken },
161952
+ { token: params.gitToken, refreshGitToken: params.refreshGitToken },
161455
161953
  `before_sha temp branch ${tempBranch}`
161456
161954
  );
161457
161955
  log.debug(`\xBB fetched before_sha via temp branch ${tempBranch}`);
@@ -161467,6 +161965,14 @@ async function ensureBeforeShaReachable(params) {
161467
161965
  return false;
161468
161966
  }
161469
161967
  }
161968
+ function hasLocalCommit(sha) {
161969
+ if (!sha) return false;
161970
+ try {
161971
+ return $2("git", ["cat-file", "-t", sha], { log: false }).trim() === "commit";
161972
+ } catch {
161973
+ return false;
161974
+ }
161975
+ }
161470
161976
  var STALE_LOCK_AGE_MS = 3e4;
161471
161977
  var PULL_REF_RETRY_DELAYS_MS = [2e3, 5e3, 1e4];
161472
161978
  var PULL_REF_MISSING_PATTERN = /couldn't find remote ref pull\/\d+\/head/i;
@@ -161517,7 +162023,7 @@ async function abortIfPullRequestMoved(args2) {
161517
162023
  );
161518
162024
  }
161519
162025
  async function checkoutPrBranch(pr, params) {
161520
- const { octokit, owner, name, gitToken, toolState, beforeSha } = params;
162026
+ const { octokit, owner, name, gitToken, refreshGitToken, toolState, beforeSha } = params;
161521
162027
  rejectIfLeadingDash(pr.baseRef, "PR base ref");
161522
162028
  rejectIfLeadingDash(pr.headRef, "PR head ref");
161523
162029
  const repoState = requireRepoState(toolState, owner, name);
@@ -161531,7 +162037,7 @@ async function checkoutPrBranch(pr, params) {
161531
162037
  log.debug(`\xBB fetching base branch (${pr.baseRef})...`);
161532
162038
  await $gitFetchWithDeepen(
161533
162039
  ["--no-tags", "origin", pr.baseRef],
161534
- { token: gitToken },
162040
+ { token: gitToken, refreshGitToken },
161535
162041
  `base branch ${pr.baseRef}`
161536
162042
  );
161537
162043
  if (!alreadyOnBranch) {
@@ -161542,7 +162048,7 @@ async function checkoutPrBranch(pr, params) {
161542
162048
  try {
161543
162049
  await $gitFetchWithDeepen(
161544
162050
  ["--no-tags", "origin", `+pull/${pr.number}/head:${localBranch}`],
161545
- { token: gitToken },
162051
+ { token: gitToken, refreshGitToken },
161546
162052
  `PR #${pr.number}`
161547
162053
  );
161548
162054
  } catch (e) {
@@ -161569,6 +162075,7 @@ async function checkoutPrBranch(pr, params) {
161569
162075
  owner,
161570
162076
  repo: name,
161571
162077
  gitToken,
162078
+ refreshGitToken,
161572
162079
  isShallow
161573
162080
  }) : false;
161574
162081
  if (isShallow) {
@@ -161682,6 +162189,7 @@ function CheckoutPrTool(ctx) {
161682
162189
  owner: ctx.repo.owner,
161683
162190
  name: ctx.repo.name,
161684
162191
  gitToken: ctx.gitToken,
162192
+ refreshGitToken: ctx.refreshGitToken,
161685
162193
  toolState: ctx.toolState,
161686
162194
  shell: ctx.payload.shell,
161687
162195
  postCheckoutScript: ctx.postCheckoutScript,
@@ -161697,6 +162205,8 @@ function CheckoutPrTool(ctx) {
161697
162205
  if (!checkoutSha) throw new Error("checkout completed without a resolved HEAD SHA");
161698
162206
  const headShort = checkoutSha.slice(0, 7);
161699
162207
  let incrementalDiffPath;
162208
+ let incrementalUnavailable = false;
162209
+ let incrementalUnavailableReason;
161700
162210
  if (primary.beforeSha) {
161701
162211
  const beforeShort = primary.beforeSha.slice(0, 7);
161702
162212
  const incremental = computeIncrementalDiff({
@@ -161704,15 +162214,18 @@ function CheckoutPrTool(ctx) {
161704
162214
  beforeSha: primary.beforeSha,
161705
162215
  headSha: checkoutSha
161706
162216
  });
161707
- if (incremental) {
162217
+ if (incremental.status === "ok") {
161708
162218
  incrementalDiffPath = join14(
161709
162219
  tempDir,
161710
162220
  `pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
161711
162221
  );
161712
- writeFileSync9(incrementalDiffPath, incremental);
162222
+ writeFileSync9(incrementalDiffPath, incremental.diff);
161713
162223
  log.info(
161714
- `\xBB incremental diff computed (${incremental.length} bytes) \u2192 ${incrementalDiffPath}`
162224
+ `\xBB incremental diff computed (${incremental.diff.length} bytes) \u2192 ${incrementalDiffPath}`
161715
162225
  );
162226
+ } else if (incremental.status === "unavailable") {
162227
+ incrementalUnavailable = true;
162228
+ incrementalUnavailableReason = incremental.reason;
161716
162229
  }
161717
162230
  }
161718
162231
  const formatResult = await fetchAndFormatPrDiff(ctx, pull_number);
@@ -161779,7 +162292,13 @@ ${diffPreview}`);
161779
162292
  primary.commentableLinesByFile = cached4;
161780
162293
  primary.commentableLinesPullNumber = pull_number;
161781
162294
  primary.commentableLinesCheckoutSha = checkoutSha;
161782
- const incrementalInstructions = incrementalDiffPath ? `IMPORTANT: incrementalDiffPath contains ONLY the changes since the last reviewed version (computed via range-diff). you MUST read incrementalDiffPath FIRST to understand what changed, then use diffPath for full PR context. do NOT skip the incremental diff. ` : "";
162295
+ const incrementalInstructions = incrementalDiffPath ? `IMPORTANT: incrementalDiffPath contains ONLY the changes since the last reviewed version (computed via range-diff). you MUST read incrementalDiffPath FIRST to understand what changed, then use diffPath for full PR context. do NOT skip the incremental diff. ` : incrementalUnavailable ? (
162296
+ // say it FAILED rather than leaving the agent to infer "nothing changed"
162297
+ // from an absent field. only suggest diff-tree when the previous
162298
+ // revision is actually PRESENT locally — if the fetch never landed it,
162299
+ // diff-tree needs that object too and would fail identically. see #1139.
162300
+ `NOTE: an incremental diff was expected for this run but could not be computed` + (incrementalUnavailableReason ? ` (${incrementalUnavailableReason})` : "") + `. review the full diffPath instead. ` + (hasLocalCommit(primary.beforeSha) ? `if you need just the delta, \`git diff-tree -p ${primary.beforeSha} ${checkoutSha}\` works without a merge base. ` : `the previous revision was never fetched into this shallow checkout, so the full diff is the only option. `)
162301
+ ) : "";
161783
162302
  const impactInstructions = impactPath ? ` impactPath contains bounded, deterministic reference leads for semantic atoms changed by the PR. read the authoritative diff TOC and relevant raw diff lines FIRST; only then use impactPath as a supplemental, explicitly incomplete lead list. impactPath never establishes review coverage and an empty artifact is not evidence of no wider impact.` : "";
161784
162303
  const COMMIT_LOG_MAX = 200;
161785
162304
  const baseRange = `origin/${pr.baseRef}..HEAD`;
@@ -162099,299 +162618,6 @@ import { performance as performance8 } from "node:perf_hooks";
162099
162618
  import { existsSync as existsSync6 } from "node:fs";
162100
162619
  import { join as join18 } from "node:path";
162101
162620
 
162102
- // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/commands.mjs
162103
- function dashDashArg(agent2, agentCommand) {
162104
- return (args2) => {
162105
- if (args2.length > 1) {
162106
- return [agent2, agentCommand, args2[0], "--", ...args2.slice(1)];
162107
- } else {
162108
- return [agent2, agentCommand, args2[0]];
162109
- }
162110
- };
162111
- }
162112
- function denoExecute() {
162113
- return (args2) => {
162114
- return ["deno", "run", `npm:${args2[0]}`, ...args2.slice(1)];
162115
- };
162116
- }
162117
- var npm = {
162118
- "agent": ["npm", 0],
162119
- "run": dashDashArg("npm", "run"),
162120
- "install": ["npm", "i", 0],
162121
- "frozen": ["npm", "ci", 0],
162122
- "global": ["npm", "i", "-g", 0],
162123
- "add": ["npm", "i", 0],
162124
- "upgrade": ["npm", "update", 0],
162125
- "upgrade-interactive": null,
162126
- "dedupe": ["npm", "dedupe", 0],
162127
- "execute": ["npx", 0],
162128
- "execute-local": ["npx", 0],
162129
- "uninstall": ["npm", "uninstall", 0],
162130
- "global_uninstall": ["npm", "uninstall", "-g", 0]
162131
- };
162132
- var yarn = {
162133
- "agent": ["yarn", 0],
162134
- "run": ["yarn", "run", 0],
162135
- "install": ["yarn", "install", 0],
162136
- "frozen": ["yarn", "install", "--frozen-lockfile", 0],
162137
- "global": ["yarn", "global", "add", 0],
162138
- "add": ["yarn", "add", 0],
162139
- "upgrade": ["yarn", "upgrade", 0],
162140
- "upgrade-interactive": ["yarn", "upgrade-interactive", 0],
162141
- "dedupe": null,
162142
- "execute": ["npx", 0],
162143
- "execute-local": dashDashArg("yarn", "exec"),
162144
- "uninstall": ["yarn", "remove", 0],
162145
- "global_uninstall": ["yarn", "global", "remove", 0]
162146
- };
162147
- var yarnBerry = {
162148
- ...yarn,
162149
- "frozen": ["yarn", "install", "--immutable", 0],
162150
- "upgrade": ["yarn", "up", 0],
162151
- "upgrade-interactive": ["yarn", "up", "-i", 0],
162152
- "dedupe": ["yarn", "dedupe", 0],
162153
- "execute": ["yarn", "dlx", 0],
162154
- "execute-local": ["yarn", "exec", 0],
162155
- // Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821
162156
- "global": ["npm", "i", "-g", 0],
162157
- "global_uninstall": ["npm", "uninstall", "-g", 0]
162158
- };
162159
- var pnpm = {
162160
- "agent": ["pnpm", 0],
162161
- "run": ["pnpm", "run", 0],
162162
- "install": ["pnpm", "i", 0],
162163
- "frozen": ["pnpm", "i", "--frozen-lockfile", 0],
162164
- "global": ["pnpm", "add", "-g", 0],
162165
- "add": ["pnpm", "add", 0],
162166
- "upgrade": ["pnpm", "update", 0],
162167
- "upgrade-interactive": ["pnpm", "update", "-i", 0],
162168
- "dedupe": ["pnpm", "dedupe", 0],
162169
- "execute": ["pnpm", "dlx", 0],
162170
- "execute-local": ["pnpm", "exec", 0],
162171
- "uninstall": ["pnpm", "remove", 0],
162172
- "global_uninstall": ["pnpm", "remove", "--global", 0]
162173
- };
162174
- var bun = {
162175
- "agent": ["bun", 0],
162176
- "run": ["bun", "run", 0],
162177
- "install": ["bun", "install", 0],
162178
- "frozen": ["bun", "install", "--frozen-lockfile", 0],
162179
- "global": ["bun", "add", "-g", 0],
162180
- "add": ["bun", "add", 0],
162181
- "upgrade": ["bun", "update", 0],
162182
- "upgrade-interactive": ["bun", "update", "-i", 0],
162183
- "dedupe": null,
162184
- "execute": ["bun", "x", 0],
162185
- "execute-local": ["bun", "x", 0],
162186
- "uninstall": ["bun", "remove", 0],
162187
- "global_uninstall": ["bun", "remove", "-g", 0]
162188
- };
162189
- var deno = {
162190
- "agent": ["deno", 0],
162191
- "run": ["deno", "task", 0],
162192
- "install": ["deno", "install", 0],
162193
- "frozen": ["deno", "install", "--frozen", 0],
162194
- "global": ["deno", "install", "-g", 0],
162195
- "add": ["deno", "add", 0],
162196
- "upgrade": ["deno", "outdated", "--update", 0],
162197
- "upgrade-interactive": ["deno", "outdated", "--update", 0],
162198
- "dedupe": null,
162199
- "execute": denoExecute(),
162200
- "execute-local": ["deno", "task", "--eval", 0],
162201
- "uninstall": ["deno", "remove", 0],
162202
- "global_uninstall": ["deno", "uninstall", "-g", 0]
162203
- };
162204
- var COMMANDS = {
162205
- "npm": npm,
162206
- "yarn": yarn,
162207
- "yarn@berry": yarnBerry,
162208
- "pnpm": pnpm,
162209
- // pnpm v6.x or below
162210
- "pnpm@6": {
162211
- ...pnpm,
162212
- run: dashDashArg("pnpm", "run")
162213
- },
162214
- "bun": bun,
162215
- "deno": deno
162216
- };
162217
- function resolveCommand(agent2, command, args2) {
162218
- const value2 = COMMANDS[agent2][command];
162219
- return constructCommand(value2, args2);
162220
- }
162221
- function constructCommand(value2, args2) {
162222
- if (value2 == null)
162223
- return null;
162224
- const list = typeof value2 === "function" ? value2(args2) : value2.flatMap((v) => {
162225
- if (typeof v === "number")
162226
- return args2;
162227
- return [v];
162228
- });
162229
- return {
162230
- command: list[0],
162231
- args: list.slice(1)
162232
- };
162233
- }
162234
-
162235
- // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/constants.mjs
162236
- var AGENTS = [
162237
- "npm",
162238
- "yarn",
162239
- "yarn@berry",
162240
- "pnpm",
162241
- "pnpm@6",
162242
- "bun",
162243
- "deno"
162244
- ];
162245
- var LOCKS = {
162246
- "bun.lock": "bun",
162247
- "bun.lockb": "bun",
162248
- "deno.lock": "deno",
162249
- "pnpm-lock.yaml": "pnpm",
162250
- "pnpm-workspace.yaml": "pnpm",
162251
- "yarn.lock": "yarn",
162252
- "package-lock.json": "npm",
162253
- "npm-shrinkwrap.json": "npm"
162254
- };
162255
- var INSTALL_METADATA = {
162256
- "node_modules/.deno/": "deno",
162257
- "node_modules/.pnpm/": "pnpm",
162258
- "node_modules/.yarn-state.yml": "yarn",
162259
- // yarn v2+ (node-modules)
162260
- "node_modules/.yarn_integrity": "yarn",
162261
- // yarn v1
162262
- "node_modules/.package-lock.json": "npm",
162263
- ".pnp.cjs": "yarn",
162264
- // yarn v3+ (pnp)
162265
- ".pnp.js": "yarn",
162266
- // yarn v2 (pnp)
162267
- "bun.lock": "bun",
162268
- "bun.lockb": "bun"
162269
- };
162270
-
162271
- // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/detect.mjs
162272
- import fs2 from "node:fs/promises";
162273
- import path from "node:path";
162274
- import process4 from "node:process";
162275
- async function pathExists(path22, type2) {
162276
- try {
162277
- const stat = await fs2.stat(path22);
162278
- return type2 === "file" ? stat.isFile() : stat.isDirectory();
162279
- } catch {
162280
- return false;
162281
- }
162282
- }
162283
- function* lookup(cwd = process4.cwd()) {
162284
- let directory = path.resolve(cwd);
162285
- const { root } = path.parse(directory);
162286
- while (directory && directory !== root) {
162287
- yield directory;
162288
- directory = path.dirname(directory);
162289
- }
162290
- }
162291
- async function parsePackageJson(filepath, options) {
162292
- if (!filepath || !await pathExists(filepath, "file"))
162293
- return null;
162294
- return await handlePackageManager(filepath, options);
162295
- }
162296
- async function detect(options = {}) {
162297
- const {
162298
- cwd,
162299
- strategies = ["lockfile", "packageManager-field", "devEngines-field"]
162300
- } = options;
162301
- let stopDir;
162302
- if (typeof options.stopDir === "string") {
162303
- const resolved = path.resolve(options.stopDir);
162304
- stopDir = (dir) => dir === resolved;
162305
- } else {
162306
- stopDir = options.stopDir;
162307
- }
162308
- for (const directory of lookup(cwd)) {
162309
- for (const strategy of strategies) {
162310
- switch (strategy) {
162311
- case "lockfile": {
162312
- for (const lock of Object.keys(LOCKS)) {
162313
- if (await pathExists(path.join(directory, lock), "file")) {
162314
- const name = LOCKS[lock];
162315
- const result = await parsePackageJson(path.join(directory, "package.json"), options);
162316
- if (result)
162317
- return result;
162318
- else
162319
- return { name, agent: name };
162320
- }
162321
- }
162322
- break;
162323
- }
162324
- case "packageManager-field":
162325
- case "devEngines-field": {
162326
- const result = await parsePackageJson(path.join(directory, "package.json"), options);
162327
- if (result)
162328
- return result;
162329
- break;
162330
- }
162331
- case "install-metadata": {
162332
- for (const metadata of Object.keys(INSTALL_METADATA)) {
162333
- const fileOrDir = metadata.endsWith("/") ? "dir" : "file";
162334
- if (await pathExists(path.join(directory, metadata), fileOrDir)) {
162335
- const name = INSTALL_METADATA[metadata];
162336
- const agent2 = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name;
162337
- return { name, agent: agent2 };
162338
- }
162339
- }
162340
- break;
162341
- }
162342
- }
162343
- }
162344
- if (stopDir?.(directory))
162345
- break;
162346
- }
162347
- return null;
162348
- }
162349
- function getNameAndVer(pkg) {
162350
- const handelVer = (version3) => version3?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version3;
162351
- if (typeof pkg.packageManager === "string") {
162352
- const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@");
162353
- return { name, ver: handelVer(ver) };
162354
- }
162355
- if (typeof pkg.devEngines?.packageManager?.name === "string") {
162356
- return {
162357
- name: pkg.devEngines.packageManager.name,
162358
- ver: handelVer(pkg.devEngines.packageManager.version)
162359
- };
162360
- }
162361
- return void 0;
162362
- }
162363
- async function handlePackageManager(filepath, options) {
162364
- try {
162365
- const content = await fs2.readFile(filepath, "utf8");
162366
- const pkg = options.packageJsonParser ? await options.packageJsonParser(content, filepath) : JSON.parse(content);
162367
- let agent2;
162368
- const nameAndVer = getNameAndVer(pkg);
162369
- if (nameAndVer) {
162370
- const name = nameAndVer.name;
162371
- const ver = nameAndVer.ver;
162372
- let version3 = ver;
162373
- if (name === "yarn" && ver && Number.parseInt(ver) > 1) {
162374
- agent2 = "yarn@berry";
162375
- version3 = "berry";
162376
- return { name, agent: agent2, version: version3 };
162377
- } else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) {
162378
- agent2 = "pnpm@6";
162379
- return { name, agent: agent2, version: version3 };
162380
- } else if (AGENTS.includes(name)) {
162381
- agent2 = name;
162382
- return { name, agent: agent2, version: version3 };
162383
- } else {
162384
- return options.onUnknown?.(pkg.packageManager) ?? null;
162385
- }
162386
- }
162387
- } catch {
162388
- }
162389
- return null;
162390
- }
162391
- function isMetadataYarnClassic(metadataPath) {
162392
- return metadataPath.endsWith(".yarn_integrity");
162393
- }
162394
-
162395
162621
  // utils/packageManager.ts
162396
162622
  var import_semver2 = __toESM(require_semver2(), 1);
162397
162623
  import { existsSync as existsSync5 } from "node:fs";
@@ -162477,11 +162703,7 @@ async function runCorepack(args2) {
162477
162703
  const result = await spawn3({
162478
162704
  cmd: "corepack",
162479
162705
  args: args2,
162480
- env: {
162481
- PATH: process.env.PATH || "",
162482
- HOME: process.env.HOME || "",
162483
- COREPACK_ENABLE_DOWNLOAD_PROMPT: "0"
162484
- },
162706
+ env: { ...filterEnvForUntrustedCode(), COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" },
162485
162707
  onStdout: (chunk) => process.stdout.write(chunk),
162486
162708
  onStderr: (chunk) => process.stderr.write(chunk)
162487
162709
  });
@@ -162491,7 +162713,7 @@ async function currentVersion(name) {
162491
162713
  const result = await spawn3({
162492
162714
  cmd: name,
162493
162715
  args: ["--version"],
162494
- env: { PATH: process.env.PATH || "" }
162716
+ env: filterEnvForUntrustedCode()
162495
162717
  });
162496
162718
  if (result.exitCode !== 0) return null;
162497
162719
  return result.stdout.trim();
@@ -162543,14 +162765,8 @@ async function ensurePackageManager(params) {
162543
162765
  }
162544
162766
  return true;
162545
162767
  }
162546
-
162547
- // prep/installNodeDependencies.ts
162548
162768
  async function isCommandAvailable(command) {
162549
- const result = await spawn3({
162550
- cmd: "which",
162551
- args: [command],
162552
- env: { PATH: process.env.PATH || "" }
162553
- });
162769
+ const result = await spawn3({ cmd: "which", args: [command], env: filterEnvForUntrustedCode() });
162554
162770
  return result.exitCode === 0;
162555
162771
  }
162556
162772
  async function installFallback(name, installSpec) {
@@ -162561,19 +162777,41 @@ async function installFallback(name, installSpec) {
162561
162777
  const result = await spawn3({
162562
162778
  cmd,
162563
162779
  args: args2,
162564
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
162780
+ env: filterEnvForUntrustedCode(),
162565
162781
  onStderr: (chunk) => process.stderr.write(chunk)
162566
162782
  });
162567
- if (result.exitCode !== 0) {
162568
- return result.stderr || `failed to install ${name}`;
162569
- }
162783
+ if (result.exitCode !== 0) return result.stderr || `failed to install ${name}`;
162570
162784
  if (name === "deno") {
162571
- const denoPath = join18(process.env.HOME || "", ".deno", "bin");
162785
+ const denoPath = join17(process.env.HOME || "", ".deno", "bin");
162572
162786
  process.env.PATH = `${denoPath}:${process.env.PATH}`;
162573
162787
  }
162574
162788
  log.info(`\xBB installed ${name}`);
162575
162789
  return null;
162576
162790
  }
162791
+ async function provisionPackageManager(params) {
162792
+ if (await isCommandAvailable(params.name)) {
162793
+ if (params.declared) {
162794
+ await ensurePackageManager({ spec: params.declared, binDir: params.binDir });
162795
+ }
162796
+ return null;
162797
+ }
162798
+ if (params.declared) {
162799
+ const activated = await ensurePackageManager({ spec: params.declared, binDir: params.binDir });
162800
+ if (activated) return null;
162801
+ }
162802
+ const spec = params.declared ? `${params.declared.name}@${params.declared.version}` : params.name;
162803
+ return installFallback(params.name, spec);
162804
+ }
162805
+
162806
+ // prep/installNodeDependencies.ts
162807
+ async function isCommandAvailable2(command) {
162808
+ const result = await spawn3({
162809
+ cmd: "which",
162810
+ args: [command],
162811
+ env: filterEnvForUntrustedCode()
162812
+ });
162813
+ return result.exitCode === 0;
162814
+ }
162577
162815
  var installNodeDependencies = {
162578
162816
  name: "installNodeDependencies",
162579
162817
  shouldRun: () => {
@@ -162594,8 +162832,8 @@ var installNodeDependencies = {
162594
162832
  } else {
162595
162833
  log.info(`\xBB no package manager declared, defaulting to npm`);
162596
162834
  }
162597
- if (!await isCommandAvailable(packageManager)) {
162598
- if (options.ignoreScripts) {
162835
+ if (options.ignoreScripts) {
162836
+ if (!await isCommandAvailable2(packageManager)) {
162599
162837
  return {
162600
162838
  language: "node",
162601
162839
  packageManager,
@@ -162605,23 +162843,20 @@ var installNodeDependencies = {
162605
162843
  ]
162606
162844
  };
162607
162845
  }
162608
- let provisioned = false;
162609
- if (declared)
162610
- provisioned = await ensurePackageManager({ spec: declared, binDir: options.binDir });
162611
- if (!provisioned) {
162612
- const fallbackSpec = declared ? `${declared.name}@${declared.version}` : packageManager;
162613
- const installError = await installFallback(packageManager, fallbackSpec);
162614
- if (installError) {
162615
- return {
162616
- language: "node",
162617
- packageManager,
162618
- dependenciesInstalled: false,
162619
- issues: [installError]
162620
- };
162621
- }
162846
+ } else {
162847
+ const installError = await provisionPackageManager({
162848
+ name: packageManager,
162849
+ declared,
162850
+ binDir: options.binDir
162851
+ });
162852
+ if (installError) {
162853
+ return {
162854
+ language: "node",
162855
+ packageManager,
162856
+ dependenciesInstalled: false,
162857
+ issues: [installError]
162858
+ };
162622
162859
  }
162623
- } else if (declared) {
162624
- await ensurePackageManager({ spec: declared, binDir: options.binDir });
162625
162860
  }
162626
162861
  if (!detected) {
162627
162862
  log.info(
@@ -162647,7 +162882,7 @@ var installNodeDependencies = {
162647
162882
  const result = await spawn3({
162648
162883
  cmd: resolved.command,
162649
162884
  args: resolved.args,
162650
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }
162885
+ env: filterEnvForUntrustedCode()
162651
162886
  });
162652
162887
  const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
162653
162888
  if (output) {
@@ -162721,11 +162956,11 @@ var TOOL_INSTALL_COMMANDS = {
162721
162956
  pipenv: ["pip", "install", "pipenv"],
162722
162957
  poetry: ["pip", "install", "poetry"]
162723
162958
  };
162724
- async function isCommandAvailable2(command) {
162959
+ async function isCommandAvailable3(command) {
162725
162960
  const result = await spawn3({
162726
162961
  cmd: "which",
162727
162962
  args: [command],
162728
- env: { PATH: process.env.PATH || "" }
162963
+ env: filterEnvForUntrustedCode()
162729
162964
  });
162730
162965
  return result.exitCode === 0;
162731
162966
  }
@@ -162739,7 +162974,7 @@ async function installTool(name) {
162739
162974
  const result = await spawn3({
162740
162975
  cmd,
162741
162976
  args: args2,
162742
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
162977
+ env: filterEnvForUntrustedCode(),
162743
162978
  onStderr: (chunk) => process.stderr.write(chunk)
162744
162979
  });
162745
162980
  if (result.exitCode !== 0) {
@@ -162751,7 +162986,7 @@ async function installTool(name) {
162751
162986
  var installPythonDependencies = {
162752
162987
  name: "installPythonDependencies",
162753
162988
  shouldRun: async () => {
162754
- const hasPython = await isCommandAvailable2("python3") || await isCommandAvailable2("python");
162989
+ const hasPython = await isCommandAvailable3("python3") || await isCommandAvailable3("python");
162755
162990
  if (!hasPython) {
162756
162991
  return false;
162757
162992
  }
@@ -162785,7 +163020,7 @@ var installPythonDependencies = {
162785
163020
  ]
162786
163021
  };
162787
163022
  }
162788
- const isAvailable = await isCommandAvailable2(config3.tool);
163023
+ const isAvailable = await isCommandAvailable3(config3.tool);
162789
163024
  if (!isAvailable) {
162790
163025
  log.info(`\xBB ${config3.tool} not found, attempting to install...`);
162791
163026
  const installError = await installTool(config3.tool);
@@ -162805,7 +163040,7 @@ var installPythonDependencies = {
162805
163040
  const result = await spawn3({
162806
163041
  cmd,
162807
163042
  args: args2,
162808
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }
163043
+ env: filterEnvForUntrustedCode()
162809
163044
  });
162810
163045
  const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
162811
163046
  if (output) {
@@ -162834,37 +163069,6 @@ var installPythonDependencies = {
162834
163069
 
162835
163070
  // prep/index.ts
162836
163071
  var prepSteps = [installNodeDependencies, installPythonDependencies];
162837
- async function dirtyTrackedPaths() {
162838
- const result = await spawn3({
162839
- cmd: "git",
162840
- args: ["diff", "--name-only", "HEAD"],
162841
- env: process.env,
162842
- activityTimeout: 0
162843
- });
162844
- if (result.exitCode !== 0) {
162845
- throw new Error(
162846
- `git diff --name-only HEAD failed (exit ${result.exitCode}): ${result.stderr.trim() || "(no stderr)"}`
162847
- );
162848
- }
162849
- return new Set(result.stdout.split("\n").filter(Boolean));
162850
- }
162851
- async function restorePrepDirtiedFiles(preDirty) {
162852
- const dirtied = [...await dirtyTrackedPaths()].filter((path4) => !preDirty.has(path4));
162853
- if (dirtied.length === 0) return;
162854
- const result = await spawn3({
162855
- cmd: "git",
162856
- args: ["restore", "--staged", "--worktree", "--", ...dirtied],
162857
- env: process.env,
162858
- activityTimeout: 0
162859
- });
162860
- if (result.exitCode !== 0) {
162861
- log.warning(
162862
- `\xBB failed to restore ${dirtied.length} tracked file(s) modified by prep: ${result.stderr.trim() || "(no stderr)"}`
162863
- );
162864
- return;
162865
- }
162866
- log.info(`\xBB restored ${dirtied.length} tracked file(s) modified by prep: ${dirtied.join(", ")}`);
162867
- }
162868
163072
  async function runPrepPhase(options) {
162869
163073
  log.debug("\xBB starting prep phase...");
162870
163074
  const startTime = performance8.now();
@@ -162887,7 +163091,7 @@ async function runPrepPhase(options) {
162887
163091
  }
162888
163092
  }
162889
163093
  } finally {
162890
- await restorePrepDirtiedFiles(preDirty);
163094
+ await restoreDirtiedSince({ before: preDirty, actor: "prep" });
162891
163095
  }
162892
163096
  const totalDurationMs = performance8.now() - startTime;
162893
163097
  log.debug(`\xBB prep phase completed (${Math.round(totalDurationMs)}ms)`);
@@ -164103,13 +164307,38 @@ function buildThreadBlocks(threads, filePatchMap, reviewId) {
164103
164307
  }
164104
164308
  return threadBlocks;
164105
164309
  }
164310
+ var fetchAllReviewThreads = op(
164311
+ async (key, ctx) => {
164312
+ const response = await ctx.octokit.graphql(REVIEW_THREADS_QUERY, {
164313
+ owner: key.owner,
164314
+ name: key.name,
164315
+ prNumber: key.pullNumber
164316
+ });
164317
+ return response.repository?.pullRequest?.reviewThreads?.nodes ?? [];
164318
+ },
164319
+ { ttl: 6e4, name: "reviewThreads" }
164320
+ );
164321
+ var fetchPrFiles = op(
164322
+ async (key, ctx) => ctx.octokit.paginate(ctx.octokit.rest.pulls.listFiles, {
164323
+ owner: key.owner,
164324
+ repo: key.name,
164325
+ pull_number: key.pullNumber,
164326
+ per_page: 100
164327
+ }),
164328
+ { ttl: 6e4, name: "prFiles" }
164329
+ );
164330
+ function invalidateReviewThreadCache(repo) {
164331
+ fetchAllReviewThreads.invalidate(
164332
+ (cached4) => cached4.owner === repo.owner && cached4.name === repo.name
164333
+ );
164334
+ }
164106
164335
  async function getReviewThreads(input) {
164107
- const response = await input.octokit.graphql(REVIEW_THREADS_QUERY, {
164108
- owner: input.owner,
164109
- name: input.name,
164110
- prNumber: input.pullNumber
164111
- });
164112
- const allThreads = response.repository?.pullRequest?.reviewThreads?.nodes ?? [];
164336
+ const allThreads = structuredClone(
164337
+ await fetchAllReviewThreads(
164338
+ { owner: input.owner, name: input.name, pullNumber: input.pullNumber },
164339
+ { octokit: input.octokit }
164340
+ )
164341
+ );
164113
164342
  if (allThreads.length >= 100) {
164114
164343
  log.warning(
164115
164344
  `PR ${input.owner}/${input.name}#${input.pullNumber}: reviewThreads returned 100 results (limit reached, some threads may be missing)`
@@ -164166,12 +164395,10 @@ async function getReviewData(input) {
164166
164395
  }),
164167
164396
  getReviewThreads(input)
164168
164397
  ]);
164169
- const prFiles = threads.length > 0 ? await input.octokit.paginate(input.octokit.rest.pulls.listFiles, {
164170
- owner: input.owner,
164171
- repo: input.name,
164172
- pull_number: input.pullNumber,
164173
- per_page: 100
164174
- }) : [];
164398
+ const prFiles = threads.length > 0 ? await fetchPrFiles(
164399
+ { owner: input.owner, name: input.name, pullNumber: input.pullNumber },
164400
+ { octokit: input.octokit }
164401
+ ) : [];
164175
164402
  if (review.data.body) {
164176
164403
  review.data.body = await resolveBodyAssets({
164177
164404
  body: review.data.body,
@@ -164315,6 +164542,7 @@ function ResolveReviewThreadTool(ctx) {
164315
164542
  });
164316
164543
  const thread = response.resolveReviewThread.thread;
164317
164544
  log.info(`\xBB resolved review thread ${thread.id}`);
164545
+ invalidateReviewThreadCache({ owner: ctx.repo.owner, name: ctx.repo.name });
164318
164546
  return {
164319
164547
  thread_id: thread.id,
164320
164548
  is_resolved: thread.isResolved,
@@ -164489,7 +164717,10 @@ import { join as join21 } from "node:path";
164489
164717
  import { setTimeout as sleep2 } from "node:timers/promises";
164490
164718
  var ShellParams = type({
164491
164719
  command: "string",
164492
- description: "string",
164720
+ // advisory and unread — no code path consumes it. kept in the schema only
164721
+ // because it nudges the model to state intent before running a command;
164722
+ // REQUIRING it cost a full rejected turn every time one was omitted. #1140.
164723
+ "description?": "string",
164493
164724
  "timeout?": type.number.describe(
164494
164725
  "Timeout in MILLISECONDS (not seconds). Default 30000 (30s), max 120000 (2m). e.g. timeout: 180000 for 3 minutes; timeout: 180 means 180ms and will kill the process almost immediately."
164495
164726
  ),
@@ -164497,6 +164728,7 @@ var ShellParams = type({
164497
164728
  "background?": "boolean"
164498
164729
  });
164499
164730
  var detectedSandboxMethod;
164731
+ var usernsProbeError;
164500
164732
  function detectSandboxMethod() {
164501
164733
  if (detectedSandboxMethod !== void 0) {
164502
164734
  return detectedSandboxMethod;
@@ -164530,6 +164762,35 @@ function detectSandboxMethod() {
164530
164762
  }
164531
164763
  } catch {
164532
164764
  }
164765
+ try {
164766
+ const result = spawnSync6(
164767
+ "unshare",
164768
+ [
164769
+ "--user",
164770
+ "--map-root-user",
164771
+ "--pid",
164772
+ "--fork",
164773
+ "--mount",
164774
+ "setpriv",
164775
+ "--no-new-privs",
164776
+ "--bounding-set",
164777
+ "-all",
164778
+ "--inh-caps",
164779
+ "-all",
164780
+ "--ambient-caps",
164781
+ "-all",
164782
+ "true"
164783
+ ],
164784
+ { timeout: 5e3, stdio: ["ignore", "ignore", "pipe"] }
164785
+ );
164786
+ if (result.status === 0) {
164787
+ detectedSandboxMethod = "userns-unshare";
164788
+ log.debug("PID namespace isolation enabled (unprivileged userns unshare)");
164789
+ return "userns-unshare";
164790
+ }
164791
+ usernsProbeError = result.stderr?.toString().trim() || result.error?.message;
164792
+ } catch {
164793
+ }
164533
164794
  detectedSandboxMethod = "none";
164534
164795
  log.info("PID namespace isolation not available");
164535
164796
  return "none";
@@ -164577,7 +164838,7 @@ function spawnShell(params) {
164577
164838
  const ci = process.env.CI === "true";
164578
164839
  if (ci && sandboxMethod === "none") {
164579
164840
  throw new Error(
164580
- "pid namespace isolation is required in CI but unavailable (both unshare and sudo unshare failed)"
164841
+ "PID-namespace isolation is required in CI but unavailable: unprivileged unshare, sudo unshare, and userns-nested unshare all failed. " + (usernsProbeError ? `userns probe said: ${usernsProbeError}. ` : "") + "on a containerized / Kubernetes self-hosted runner the cause is usually one of: the pod's seccomp profile blocks user-namespace creation (Pod Security Standards baseline/restricted); the pod runs as root without CAP_SETFCAP, which the kernel requires to map uid 0; or the node kernel disallows unprivileged user namespaces (Ubuntu >= 23.10, Bottlerocket, Talos). elsewhere, check that `unshare` and `setpriv` (util-linux >= 2.31, which is what added --ambient-caps) are on PATH. see https://docs.pullfrog.com/security#self-hosted-runners"
164581
164842
  );
164582
164843
  }
164583
164844
  const repoRoot = resolveRepoRoot();
@@ -164596,6 +164857,23 @@ function spawnShell(params) {
164596
164857
  spawnOpts
164597
164858
  );
164598
164859
  }
164860
+ if (sandboxMethod === "userns-unshare") {
164861
+ const escaped = params.command.replace(/'/g, "'\\''");
164862
+ return spawn5(
164863
+ "unshare",
164864
+ [
164865
+ "--user",
164866
+ "--map-root-user",
164867
+ "--pid",
164868
+ "--fork",
164869
+ "--mount",
164870
+ "bash",
164871
+ "-c",
164872
+ `${PROC_CLEANUP} ${SOCKET_CLEANUP} ${fsMounts} exec setpriv --no-new-privs --bounding-set -all --inh-caps -all --ambient-caps -all bash -c '${escaped}'`
164873
+ ],
164874
+ spawnOpts
164875
+ );
164876
+ }
164599
164877
  if (sandboxMethod === "sudo-unshare") {
164600
164878
  const envArgs = [];
164601
164879
  for (const [k, v] of Object.entries(params.env)) {
@@ -164759,6 +165037,8 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
164759
165037
  proc.on("exit", done);
164760
165038
  proc.on("error", () => done(null));
164761
165039
  });
165040
+ proc.stdout?.destroy();
165041
+ proc.stderr?.destroy();
164762
165042
  let output = stderr ? stdout ? `${stdout}
164763
165043
  ${stderr}` : stderr : stdout;
164764
165044
  if (timedOut)
@@ -165002,6 +165282,7 @@ function CheckoutRepoTool(ctx) {
165002
165282
  owner,
165003
165283
  name: repo,
165004
165284
  gitToken: rc.gitToken,
165285
+ refreshGitToken: rc.refreshGitToken,
165005
165286
  octokit: rc.octokit,
165006
165287
  toolState: ctx.toolState,
165007
165288
  shell: ctx.payload.shell,
@@ -165498,14 +165779,22 @@ function validateAgentApiKey(params) {
165498
165779
  }
165499
165780
  function isApiKeyAuthError(text) {
165500
165781
  if (!text) return false;
165501
- return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isClaudeSubscriptionDisabledError(text) || isOAuthCredentialExpiredError(text);
165782
+ return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isClaudeSubscriptionDisabledError(text) || isClaudeSessionLimitError(text) || isOAuthCredentialExpiredError(text);
165502
165783
  }
165503
165784
  function isOAuthCredentialExpiredError(text) {
165504
- return /authentication token has (expired|been invalidated)/i.test(text) || /OAuth access token has expired/i.test(text) || /Token refresh failed/i.test(text);
165785
+ return /(?:authentication|OAuth access) token has (?:expired|been (?:invalidated|revoked))/i.test(
165786
+ text
165787
+ ) || // the provider no longer recognises the token at all (#1086) — same dead
165788
+ // credential, phrased as a lookup miss rather than a state transition.
165789
+ /Could not find the appropriate key in your authentication token/i.test(text) || /Token refresh failed/i.test(text);
165505
165790
  }
165506
165791
  function isClaudeSubscriptionDisabledError(text) {
165507
165792
  return /disabled Claude subscription access/i.test(text);
165508
165793
  }
165794
+ var CLAUDE_SESSION_LIMIT_PATTERN = /hit your (?:session|weekly|five-hour|Opus|Sonnet|Haiku)\s+limit(?:\s*·\s*resets\s+([^"\n]+))?/i;
165795
+ function isClaudeSessionLimitError(text) {
165796
+ return CLAUDE_SESSION_LIMIT_PATTERN.test(text);
165797
+ }
165509
165798
  function formatApiKeyErrorSummary(params) {
165510
165799
  if (params.raw.includes(MISSING_KEY_MARKER)) {
165511
165800
  if (params.raw.startsWith(`**${MISSING_KEY_MARKER}**`)) return params.raw;
@@ -165513,6 +165802,15 @@ function formatApiKeyErrorSummary(params) {
165513
165802
  }
165514
165803
  const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
165515
165804
  const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
165805
+ if (isClaudeSessionLimitError(params.raw)) {
165806
+ const reset = CLAUDE_SESSION_LIMIT_PATTERN.exec(params.raw)?.[1]?.trim();
165807
+ const resets = reset ? ` It resets at **${reset}**.` : "";
165808
+ return [
165809
+ `**Your Claude subscription has hit its usage limit.**${resets} Re-trigger Pullfrog after the reset, or add an \`ANTHROPIC_API_KEY\` repo secret \u2014 Pullfrog routes around an exhausted subscription automatically when one is present.`,
165810
+ "",
165811
+ `[Add repo secret \u2192](${githubSecretsUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
165812
+ ].join("\n");
165813
+ }
165516
165814
  if (isClaudeSubscriptionDisabledError(params.raw)) {
165517
165815
  return [
165518
165816
  `**Your organization has disabled Claude subscription access for Claude Code.** Ask your Claude organization's admin to re-enable it in the Claude Console, or set an \`ANTHROPIC_API_KEY\` for this repo instead, then re-trigger the run.`,
@@ -166322,7 +166620,9 @@ function decideModelAccess(input) {
166322
166620
  if (input.proxyActive) {
166323
166621
  const target = resolveOpenRouterModel(input.model);
166324
166622
  if (input.oss) {
166325
- if (target && target === input.subsidyTarget) return { kind: "proxy", target };
166623
+ if (target && (target === input.subsidyTarget || isOssAllowedModel(input.model))) {
166624
+ return { kind: "proxy", target };
166625
+ }
166326
166626
  if (byokAuthorized) return { kind: "byok" };
166327
166627
  return { kind: "error", reason: "oss" };
166328
166628
  }
@@ -166334,6 +166634,11 @@ function decideModelAccess(input) {
166334
166634
  return { kind: "error", reason: "byok_no_key" };
166335
166635
  }
166336
166636
  var MODEL_ACCESS_MARKER = "requested model is not available";
166637
+ function ossAllowedLabels() {
166638
+ return OSS_MODEL_ALLOWLIST.map(
166639
+ (slug2) => `\`${resolveDisplayAlias(slug2)?.displayName ?? slug2}\``
166640
+ ).join(", ");
166641
+ }
166337
166642
  function buildModelAccessError(input) {
166338
166643
  const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
166339
166644
  const secretsUrl = `https://github.com/${input.owner}/${input.name}/settings/secrets/actions`;
@@ -166341,8 +166646,8 @@ function buildModelAccessError(input) {
166341
166646
  const headline = `**The ${MODEL_ACCESS_MARKER}: \`${input.model}\`.**`;
166342
166647
  const branch = {
166343
166648
  oss: {
166344
- why: "This repo runs on Pullfrog's OSS subsidy, which only funds the default model. Switch back to the funded model, or add your own provider key to run a different one.",
166345
- cta: `[Add a provider key \u2192](${secretsUrl}) \xB7 [Setup docs \u2192](${docsUrl})`
166649
+ why: `This repo runs on Pullfrog's OSS subsidy, which funds a set of pre-approved models: ${ossAllowedLabels()}. Pick one of those, or add your own provider key to run a different one.`,
166650
+ cta: `[Configure model \u2192](${settingsUrl}) \xB7 [Add a provider key \u2192](${secretsUrl}) \xB7 [Setup docs \u2192](${docsUrl})`
166346
166651
  },
166347
166652
  byok_no_key: {
166348
166653
  why: `No provider key for \`${input.model}\` is present in this run's environment. Add the matching provider key as a GitHub Actions secret, or pick a model you already have a key for.`,
@@ -166498,12 +166803,14 @@ var ShellPermissionInput = type.enumerated("disabled", "restricted", "enabled");
166498
166803
  var PushPermissionInput = type.enumerated("disabled", "restricted", "enabled");
166499
166804
  var StatusChecksInput = type.enumerated("disabled", "enabled");
166500
166805
  var ProgressCommentsInput = type.enumerated("disabled", "enabled");
166806
+ var DebugInput = type.enumerated("disabled", "enabled");
166501
166807
  var JsonPayload = type({
166502
166808
  "~pullfrog": "true",
166503
166809
  version: "string",
166504
166810
  "model?": "string | undefined",
166505
166811
  "modelExplicit?": "boolean | undefined",
166506
166812
  "effort?": "number | string | undefined",
166813
+ "debug?": "boolean | undefined",
166507
166814
  prompt: "string",
166508
166815
  "triggerer?": "string | undefined",
166509
166816
  "baseInstructions?": "string | undefined",
@@ -166538,6 +166845,7 @@ var Inputs = type({
166538
166845
  "prompt_file?": type.string.or("undefined"),
166539
166846
  "model?": type.string.or("undefined"),
166540
166847
  "effort?": type.string.or("undefined"),
166848
+ "debug?": DebugInput.or("undefined"),
166541
166849
  "timeout?": type.string.or("undefined"),
166542
166850
  "push?": PushPermissionInput.or("undefined"),
166543
166851
  "shell?": ShellPermissionInput.or("undefined"),
@@ -166589,15 +166897,24 @@ function resolvePromptFile(input) {
166589
166897
  }
166590
166898
  return content;
166591
166899
  }
166900
+ function warnIfDeprecatedStatusChecks(value2) {
166901
+ if (value2 !== void 0) {
166902
+ core6.warning(
166903
+ "`status_checks` is deprecated. Both checks are now repository settings \u2014 open the Pullfrog console for this repo (Automations \u2192 Review PRs) and set them there, then remove `status_checks` from your workflow. It keeps working until you do."
166904
+ );
166905
+ }
166906
+ return value2;
166907
+ }
166592
166908
  function resolveNonPromptInputs() {
166593
166909
  return Inputs.omit("prompt", "prompt_file").assert({
166594
166910
  model: core6.getInput("model") || void 0,
166595
166911
  effort: core6.getInput("effort") || void 0,
166912
+ debug: core6.getInput("debug") || void 0,
166596
166913
  timeout: core6.getInput("timeout") || void 0,
166597
166914
  cwd: core6.getInput("cwd") || void 0,
166598
166915
  push: core6.getInput("push") || void 0,
166599
166916
  shell: core6.getInput("shell") || void 0,
166600
- status_checks: core6.getInput("status_checks") || void 0,
166917
+ status_checks: warnIfDeprecatedStatusChecks(core6.getInput("status_checks") || void 0),
166601
166918
  progress_comments: core6.getInput("progress_comments") || void 0
166602
166919
  });
166603
166920
  }
@@ -166609,6 +166926,8 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
166609
166926
  const model = jsonPayload?.model ?? inputs.model ?? repoSettings.model ?? void 0;
166610
166927
  const rawEffort = jsonPayload?.effort ?? inputs.effort ?? repoSettings.effort ?? void 0;
166611
166928
  const effort = rawEffort === void 0 ? void 0 : parseEffortPosition(String(rawEffort));
166929
+ const debug4 = jsonPayload?.debug ?? inputs.debug === "enabled";
166930
+ if (debug4) process.env.LOG_LEVEL = "debug";
166612
166931
  const isNonCollaborator = !isCollaborator(event);
166613
166932
  const repoShell = repoSettings.shell ?? "restricted";
166614
166933
  const inputShell = inputs.shell;
@@ -166629,6 +166948,7 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
166629
166948
  // the JSON payload). a GHA `model` input or the repo default is not explicit.
166630
166949
  modelExplicit: jsonPayload?.modelExplicit ?? false,
166631
166950
  effort,
166951
+ debug: debug4 || void 0,
166632
166952
  prompt,
166633
166953
  triggerer: jsonPayload?.triggerer ?? // it's not a common use case but GITHUB_ACTOR can be a user when the workflow is manually triggered by a user through GitHub Actions UI
166634
166954
  (!isPullfrog(process.env.GITHUB_ACTOR) ? process.env.GITHUB_ACTOR : void 0),
@@ -166650,9 +166970,11 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
166650
166970
  // input is the source of truth when set (mirrors `push`); otherwise the repo
166651
166971
  // setting decides.
166652
166972
  runStatusCheck: inputs.status_checks === void 0 ? repoSettings.statusChecks : inputs.status_checks === "enabled",
166653
- // the `pullfrog-approval` verdict check stays opt-in and workflow-only. it exists to
166654
- // be *required* by branch protection, so it must never turn itself on.
166655
- approvalCheck: inputs.status_checks === "enabled",
166973
+ // the `pullfrog-approval` verdict check. `Repo.approvalCheck` is authoritative; the
166974
+ // `status_checks` input is DEPRECATED but still honoured, for the dormant installs the
166975
+ // backfill could not read (see `warnIfDeprecatedStatusChecks`). OR rather than override:
166976
+ // this can only ever turn the check ON, never off, so no existing user loses it.
166977
+ approvalCheck: repoSettings.approvalCheck || inputs.status_checks === "enabled",
166656
166978
  // temporary progress chrome. the workflow input is the source of truth when
166657
166979
  // set (mirrors `push`); otherwise the repo setting decides. defaults to true.
166658
166980
  progressComments: inputs.progress_comments === void 0 ? repoSettings.progressComments : inputs.progress_comments === "enabled",
@@ -167024,7 +167346,7 @@ async function resolveProxyModel(ctx) {
167024
167346
  if (ctx.oss) {
167025
167347
  ctx.toolState.modelClamped = { from: ctx.payload.model, reason: "oss" };
167026
167348
  log.info(
167027
- `\xBB ${ctx.payload.model} overridden \u2014 Pullfrog for OSS covers ${ctx.proxyModel}; add a provider key in your Pullfrog settings to run your configured model.`
167349
+ `\xBB ${ctx.payload.model} overridden \u2014 it is not one of the models Pullfrog for OSS funds, so this run uses ${ctx.proxyModel}; pick a funded model in your Pullfrog settings, or add a provider key to run your own.`
167028
167350
  );
167029
167351
  } else if (isCardGatedModel(ctx.payload.model)) {
167030
167352
  ctx.toolState.modelClamped = { from: ctx.payload.model, reason: "card" };
@@ -167226,6 +167548,7 @@ var defaultSettings = {
167226
167548
  repoIntelligence: false,
167227
167549
  progressComments: true,
167228
167550
  statusChecks: true,
167551
+ approvalCheck: false,
167229
167552
  modeInstructions: {},
167230
167553
  learnings: null,
167231
167554
  learningsHeadings: [],
@@ -167453,6 +167776,40 @@ function formatBillingExhaustedBody(diagnostic) {
167453
167776
  function isProviderModelNotFoundError(message) {
167454
167777
  return message.includes("ProviderModelNotFoundError");
167455
167778
  }
167779
+ function isContextOverflowError(message) {
167780
+ return /Prompt is too long/i.test(message) || /Input exceeds context window/i.test(message) || /maximum context length is \d+ tokens/i.test(message) || /Session too large to compact/i.test(message);
167781
+ }
167782
+ function isNoProviderAvailableError(message) {
167783
+ return /\bNo provider available\b/i.test(message);
167784
+ }
167785
+ function formatNoProviderAvailableSummary(input) {
167786
+ const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
167787
+ return [
167788
+ "**The provider refused to serve this model.** It's listed in the catalog, but the account this run used has no access to it \u2014 so the request was accepted and then declined.",
167789
+ "",
167790
+ "This often happens when Pullfrog auto-selects a model your account can't reach. Pin an explicit model for this repo, or add credentials for the provider that was picked.",
167791
+ "",
167792
+ `[Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
167793
+ "",
167794
+ `\`\`\`
167795
+ ${input.raw}
167796
+ \`\`\``
167797
+ ].join("\n");
167798
+ }
167799
+ function formatContextOverflowSummary(input) {
167800
+ const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
167801
+ return [
167802
+ "**This run exceeded the model's context window.** Pullfrog read more than the model could hold, so it stopped before finishing.",
167803
+ "",
167804
+ `Pick a model with a larger context window, or split this PR into smaller ones and re-trigger.`,
167805
+ "",
167806
+ `[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
167807
+ "",
167808
+ `\`\`\`
167809
+ ${input.raw}
167810
+ \`\`\``
167811
+ ].join("\n");
167812
+ }
167456
167813
  function formatGenericFailure(errorMessage) {
167457
167814
  return [
167458
167815
  "Pullfrog ran into an unexpected error and couldn't finish this run. The underlying error is below \u2014 re-trigger Pullfrog to try again, and reach out to support if it keeps happening.",
@@ -167474,12 +167831,18 @@ var PROVIDER_BILLING_URLS = {
167474
167831
  anthropic: "https://console.anthropic.com/settings/billing",
167475
167832
  openai: "https://platform.openai.com/account/billing",
167476
167833
  google: "https://aistudio.google.com/usage",
167477
- opencode: "https://opencode.ai/zen"
167834
+ opencode: "https://opencode.ai/zen",
167835
+ xai: "https://console.x.ai/team/default/billing",
167836
+ openrouter: "https://openrouter.ai/settings/credits"
167478
167837
  };
167479
167838
  function detectProviderId(message) {
167480
167839
  const harnessId = extractProviderId(message);
167481
167840
  if (harnessId) return harnessId;
167482
167841
  if (/credit balance is too low/i.test(message)) return "anthropic";
167842
+ if (/used all available credits/i.test(message)) return "xai";
167843
+ if (/requires more credits|Key limit exceeded \(total limit\)|openrouter\.ai/i.test(message)) {
167844
+ return "openrouter";
167845
+ }
167483
167846
  return null;
167484
167847
  }
167485
167848
  function formatProviderBillingExhausted(input) {
@@ -167507,7 +167870,7 @@ ${input.raw}
167507
167870
  \`\`\``;
167508
167871
  }
167509
167872
  function renderRunError(input) {
167510
- const billingError = isRouterKeylimitExhaustedError(input.errorMessage) ? new BillingError(input.errorMessage, { code: "router_keylimit_exhausted" }) : null;
167873
+ const billingError = input.routerActive && isRouterKeylimitExhaustedError(input.errorMessage) ? new BillingError(input.errorMessage, { code: "router_keylimit_exhausted" }) : null;
167511
167874
  if (billingError) {
167512
167875
  const body = formatBillingErrorSummary(billingError, input.repo.owner);
167513
167876
  return { summary: body, comment: body };
@@ -167547,6 +167910,26 @@ ${body}`, comment: body };
167547
167910
  });
167548
167911
  return { summary: body, comment: body };
167549
167912
  }
167913
+ if (isNoProviderAvailableError(input.errorMessage)) {
167914
+ const body = formatNoProviderAvailableSummary({
167915
+ owner: input.repo.owner,
167916
+ name: input.repo.name,
167917
+ raw: input.errorMessage
167918
+ });
167919
+ return { summary: `### \u274C Pullfrog failed
167920
+
167921
+ ${body}`, comment: body };
167922
+ }
167923
+ if (isContextOverflowError(input.errorMessage)) {
167924
+ const body = formatContextOverflowSummary({
167925
+ owner: input.repo.owner,
167926
+ name: input.repo.name,
167927
+ raw: input.errorMessage
167928
+ });
167929
+ return { summary: `### \u274C Pullfrog failed
167930
+
167931
+ ${body}`, comment: body };
167932
+ }
167550
167933
  if (hangBody) {
167551
167934
  const isBillingExhausted = input.agentDiagnostic?.lastProviderError === "provider billing exhausted";
167552
167935
  return {
@@ -167927,7 +168310,8 @@ async function finalizeSuccessRun(input) {
167927
168310
  const rendered = !input.result.success ? renderRunError({
167928
168311
  errorMessage: input.result.error || "agent run failed",
167929
168312
  repo: input.repo,
167930
- agentDiagnostic: input.toolState.agentDiagnostic
168313
+ agentDiagnostic: input.toolState.agentDiagnostic,
168314
+ routerActive: !!input.toolContext.payload.proxyModel
167931
168315
  }) : null;
167932
168316
  if (rendered) {
167933
168317
  await reportErrorToComment({
@@ -168375,7 +168759,9 @@ async function main() {
168375
168759
  }
168376
168760
  if (access.kind === "proxy") payload.proxyModel = access.target;
168377
168761
  if (access.kind === "byok") payload.proxyModel = void 0;
168378
- if (runContext.oss && payload.proxyModel) payload.effort = 0;
168762
+ if (runContext.oss && payload.proxyModel) {
168763
+ payload.effort = ossEffortFloor({ payload });
168764
+ }
168379
168765
  const resolvedModel = payload.proxyModel ? void 0 : resolveModel({ slug: payload.model });
168380
168766
  vertexCredentials = materializeVertexCredentials({ model: resolvedModel });
168381
168767
  const agent2 = resolveAgent({ model: resolvedModel });
@@ -168402,8 +168788,15 @@ async function main() {
168402
168788
  });
168403
168789
  timer.checkpoint("git");
168404
168790
  const pmSpec = await resolvePackageManagerSpec(process.cwd());
168405
- if (pmSpec) {
168406
- await ensurePackageManager({ spec: pmSpec, binDir: packageManagerBinDir(tmpdir4) });
168791
+ const pmDetected = await detect({ cwd: process.cwd(), strategies: ["lockfile"] });
168792
+ const pmName = pmSpec?.name ?? pmDetected?.name ?? "npm";
168793
+ if (payload.shell !== "disabled") {
168794
+ const pmError = await provisionPackageManager({
168795
+ name: pmName,
168796
+ declared: pmSpec,
168797
+ binDir: packageManagerBinDir(tmpdir4)
168798
+ });
168799
+ if (pmError) log.warning(`\xBB could not provision ${pmName}: ${pmError}`);
168407
168800
  }
168408
168801
  timer.checkpoint("packageManager");
168409
168802
  const setupHook = await executeLifecycleHook({
@@ -168683,7 +169076,8 @@ ${instructions.user}` : null,
168683
169076
  const rendered = renderRunError({
168684
169077
  errorMessage,
168685
169078
  repo: runContext.repo,
168686
- agentDiagnostic: toolState.agentDiagnostic
169079
+ agentDiagnostic: toolState.agentDiagnostic,
169080
+ routerActive: !!payload.proxyModel
168687
169081
  });
168688
169082
  await writeRunErrorOutputs({ rendered, toolState });
168689
169083
  if (toolContext) {
@@ -169718,7 +170112,7 @@ async function runCli4(input) {
169718
170112
  }
169719
170113
 
169720
170114
  // cli.ts
169721
- var VERSION10 = "0.1.51";
170115
+ var VERSION10 = "0.1.53";
169722
170116
  var bin = basename2(process.argv[1] || "");
169723
170117
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
169724
170118
  var rawArgs = process.argv.slice(2);
@@ -169821,6 +170215,7 @@ async function run3() {
169821
170215
  }
169822
170216
  try {
169823
170217
  await run3();
170218
+ process.exit(process.exitCode ?? 0);
169824
170219
  } catch (error49) {
169825
170220
  const message = error49 instanceof Error ? error49.message : String(error49);
169826
170221
  console.error(import_picocolors5.default.red(message));