pullfrog 0.1.50 → 0.1.52

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"
101879
102181
  },
101880
- // dropped hidden subagent tier folds stored pins forward to gpt (Sol).
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"
102201
+ },
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",
@@ -101958,12 +102280,20 @@ var providers = {
101958
102280
  openRouterResolve: "openrouter/deepseek/deepseek-v4-pro",
101959
102281
  preferred: true
101960
102282
  },
102283
+ // DeepSeek upgraded the `deepseek-v4-flash` API model in place to the
102284
+ // 0731 release, but OpenRouter forked it into a separate `-0731` id and
102285
+ // left the April preview live at a HIGHER price — so the direct
102286
+ // `resolve` needs no version and the OpenRouter route must be pinned.
102287
+ // 0731 publishes a DIFFERENT OpenRouter ladder to both the April preview
102288
+ // and Pro (`high, xhigh`) — it gained a `low` rung and renamed the top to
102289
+ // `max`. that makes `low`, not `high`, position 0 on this route, which is
102290
+ // why the OSS effort floor in `main.ts` pins the `high` rung by name.
101961
102291
  "deepseek-flash": {
101962
102292
  displayName: "DeepSeek Flash",
101963
102293
  resolve: "deepseek/deepseek-v4-flash",
101964
102294
  effort: ["high", "max"],
101965
- openRouterEffort: ["high", "xhigh"],
101966
- openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
102295
+ openRouterEffort: ["low", "high", "max"],
102296
+ openRouterResolve: "openrouter/deepseek/deepseek-v4-flash-0731"
101967
102297
  },
101968
102298
  // legacy aliases — deepseek retires these on 2026-07-24; transparently
101969
102299
  // upgrade existing users to the v4 family via the fallback chain.
@@ -102032,30 +102362,30 @@ var providers = {
102032
102362
  resolve: "opencode/claude-haiku-4-5",
102033
102363
  openRouterResolve: "openrouter/anthropic/claude-haiku-4.5"
102034
102364
  },
102035
- gpt: {
102365
+ "gpt-sol": {
102036
102366
  displayName: "GPT Sol",
102037
102367
  resolve: "opencode/gpt-5.6-sol",
102038
102368
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102039
102369
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102040
102370
  subagentModel: "gpt-terra"
102041
102371
  },
102042
- // see openai/gpt-pro — Zen has no -pro id, so direct resolves to plain Sol.
102043
- "gpt-pro": {
102372
+ // see openai/gpt-sol-pro — Zen has no -pro id, so direct resolves to plain Sol.
102373
+ "gpt-sol-pro": {
102044
102374
  displayName: "GPT Sol Pro",
102045
102375
  description: "Maximum reasoning effort",
102046
102376
  resolve: "opencode/gpt-5.6-sol",
102047
102377
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102048
102378
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102049
- subagentModel: "gpt"
102379
+ subagentModel: "gpt-sol"
102050
102380
  },
102051
- // gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
102381
+ // gpt-5.6 balanced mid-tier — selectable + Sol's subagent. see openai above.
102052
102382
  "gpt-terra": {
102053
102383
  displayName: "GPT Terra",
102054
102384
  resolve: "opencode/gpt-5.6-terra",
102055
102385
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102056
102386
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
102057
102387
  },
102058
- "gpt-mini": {
102388
+ "gpt-luna": {
102059
102389
  displayName: "GPT Luna",
102060
102390
  resolve: "opencode/gpt-5.6-luna",
102061
102391
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -102066,20 +102396,39 @@ var providers = {
102066
102396
  displayName: "GPT Codex",
102067
102397
  resolve: "opencode/gpt-5.3-codex",
102068
102398
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
102069
- fallback: "opencode/gpt"
102399
+ fallback: "opencode/gpt-sol"
102070
102400
  },
102071
102401
  "gpt-codex-mini": {
102072
102402
  displayName: "GPT Codex Mini",
102073
102403
  resolve: "opencode/gpt-5.1-codex-mini",
102074
102404
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
102075
- fallback: "opencode/gpt-mini"
102405
+ fallback: "opencode/gpt-luna"
102406
+ },
102407
+ // pre-5.6 tier slugs — see openai provider above.
102408
+ gpt: {
102409
+ displayName: "GPT",
102410
+ resolve: "opencode/gpt-5.6-sol",
102411
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102412
+ fallback: "opencode/gpt-sol"
102076
102413
  },
102077
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
102414
+ "gpt-pro": {
102415
+ displayName: "GPT Pro",
102416
+ resolve: "opencode/gpt-5.6-sol",
102417
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102418
+ fallback: "opencode/gpt-sol-pro"
102419
+ },
102420
+ "gpt-mini": {
102421
+ displayName: "GPT Mini",
102422
+ resolve: "opencode/gpt-5.6-luna",
102423
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
102424
+ fallback: "opencode/gpt-luna"
102425
+ },
102426
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
102078
102427
  "gpt-5.4": {
102079
102428
  displayName: "GPT 5.4",
102080
102429
  resolve: "opencode/gpt-5.4",
102081
102430
  openRouterResolve: "openrouter/openai/gpt-5.4",
102082
- fallback: "opencode/gpt"
102431
+ fallback: "opencode/gpt-sol"
102083
102432
  },
102084
102433
  "gemini-pro": {
102085
102434
  displayName: "Gemini Pro",
@@ -102235,30 +102584,30 @@ var providers = {
102235
102584
  // alias): after the Sol/Terra/Luna rename, ~gpt-mini-latest no longer maps
102236
102585
  // to Luna, so rolling aliases would silently diverge `gpt`/`gpt-mini` from
102237
102586
  // the chosen tiers across funding paths.
102238
- gpt: {
102587
+ "gpt-sol": {
102239
102588
  displayName: "GPT Sol",
102240
102589
  resolve: "openrouter/openai/gpt-5.6-sol",
102241
102590
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102242
102591
  openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102243
102592
  subagentModel: "gpt-terra"
102244
102593
  },
102245
- // see openai/gpt-pro. openrouter serves sol-pro directly on both routes.
102246
- "gpt-pro": {
102594
+ // see openai/gpt-sol-pro. openrouter serves sol-pro directly on both routes.
102595
+ "gpt-sol-pro": {
102247
102596
  displayName: "GPT Sol Pro",
102248
102597
  description: "Maximum reasoning effort",
102249
102598
  resolve: "openrouter/openai/gpt-5.6-sol-pro",
102250
102599
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102251
102600
  openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102252
- subagentModel: "gpt"
102601
+ subagentModel: "gpt-sol"
102253
102602
  },
102254
- // gpt-5.6 balanced mid-tier — selectable + `gpt`'s subagent. see openai above.
102603
+ // gpt-5.6 balanced mid-tier — selectable + Sol's subagent. see openai above.
102255
102604
  "gpt-terra": {
102256
102605
  displayName: "GPT Terra",
102257
102606
  resolve: "openrouter/openai/gpt-5.6-terra",
102258
102607
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
102259
102608
  openRouterResolve: "openrouter/openai/gpt-5.6-terra"
102260
102609
  },
102261
- "gpt-mini": {
102610
+ "gpt-luna": {
102262
102611
  displayName: "GPT Luna",
102263
102612
  resolve: "openrouter/openai/gpt-5.6-luna",
102264
102613
  effort: ["none", "low", "medium", "high", "xhigh", "max"],
@@ -102269,20 +102618,39 @@ var providers = {
102269
102618
  displayName: "GPT Codex",
102270
102619
  resolve: "openrouter/openai/gpt-5.3-codex",
102271
102620
  openRouterResolve: "openrouter/openai/gpt-5.3-codex",
102272
- fallback: "openrouter/gpt"
102621
+ fallback: "openrouter/gpt-sol"
102273
102622
  },
102274
102623
  "gpt-codex-mini": {
102275
102624
  displayName: "GPT Codex Mini",
102276
102625
  resolve: "openrouter/openai/gpt-5.1-codex-mini",
102277
102626
  openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini",
102278
- fallback: "openrouter/gpt-mini"
102627
+ fallback: "openrouter/gpt-luna"
102628
+ },
102629
+ // pre-5.6 tier slugs — see openai provider above.
102630
+ gpt: {
102631
+ displayName: "GPT",
102632
+ resolve: "openrouter/openai/gpt-5.6-sol",
102633
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol",
102634
+ fallback: "openrouter/gpt-sol"
102635
+ },
102636
+ "gpt-pro": {
102637
+ displayName: "GPT Pro",
102638
+ resolve: "openrouter/openai/gpt-5.6-sol-pro",
102639
+ openRouterResolve: "openrouter/openai/gpt-5.6-sol-pro",
102640
+ fallback: "openrouter/gpt-sol-pro"
102279
102641
  },
102280
- // dropped hidden subagent tier — folds stored pins forward to gpt (Sol).
102642
+ "gpt-mini": {
102643
+ displayName: "GPT Mini",
102644
+ resolve: "openrouter/openai/gpt-5.6-luna",
102645
+ openRouterResolve: "openrouter/openai/gpt-5.6-luna",
102646
+ fallback: "openrouter/gpt-luna"
102647
+ },
102648
+ // dropped hidden subagent tier — folds stored pins forward to Sol.
102281
102649
  "gpt-5.4": {
102282
102650
  displayName: "GPT 5.4",
102283
102651
  resolve: "openrouter/openai/gpt-5.4",
102284
102652
  openRouterResolve: "openrouter/openai/gpt-5.4",
102285
- fallback: "openrouter/gpt"
102653
+ fallback: "openrouter/gpt-sol"
102286
102654
  },
102287
102655
  "o4-mini": {
102288
102656
  displayName: "O4 Mini",
@@ -102317,9 +102685,9 @@ var providers = {
102317
102685
  },
102318
102686
  "deepseek-flash": {
102319
102687
  displayName: "DeepSeek Flash",
102320
- resolve: "openrouter/deepseek/deepseek-v4-flash",
102321
- effort: ["high", "xhigh"],
102322
- openRouterResolve: "openrouter/deepseek/deepseek-v4-flash"
102688
+ resolve: "openrouter/deepseek/deepseek-v4-flash-0731",
102689
+ effort: ["low", "high", "max"],
102690
+ openRouterResolve: "openrouter/deepseek/deepseek-v4-flash-0731"
102323
102691
  },
102324
102692
  // legacy alias — deepseek retires this on 2026-07-24; transparently
102325
102693
  // upgrade existing users to the v4 family via the fallback chain.
@@ -102400,7 +102768,7 @@ var modelAliases = Object.entries(providers).flatMap(
102400
102768
  var AUTO_EFFICIENT = "auto/efficient";
102401
102769
  var AUTO_INTELLIGENT = "auto/intelligent";
102402
102770
  var AUTO_TIER_TARGET = {
102403
- [AUTO_EFFICIENT]: "deepseek/deepseek-pro",
102771
+ [AUTO_EFFICIENT]: "deepseek/deepseek-flash",
102404
102772
  [AUTO_INTELLIGENT]: "anthropic/claude-opus"
102405
102773
  };
102406
102774
  function isAutoTier(slug2) {
@@ -102449,6 +102817,26 @@ if (!defaultProxyAlias?.openRouterResolve) {
102449
102817
  }
102450
102818
  var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
102451
102819
  var defaultProxyDisplayName = defaultProxyAlias.displayName;
102820
+ var OSS_MODEL_ALLOWLIST = [
102821
+ "deepseek/deepseek-flash",
102822
+ "deepseek/deepseek-pro",
102823
+ "openai/gpt-luna",
102824
+ "openrouter/minimax-m2.5",
102825
+ "moonshotai/kimi-k2"
102826
+ ];
102827
+ var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
102828
+ var ossAllowedTargets = new Set(
102829
+ OSS_MODEL_ALLOWLIST.map((slug2) => {
102830
+ const target = resolveOpenRouterModel(slug2);
102831
+ if (!target) throw new Error(`OSS_MODEL_ALLOWLIST: ${slug2} has no openRouterResolve`);
102832
+ return target;
102833
+ })
102834
+ );
102835
+ function isOssAllowedModel(slug2) {
102836
+ if (!slug2) return false;
102837
+ const target = resolveOpenRouterModel(slug2);
102838
+ return target !== void 0 && ossAllowedTargets.has(target);
102839
+ }
102452
102840
  var BEDROCK_MODEL_ID_ENV = "BEDROCK_MODEL_ID";
102453
102841
  var VERTEX_MODEL_ID_ENV = "VERTEX_MODEL_ID";
102454
102842
  var OPENAI_COMPATIBLE_PROVIDER = "openai-compatible";
@@ -102482,7 +102870,7 @@ function hasSimilarIssues(params) {
102482
102870
 
102483
102871
  // utils/activity.ts
102484
102872
  import { performance as performance2 } from "node:perf_hooks";
102485
- function isMonitorDebugEnabled() {
102873
+ function isDebugEnabled() {
102486
102874
  return process.env.ACTIONS_STEP_DEBUG === "true" || process.env.RUNNER_DEBUG === "1" || process.env.LOG_LEVEL === "debug";
102487
102875
  }
102488
102876
  var DEFAULT_ACTIVITY_TIMEOUT_MS = 3e5;
@@ -102531,7 +102919,7 @@ function startProcessOutputMonitor(ctx) {
102531
102919
  process.stdout.write = wrapWrite(originalStdoutWrite, markActivity);
102532
102920
  process.stderr.write = wrapWrite(originalStderrWrite, markActivity);
102533
102921
  const debugBypass = (msg) => {
102534
- if (!isMonitorDebugEnabled()) return;
102922
+ if (!isDebugEnabled()) return;
102535
102923
  originalStdoutWrite(`[${(/* @__PURE__ */ new Date()).toISOString()}] [DEBUG] ${msg}
102536
102924
  `);
102537
102925
  };
@@ -102740,7 +103128,6 @@ function prefixPlain(name) {
102740
103128
  }
102741
103129
  var isRunnerDebugEnabled = () => core.isDebug();
102742
103130
  var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true";
102743
- var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled();
102744
103131
  function ts() {
102745
103132
  return isDebugEnabled() ? `[${(/* @__PURE__ */ new Date()).toISOString()}] ` : "";
102746
103133
  }
@@ -103055,7 +103442,21 @@ var PROVIDER_ERROR_PATTERNS = [
103055
103442
  { regex: /\bFreeUsageLimitError\b/, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103056
103443
  { regex: /Insufficient balance/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103057
103444
  { regex: /credit balance is too low/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103058
- { regex: /spending cap/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103445
+ // "spending cap" (Gemini) and "spending limit" (xAI, #1076) are the same
103446
+ // condition in two house styles — a configured ceiling was reached.
103447
+ { regex: /spending (?:cap|limit)/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103448
+ // xAI exhausts credits and the monthly ceiling in one 403 whose status code
103449
+ // sits nowhere near a `status:` key, so no status pattern below fires (#1076).
103450
+ { regex: /used all available credits/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
103451
+ // the OpenRouter shapes `isRouterKeylimitExhaustedError` matches. on a Router
103452
+ // run those mean the PULLFROG wallet is empty and `renderRunError` returns a
103453
+ // `BillingError` before ever reaching this list; on a BYOK run the very same
103454
+ // wire text means the user's OWN OpenRouter wallet is empty, and this entry is
103455
+ // what gives them the right dashboard instead of ours. see #1135.
103456
+ {
103457
+ regex: /requires more credits|Key limit exceeded \(total limit\)/i,
103458
+ label: PROVIDER_BILLING_EXHAUSTED_LABEL
103459
+ },
103059
103460
  // auth patterns must come BEFORE rate-limit patterns. OpenRouter 401 error
103060
103461
  // payloads carry `x-ratelimit-*` response headers in the dump, and the
103061
103462
  // free-form rate-limit regex below would otherwise win on word-boundary
@@ -103151,6 +103552,12 @@ function resolveRunAlias(ctx) {
103151
103552
  if (!model) return void 0;
103152
103553
  return modelAliases.find((a) => !a.fallback && a.resolve === model) ?? matchHostedAnthropicAlias(model);
103153
103554
  }
103555
+ function ossEffortFloor(ctx) {
103556
+ const alias = resolveRunAlias(ctx);
103557
+ const published = alias?.openRouterEffort ?? alias?.effort;
103558
+ if (!published) return 0;
103559
+ return rungPosition({ rung: "high", published }) ?? 0;
103560
+ }
103154
103561
  function resolveRunEffort(ctx) {
103155
103562
  const configured = ctx.payload.effort !== void 0;
103156
103563
  const position = ctx.payload.effort ?? DEFAULT_EFFORT_POSITION;
@@ -103181,7 +103588,7 @@ var import_semver = __toESM(require_semver2(), 1);
103181
103588
  // package.json
103182
103589
  var package_default = {
103183
103590
  name: "pullfrog",
103184
- version: "0.1.50",
103591
+ version: "0.1.52",
103185
103592
  type: "module",
103186
103593
  bin: {
103187
103594
  pullfrog: "dist/cli.mjs",
@@ -110796,6 +111203,41 @@ function bootstrapPullfrogDataDir() {
110796
111203
  }
110797
111204
  }
110798
111205
 
111206
+ // utils/worktree.ts
111207
+ async function dirtyTrackedPaths() {
111208
+ const result = await spawn3({
111209
+ cmd: "git",
111210
+ args: ["diff", "--name-only", "HEAD"],
111211
+ env: process.env,
111212
+ activityTimeout: 0
111213
+ });
111214
+ if (result.exitCode !== 0) {
111215
+ throw new Error(
111216
+ `git diff --name-only HEAD failed (exit ${result.exitCode}): ${result.stderr.trim() || "(no stderr)"}`
111217
+ );
111218
+ }
111219
+ return new Set(result.stdout.split("\n").filter(Boolean));
111220
+ }
111221
+ async function restoreDirtiedSince(params) {
111222
+ const dirtied = [...await dirtyTrackedPaths()].filter((path4) => !params.before.has(path4));
111223
+ if (dirtied.length === 0) return;
111224
+ const result = await spawn3({
111225
+ cmd: "git",
111226
+ args: ["restore", "--staged", "--worktree", "--", ...dirtied],
111227
+ env: process.env,
111228
+ activityTimeout: 0
111229
+ });
111230
+ if (result.exitCode !== 0) {
111231
+ log.warning(
111232
+ `\xBB failed to restore ${dirtied.length} tracked file(s) modified by ${params.actor}: ${result.stderr.trim() || "(no stderr)"}`
111233
+ );
111234
+ return;
111235
+ }
111236
+ log.info(
111237
+ `\xBB restored ${dirtied.length} tracked file(s) modified by ${params.actor}: ${dirtied.join(", ")}`
111238
+ );
111239
+ }
111240
+
110799
111241
  // agents/opencodePlugin.ts
110800
111242
  var PULLFROG_BUS_EVENT_TYPE = "pullfrog_bus_event";
110801
111243
  var PULLFROG_OPENCODE_GATE_PLUGIN_FILENAME = "pullfrog-subagent-gate.ts";
@@ -111127,9 +111569,11 @@ function parseModel2(value2) {
111127
111569
  return { providerID: value2.slice(0, slash), modelID: value2.slice(slash + 1) };
111128
111570
  }
111129
111571
  function bootOpencodeServer(params) {
111572
+ const logLevel = isDebugEnabled() ? "INFO" : "ERROR";
111573
+ if (logLevel !== "ERROR") log.info(`\xBB opencode log level: ${logLevel} (debug run)`);
111130
111574
  const proc = nodeSpawn2(
111131
111575
  params.cliPath,
111132
- ["serve", "--port", "0", "--hostname", "127.0.0.1", "--print-logs", "--log-level", "ERROR"],
111576
+ ["serve", "--port", "0", "--hostname", "127.0.0.1", "--print-logs", "--log-level", logLevel],
111133
111577
  {
111134
111578
  cwd: params.cwd,
111135
111579
  env: params.env,
@@ -111679,6 +112123,7 @@ var opencode = agent({
111679
112123
  }
111680
112124
  log.debug(`\xBB starting Pullfrog (OpenCode, in-process SDK): ${cliPath}`);
111681
112125
  log.debug(`\xBB working directory: ${repoDir}`);
112126
+ const preBootDirty = await dirtyTrackedPaths();
111682
112127
  const server = await bootOpencodeServer({ cliPath, env: env2, cwd: repoDir });
111683
112128
  const dispatcher = new import_undici.Agent({ headersTimeout: 0, bodyTimeout: 0, connectTimeout: 0 });
111684
112129
  const fetchWithoutTimeout = (input, init) => {
@@ -111699,6 +112144,7 @@ var opencode = agent({
111699
112144
  fetch: fetchWithoutTimeout
111700
112145
  });
111701
112146
  const sessionResp = await client2.session.create({ title: "Pullfrog" });
112147
+ await restoreDirtiedSince({ before: preBootDirty, actor: "agent startup" });
111702
112148
  if (sessionResp.error || !sessionResp.data) {
111703
112149
  const msg = sessionResp.error ? formatPromptError(sessionResp.error) : "session.create returned no data";
111704
112150
  return {
@@ -118427,7 +118873,7 @@ var Server = class extends Protocol {
118427
118873
  };
118428
118874
 
118429
118875
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
118430
- import process3 from "node:process";
118876
+ import process4 from "node:process";
118431
118877
 
118432
118878
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
118433
118879
  var ReadBuffer = class {
@@ -118459,7 +118905,7 @@ function serializeMessage(message) {
118459
118905
 
118460
118906
  // node_modules/.pnpm/@modelcontextprotocol+sdk@1.27.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
118461
118907
  var StdioServerTransport = class {
118462
- constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
118908
+ constructor(_stdin = process4.stdin, _stdout = process4.stdout) {
118463
118909
  this._stdin = _stdin;
118464
118910
  this._stdout = _stdout;
118465
118911
  this._readBuffer = new ReadBuffer();
@@ -121894,7 +122340,7 @@ var Hono2 = class extends Hono {
121894
122340
  import { createRequire } from "node:module";
121895
122341
  import { randomUUID as randomUUID2 } from "node:crypto";
121896
122342
  import { URL as URL$1 } from "node:url";
121897
- import fs from "fs";
122343
+ import fs2 from "fs";
121898
122344
  import http from "http";
121899
122345
  import https from "https";
121900
122346
  var __create2 = Object.create;
@@ -136462,17 +136908,17 @@ var startHTTPServer = async ({ apiKey, authenticate, cors, createServer: createS
136462
136908
  if (sslCa || sslCert || sslKey) {
136463
136909
  const options = {};
136464
136910
  if (sslCa) try {
136465
- options.ca = fs.readFileSync(sslCa);
136911
+ options.ca = fs2.readFileSync(sslCa);
136466
136912
  } catch (error$1) {
136467
136913
  throw new Error(`Failed to read CA file '${sslCa}': ${error$1.message}`);
136468
136914
  }
136469
136915
  if (sslCert) try {
136470
- options.cert = fs.readFileSync(sslCert);
136916
+ options.cert = fs2.readFileSync(sslCert);
136471
136917
  } catch (error$1) {
136472
136918
  throw new Error(`Failed to read certificate file '${sslCert}': ${error$1.message}`);
136473
136919
  }
136474
136920
  if (sslKey) try {
136475
- options.key = fs.readFileSync(sslKey);
136921
+ options.key = fs2.readFileSync(sslKey);
136476
136922
  } catch (error$1) {
136477
136923
  throw new Error(`Failed to read key file '${sslKey}': ${error$1.message}`);
136478
136924
  }
@@ -144899,6 +145345,24 @@ function isSafeEnvVar(key) {
144899
145345
  if (SAFE_ENV_NAMES.has(key)) return true;
144900
145346
  return SAFE_ENV_PREFIXES.some((p2) => key.startsWith(p2));
144901
145347
  }
145348
+ var WORKFLOW_COMMAND_ENV_NAMES = [
145349
+ "GITHUB_ENV",
145350
+ "GITHUB_PATH",
145351
+ "GITHUB_OUTPUT",
145352
+ "GITHUB_STATE",
145353
+ "GITHUB_STEP_SUMMARY",
145354
+ // dropping the five paths above but keeping RUNNER_TEMP would be theatre:
145355
+ // the file-command files live in `$RUNNER_TEMP/_runner_file_commands/`, so the
145356
+ // directory is one `ls` away. nothing in the install path reads it (only our
145357
+ // own leak-surface wipe in `setup.ts`, which runs in the parent), and package
145358
+ // managers use TMPDIR.
145359
+ "RUNNER_TEMP"
145360
+ ];
145361
+ function filterEnvForUntrustedCode() {
145362
+ const env2 = filterEnv();
145363
+ for (const name of WORKFLOW_COMMAND_ENV_NAMES) delete env2[name];
145364
+ return env2;
145365
+ }
144902
145366
  function filterEnv() {
144903
145367
  const filtered = {};
144904
145368
  for (const [key, value2] of Object.entries(process.env)) {
@@ -153092,6 +153556,8 @@ import { join as join9 } from "node:path";
153092
153556
 
153093
153557
  // utils/shell.ts
153094
153558
  import { spawnSync as spawnSync5 } from "node:child_process";
153559
+ var MAX_BUFFER_BYTES = 32 * 1024 * 1024;
153560
+ var MAX_ERROR_DETAIL_CHARS = 2e4;
153095
153561
  function $2(cmd, args2, options) {
153096
153562
  const encoding = options?.encoding ?? "utf-8";
153097
153563
  const env2 = resolveEnv(options?.env);
@@ -153099,7 +153565,8 @@ function $2(cmd, args2, options) {
153099
153565
  stdio: ["ignore", "pipe", "pipe"],
153100
153566
  encoding,
153101
153567
  cwd: options?.cwd,
153102
- env: env2
153568
+ env: env2,
153569
+ maxBuffer: MAX_BUFFER_BYTES
153103
153570
  });
153104
153571
  const stdout = result.stdout ?? "";
153105
153572
  const stderr = result.stderr ?? "";
@@ -153117,6 +153584,11 @@ function $2(cmd, args2, options) {
153117
153584
  }
153118
153585
  }
153119
153586
  if (result.status !== 0) {
153587
+ if (result.error && "code" in result.error && result.error.code === "ENOBUFS") {
153588
+ throw new Error(
153589
+ `Command produced more than ${MAX_BUFFER_BYTES / 1024 / 1024}MB of output and was terminated: ${cmd} ${args2.join(" ")}`
153590
+ );
153591
+ }
153120
153592
  const errorResult = {
153121
153593
  status: result.status ?? -1,
153122
153594
  stdout,
@@ -153126,7 +153598,7 @@ function $2(cmd, args2, options) {
153126
153598
  options.onError(errorResult);
153127
153599
  return stdout.trim();
153128
153600
  }
153129
- const detail = [stderr, stdout].map((s) => s.trim()).filter(Boolean).join("\n");
153601
+ const detail = [stderr, stdout].map((s) => s.trim()).filter(Boolean).join("\n").slice(0, MAX_ERROR_DETAIL_CHARS);
153130
153602
  throw new Error(
153131
153603
  `Command failed with exit code ${errorResult.status}: ${detail || "Unknown error"}`
153132
153604
  );
@@ -153135,6 +153607,10 @@ function $2(cmd, args2, options) {
153135
153607
  }
153136
153608
 
153137
153609
  // utils/gitAuth.ts
153610
+ var TRANSIENT_AUTH_PATTERNS = [
153611
+ /Invalid username or token/,
153612
+ /Authentication failed for 'https:\/\/github\.com\//
153613
+ ];
153138
153614
  var gitBinary;
153139
153615
  function hashFile(path4) {
153140
153616
  return createHash("sha256").update(readFileSync3(path4)).digest("hex");
@@ -153251,6 +153727,17 @@ async function $gitFetchWithDeepen(args2, options, label) {
153251
153727
  return await $git("fetch", args2, options);
153252
153728
  } catch (err) {
153253
153729
  const msg = err instanceof Error ? err.message : String(err);
153730
+ if (TRANSIENT_AUTH_PATTERNS.some((p2) => p2.test(msg)) && options.refreshGitToken) {
153731
+ log.info(
153732
+ `\xBB ${label ?? "git fetch"} hit an auth error, re-minting the git token and retrying`
153733
+ );
153734
+ const fresh = await options.refreshGitToken(options.token);
153735
+ return await $gitFetchWithDeepen(
153736
+ args2,
153737
+ { ...options, token: fresh, refreshGitToken: void 0 },
153738
+ label
153739
+ );
153740
+ }
153254
153741
  const isShallowUnreachable = SHALLOW_UNREACHABLE_PATTERNS.some((p2) => p2.test(msg));
153255
153742
  if (!isShallowUnreachable) throw err;
153256
153743
  const isShallow = $2("git", ["rev-parse", "--is-shallow-repository"], { log: false }).trim() === "true";
@@ -153370,10 +153857,12 @@ function computeIncrementalDiff(params) {
153370
153857
  ],
153371
153858
  { log: false }
153372
153859
  );
153373
- return postProcessRangeDiff(raw2);
153860
+ const processed = postProcessRangeDiff(raw2);
153861
+ return processed === null ? { status: "empty" } : { status: "ok", diff: processed };
153374
153862
  } catch (e) {
153375
- log.debug(`\xBB range-diff failed: ${e instanceof Error ? e.message : String(e)}`);
153376
- return null;
153863
+ const reason = e instanceof Error ? e.message : String(e);
153864
+ log.warning(`\xBB incremental diff unavailable: range-diff failed: ${reason}`);
153865
+ return { status: "unavailable", reason };
153377
153866
  }
153378
153867
  }
153379
153868
  function isDiffPrefix(ch) {
@@ -154805,7 +155294,7 @@ throttling.VERSION = VERSION;
154805
155294
  throttling.triggersNotification = triggersNotification;
154806
155295
 
154807
155296
  // node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
154808
- function getUserAgent() {
155297
+ function getUserAgent2() {
154809
155298
  if (typeof navigator === "object" && "userAgent" in navigator) {
154810
155299
  return navigator.userAgent;
154811
155300
  }
@@ -154923,7 +155412,7 @@ var before_after_hook_default = { Singular, Collection };
154923
155412
 
154924
155413
  // node_modules/.pnpm/@octokit+endpoint@11.0.1/node_modules/@octokit/endpoint/dist-bundle/index.js
154925
155414
  var VERSION2 = "0.0.0-development";
154926
- var userAgent = `octokit-endpoint.js/${VERSION2} ${getUserAgent()}`;
155415
+ var userAgent = `octokit-endpoint.js/${VERSION2} ${getUserAgent2()}`;
154927
155416
  var DEFAULTS = {
154928
155417
  method: "GET",
154929
155418
  baseUrl: "https://api.github.com",
@@ -155280,7 +155769,7 @@ var RequestError = class extends Error {
155280
155769
  var VERSION3 = "10.0.5";
155281
155770
  var defaults_default = {
155282
155771
  headers: {
155283
- "user-agent": `octokit-request.js/${VERSION3} ${getUserAgent()}`
155772
+ "user-agent": `octokit-request.js/${VERSION3} ${getUserAgent2()}`
155284
155773
  }
155285
155774
  };
155286
155775
  function isPlainObject4(value2) {
@@ -155545,7 +156034,7 @@ function withDefaults3(request2, newDefaults) {
155545
156034
  }
155546
156035
  var graphql2 = withDefaults3(request, {
155547
156036
  headers: {
155548
- "user-agent": `octokit-graphql.js/${VERSION4} ${getUserAgent()}`
156037
+ "user-agent": `octokit-graphql.js/${VERSION4} ${getUserAgent2()}`
155549
156038
  },
155550
156039
  method: "POST",
155551
156040
  url: "/graphql"
@@ -155625,7 +156114,7 @@ function createLogger(logger = {}) {
155625
156114
  }
155626
156115
  return logger;
155627
156116
  }
155628
- var userAgentTrail = `octokit-core.js/${VERSION5} ${getUserAgent()}`;
156117
+ var userAgentTrail = `octokit-core.js/${VERSION5} ${getUserAgent2()}`;
155629
156118
  var Octokit = class {
155630
156119
  static VERSION = VERSION5;
155631
156120
  static defaults(defaults) {
@@ -158593,8 +159082,13 @@ function createOctokit(token, refreshAuth) {
158593
159082
  var readOctokitByToken = /* @__PURE__ */ new Map();
158594
159083
  function resolveRepoCtx(ctx, repo) {
158595
159084
  const owner = ctx.repo.owner;
158596
- const name = repo ?? ctx.repo.name;
158597
- const state = requireRepoState(ctx.toolState, owner, name);
159085
+ const name = repo?.trim() || ctx.repo.name;
159086
+ const state = ctx.toolState.repos.get(repoKey(owner, name));
159087
+ if (!state) {
159088
+ throw new Error(
159089
+ 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}`
159090
+ );
159091
+ }
158598
159092
  if (state.access !== "read") {
158599
159093
  return {
158600
159094
  owner,
@@ -159311,10 +159805,6 @@ var TRANSIENT_PATTERNS = [
159311
159805
  /HTTP 429/,
159312
159806
  /returned error: 429/i
159313
159807
  ];
159314
- var TRANSIENT_AUTH_PATTERNS = [
159315
- /Invalid username or token/,
159316
- /Authentication failed for 'https:\/\/github\.com\//
159317
- ];
159318
159808
  function classifyPushError(msg) {
159319
159809
  if (CONCURRENT_PUSH_PATTERNS.some((p2) => msg.includes(p2))) return "concurrent-push";
159320
159810
  if (TRANSIENT_AUTH_PATTERNS.some((p2) => p2.test(msg))) return "transient-auth";
@@ -159813,7 +160303,11 @@ function GitFetchTool(ctx) {
159813
160303
  if (params.depth !== void 0) {
159814
160304
  fetchArgs.push(`--depth=${params.depth}`);
159815
160305
  }
159816
- await $gitFetchWithDeepen(fetchArgs, { token: rc.gitToken, cwd: rc.dir }, "git_fetch");
160306
+ await $gitFetchWithDeepen(
160307
+ fetchArgs,
160308
+ { token: rc.gitToken, cwd: rc.dir, refreshGitToken: rc.refreshGitToken },
160309
+ "git_fetch"
160310
+ );
159817
160311
  return { success: true, ref: params.ref };
159818
160312
  })
159819
160313
  });
@@ -159902,7 +160396,7 @@ function formatModelLabel(params) {
159902
160396
  const ossBase = `\`${displayName}\` (free via [Pullfrog for OSS](https://pullfrog.com/for-oss))`;
159903
160397
  if (params.clamped?.reason !== "oss") return ossBase;
159904
160398
  const configured = isAutoTier(params.clamped.from) ? "the intelligent tier" : `\`${resolveDisplayAlias(params.clamped.from)?.displayName ?? params.clamped.from}\``;
159905
- return `${ossBase} (${configured} not used \u2014 the program covers this model; add its [provider key](https://docs.pullfrog.com/models) to run your pick)`;
160399
+ 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)`;
159906
160400
  }
159907
160401
  const base = alias?.isFree ? `\`${displayName}\` (free)` : `\`${displayName}\``;
159908
160402
  if (params.fallbackFrom) {
@@ -161450,7 +161944,7 @@ async function ensureBeforeShaReachable(params) {
161450
161944
  }), true);
161451
161945
  await $gitFetchWithDeepen(
161452
161946
  ["--no-tags", ...params.isShallow ? ["--depth=1"] : [], "origin", tempBranch],
161453
- { token: params.gitToken },
161947
+ { token: params.gitToken, refreshGitToken: params.refreshGitToken },
161454
161948
  `before_sha temp branch ${tempBranch}`
161455
161949
  );
161456
161950
  log.debug(`\xBB fetched before_sha via temp branch ${tempBranch}`);
@@ -161466,6 +161960,14 @@ async function ensureBeforeShaReachable(params) {
161466
161960
  return false;
161467
161961
  }
161468
161962
  }
161963
+ function hasLocalCommit(sha) {
161964
+ if (!sha) return false;
161965
+ try {
161966
+ return $2("git", ["cat-file", "-t", sha], { log: false }).trim() === "commit";
161967
+ } catch {
161968
+ return false;
161969
+ }
161970
+ }
161469
161971
  var STALE_LOCK_AGE_MS = 3e4;
161470
161972
  var PULL_REF_RETRY_DELAYS_MS = [2e3, 5e3, 1e4];
161471
161973
  var PULL_REF_MISSING_PATTERN = /couldn't find remote ref pull\/\d+\/head/i;
@@ -161516,7 +162018,7 @@ async function abortIfPullRequestMoved(args2) {
161516
162018
  );
161517
162019
  }
161518
162020
  async function checkoutPrBranch(pr, params) {
161519
- const { octokit, owner, name, gitToken, toolState, beforeSha } = params;
162021
+ const { octokit, owner, name, gitToken, refreshGitToken, toolState, beforeSha } = params;
161520
162022
  rejectIfLeadingDash(pr.baseRef, "PR base ref");
161521
162023
  rejectIfLeadingDash(pr.headRef, "PR head ref");
161522
162024
  const repoState = requireRepoState(toolState, owner, name);
@@ -161530,7 +162032,7 @@ async function checkoutPrBranch(pr, params) {
161530
162032
  log.debug(`\xBB fetching base branch (${pr.baseRef})...`);
161531
162033
  await $gitFetchWithDeepen(
161532
162034
  ["--no-tags", "origin", pr.baseRef],
161533
- { token: gitToken },
162035
+ { token: gitToken, refreshGitToken },
161534
162036
  `base branch ${pr.baseRef}`
161535
162037
  );
161536
162038
  if (!alreadyOnBranch) {
@@ -161541,7 +162043,7 @@ async function checkoutPrBranch(pr, params) {
161541
162043
  try {
161542
162044
  await $gitFetchWithDeepen(
161543
162045
  ["--no-tags", "origin", `+pull/${pr.number}/head:${localBranch}`],
161544
- { token: gitToken },
162046
+ { token: gitToken, refreshGitToken },
161545
162047
  `PR #${pr.number}`
161546
162048
  );
161547
162049
  } catch (e) {
@@ -161568,6 +162070,7 @@ async function checkoutPrBranch(pr, params) {
161568
162070
  owner,
161569
162071
  repo: name,
161570
162072
  gitToken,
162073
+ refreshGitToken,
161571
162074
  isShallow
161572
162075
  }) : false;
161573
162076
  if (isShallow) {
@@ -161681,6 +162184,7 @@ function CheckoutPrTool(ctx) {
161681
162184
  owner: ctx.repo.owner,
161682
162185
  name: ctx.repo.name,
161683
162186
  gitToken: ctx.gitToken,
162187
+ refreshGitToken: ctx.refreshGitToken,
161684
162188
  toolState: ctx.toolState,
161685
162189
  shell: ctx.payload.shell,
161686
162190
  postCheckoutScript: ctx.postCheckoutScript,
@@ -161696,6 +162200,8 @@ function CheckoutPrTool(ctx) {
161696
162200
  if (!checkoutSha) throw new Error("checkout completed without a resolved HEAD SHA");
161697
162201
  const headShort = checkoutSha.slice(0, 7);
161698
162202
  let incrementalDiffPath;
162203
+ let incrementalUnavailable = false;
162204
+ let incrementalUnavailableReason;
161699
162205
  if (primary.beforeSha) {
161700
162206
  const beforeShort = primary.beforeSha.slice(0, 7);
161701
162207
  const incremental = computeIncrementalDiff({
@@ -161703,15 +162209,18 @@ function CheckoutPrTool(ctx) {
161703
162209
  beforeSha: primary.beforeSha,
161704
162210
  headSha: checkoutSha
161705
162211
  });
161706
- if (incremental) {
162212
+ if (incremental.status === "ok") {
161707
162213
  incrementalDiffPath = join14(
161708
162214
  tempDir,
161709
162215
  `pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
161710
162216
  );
161711
- writeFileSync9(incrementalDiffPath, incremental);
162217
+ writeFileSync9(incrementalDiffPath, incremental.diff);
161712
162218
  log.info(
161713
- `\xBB incremental diff computed (${incremental.length} bytes) \u2192 ${incrementalDiffPath}`
162219
+ `\xBB incremental diff computed (${incremental.diff.length} bytes) \u2192 ${incrementalDiffPath}`
161714
162220
  );
162221
+ } else if (incremental.status === "unavailable") {
162222
+ incrementalUnavailable = true;
162223
+ incrementalUnavailableReason = incremental.reason;
161715
162224
  }
161716
162225
  }
161717
162226
  const formatResult = await fetchAndFormatPrDiff(ctx, pull_number);
@@ -161778,7 +162287,13 @@ ${diffPreview}`);
161778
162287
  primary.commentableLinesByFile = cached4;
161779
162288
  primary.commentableLinesPullNumber = pull_number;
161780
162289
  primary.commentableLinesCheckoutSha = checkoutSha;
161781
- 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. ` : "";
162290
+ 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 ? (
162291
+ // say it FAILED rather than leaving the agent to infer "nothing changed"
162292
+ // from an absent field. only suggest diff-tree when the previous
162293
+ // revision is actually PRESENT locally — if the fetch never landed it,
162294
+ // diff-tree needs that object too and would fail identically. see #1139.
162295
+ `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. `)
162296
+ ) : "";
161782
162297
  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.` : "";
161783
162298
  const COMMIT_LOG_MAX = 200;
161784
162299
  const baseRange = `origin/${pr.baseRef}..HEAD`;
@@ -162098,299 +162613,6 @@ import { performance as performance8 } from "node:perf_hooks";
162098
162613
  import { existsSync as existsSync6 } from "node:fs";
162099
162614
  import { join as join18 } from "node:path";
162100
162615
 
162101
- // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/commands.mjs
162102
- function dashDashArg(agent2, agentCommand) {
162103
- return (args2) => {
162104
- if (args2.length > 1) {
162105
- return [agent2, agentCommand, args2[0], "--", ...args2.slice(1)];
162106
- } else {
162107
- return [agent2, agentCommand, args2[0]];
162108
- }
162109
- };
162110
- }
162111
- function denoExecute() {
162112
- return (args2) => {
162113
- return ["deno", "run", `npm:${args2[0]}`, ...args2.slice(1)];
162114
- };
162115
- }
162116
- var npm = {
162117
- "agent": ["npm", 0],
162118
- "run": dashDashArg("npm", "run"),
162119
- "install": ["npm", "i", 0],
162120
- "frozen": ["npm", "ci", 0],
162121
- "global": ["npm", "i", "-g", 0],
162122
- "add": ["npm", "i", 0],
162123
- "upgrade": ["npm", "update", 0],
162124
- "upgrade-interactive": null,
162125
- "dedupe": ["npm", "dedupe", 0],
162126
- "execute": ["npx", 0],
162127
- "execute-local": ["npx", 0],
162128
- "uninstall": ["npm", "uninstall", 0],
162129
- "global_uninstall": ["npm", "uninstall", "-g", 0]
162130
- };
162131
- var yarn = {
162132
- "agent": ["yarn", 0],
162133
- "run": ["yarn", "run", 0],
162134
- "install": ["yarn", "install", 0],
162135
- "frozen": ["yarn", "install", "--frozen-lockfile", 0],
162136
- "global": ["yarn", "global", "add", 0],
162137
- "add": ["yarn", "add", 0],
162138
- "upgrade": ["yarn", "upgrade", 0],
162139
- "upgrade-interactive": ["yarn", "upgrade-interactive", 0],
162140
- "dedupe": null,
162141
- "execute": ["npx", 0],
162142
- "execute-local": dashDashArg("yarn", "exec"),
162143
- "uninstall": ["yarn", "remove", 0],
162144
- "global_uninstall": ["yarn", "global", "remove", 0]
162145
- };
162146
- var yarnBerry = {
162147
- ...yarn,
162148
- "frozen": ["yarn", "install", "--immutable", 0],
162149
- "upgrade": ["yarn", "up", 0],
162150
- "upgrade-interactive": ["yarn", "up", "-i", 0],
162151
- "dedupe": ["yarn", "dedupe", 0],
162152
- "execute": ["yarn", "dlx", 0],
162153
- "execute-local": ["yarn", "exec", 0],
162154
- // Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821
162155
- "global": ["npm", "i", "-g", 0],
162156
- "global_uninstall": ["npm", "uninstall", "-g", 0]
162157
- };
162158
- var pnpm = {
162159
- "agent": ["pnpm", 0],
162160
- "run": ["pnpm", "run", 0],
162161
- "install": ["pnpm", "i", 0],
162162
- "frozen": ["pnpm", "i", "--frozen-lockfile", 0],
162163
- "global": ["pnpm", "add", "-g", 0],
162164
- "add": ["pnpm", "add", 0],
162165
- "upgrade": ["pnpm", "update", 0],
162166
- "upgrade-interactive": ["pnpm", "update", "-i", 0],
162167
- "dedupe": ["pnpm", "dedupe", 0],
162168
- "execute": ["pnpm", "dlx", 0],
162169
- "execute-local": ["pnpm", "exec", 0],
162170
- "uninstall": ["pnpm", "remove", 0],
162171
- "global_uninstall": ["pnpm", "remove", "--global", 0]
162172
- };
162173
- var bun = {
162174
- "agent": ["bun", 0],
162175
- "run": ["bun", "run", 0],
162176
- "install": ["bun", "install", 0],
162177
- "frozen": ["bun", "install", "--frozen-lockfile", 0],
162178
- "global": ["bun", "add", "-g", 0],
162179
- "add": ["bun", "add", 0],
162180
- "upgrade": ["bun", "update", 0],
162181
- "upgrade-interactive": ["bun", "update", "-i", 0],
162182
- "dedupe": null,
162183
- "execute": ["bun", "x", 0],
162184
- "execute-local": ["bun", "x", 0],
162185
- "uninstall": ["bun", "remove", 0],
162186
- "global_uninstall": ["bun", "remove", "-g", 0]
162187
- };
162188
- var deno = {
162189
- "agent": ["deno", 0],
162190
- "run": ["deno", "task", 0],
162191
- "install": ["deno", "install", 0],
162192
- "frozen": ["deno", "install", "--frozen", 0],
162193
- "global": ["deno", "install", "-g", 0],
162194
- "add": ["deno", "add", 0],
162195
- "upgrade": ["deno", "outdated", "--update", 0],
162196
- "upgrade-interactive": ["deno", "outdated", "--update", 0],
162197
- "dedupe": null,
162198
- "execute": denoExecute(),
162199
- "execute-local": ["deno", "task", "--eval", 0],
162200
- "uninstall": ["deno", "remove", 0],
162201
- "global_uninstall": ["deno", "uninstall", "-g", 0]
162202
- };
162203
- var COMMANDS = {
162204
- "npm": npm,
162205
- "yarn": yarn,
162206
- "yarn@berry": yarnBerry,
162207
- "pnpm": pnpm,
162208
- // pnpm v6.x or below
162209
- "pnpm@6": {
162210
- ...pnpm,
162211
- run: dashDashArg("pnpm", "run")
162212
- },
162213
- "bun": bun,
162214
- "deno": deno
162215
- };
162216
- function resolveCommand(agent2, command, args2) {
162217
- const value2 = COMMANDS[agent2][command];
162218
- return constructCommand(value2, args2);
162219
- }
162220
- function constructCommand(value2, args2) {
162221
- if (value2 == null)
162222
- return null;
162223
- const list = typeof value2 === "function" ? value2(args2) : value2.flatMap((v) => {
162224
- if (typeof v === "number")
162225
- return args2;
162226
- return [v];
162227
- });
162228
- return {
162229
- command: list[0],
162230
- args: list.slice(1)
162231
- };
162232
- }
162233
-
162234
- // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/constants.mjs
162235
- var AGENTS = [
162236
- "npm",
162237
- "yarn",
162238
- "yarn@berry",
162239
- "pnpm",
162240
- "pnpm@6",
162241
- "bun",
162242
- "deno"
162243
- ];
162244
- var LOCKS = {
162245
- "bun.lock": "bun",
162246
- "bun.lockb": "bun",
162247
- "deno.lock": "deno",
162248
- "pnpm-lock.yaml": "pnpm",
162249
- "pnpm-workspace.yaml": "pnpm",
162250
- "yarn.lock": "yarn",
162251
- "package-lock.json": "npm",
162252
- "npm-shrinkwrap.json": "npm"
162253
- };
162254
- var INSTALL_METADATA = {
162255
- "node_modules/.deno/": "deno",
162256
- "node_modules/.pnpm/": "pnpm",
162257
- "node_modules/.yarn-state.yml": "yarn",
162258
- // yarn v2+ (node-modules)
162259
- "node_modules/.yarn_integrity": "yarn",
162260
- // yarn v1
162261
- "node_modules/.package-lock.json": "npm",
162262
- ".pnp.cjs": "yarn",
162263
- // yarn v3+ (pnp)
162264
- ".pnp.js": "yarn",
162265
- // yarn v2 (pnp)
162266
- "bun.lock": "bun",
162267
- "bun.lockb": "bun"
162268
- };
162269
-
162270
- // node_modules/.pnpm/package-manager-detector@1.6.0/node_modules/package-manager-detector/dist/detect.mjs
162271
- import fs2 from "node:fs/promises";
162272
- import path from "node:path";
162273
- import process4 from "node:process";
162274
- async function pathExists(path22, type2) {
162275
- try {
162276
- const stat = await fs2.stat(path22);
162277
- return type2 === "file" ? stat.isFile() : stat.isDirectory();
162278
- } catch {
162279
- return false;
162280
- }
162281
- }
162282
- function* lookup(cwd = process4.cwd()) {
162283
- let directory = path.resolve(cwd);
162284
- const { root } = path.parse(directory);
162285
- while (directory && directory !== root) {
162286
- yield directory;
162287
- directory = path.dirname(directory);
162288
- }
162289
- }
162290
- async function parsePackageJson(filepath, options) {
162291
- if (!filepath || !await pathExists(filepath, "file"))
162292
- return null;
162293
- return await handlePackageManager(filepath, options);
162294
- }
162295
- async function detect(options = {}) {
162296
- const {
162297
- cwd,
162298
- strategies = ["lockfile", "packageManager-field", "devEngines-field"]
162299
- } = options;
162300
- let stopDir;
162301
- if (typeof options.stopDir === "string") {
162302
- const resolved = path.resolve(options.stopDir);
162303
- stopDir = (dir) => dir === resolved;
162304
- } else {
162305
- stopDir = options.stopDir;
162306
- }
162307
- for (const directory of lookup(cwd)) {
162308
- for (const strategy of strategies) {
162309
- switch (strategy) {
162310
- case "lockfile": {
162311
- for (const lock of Object.keys(LOCKS)) {
162312
- if (await pathExists(path.join(directory, lock), "file")) {
162313
- const name = LOCKS[lock];
162314
- const result = await parsePackageJson(path.join(directory, "package.json"), options);
162315
- if (result)
162316
- return result;
162317
- else
162318
- return { name, agent: name };
162319
- }
162320
- }
162321
- break;
162322
- }
162323
- case "packageManager-field":
162324
- case "devEngines-field": {
162325
- const result = await parsePackageJson(path.join(directory, "package.json"), options);
162326
- if (result)
162327
- return result;
162328
- break;
162329
- }
162330
- case "install-metadata": {
162331
- for (const metadata of Object.keys(INSTALL_METADATA)) {
162332
- const fileOrDir = metadata.endsWith("/") ? "dir" : "file";
162333
- if (await pathExists(path.join(directory, metadata), fileOrDir)) {
162334
- const name = INSTALL_METADATA[metadata];
162335
- const agent2 = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name;
162336
- return { name, agent: agent2 };
162337
- }
162338
- }
162339
- break;
162340
- }
162341
- }
162342
- }
162343
- if (stopDir?.(directory))
162344
- break;
162345
- }
162346
- return null;
162347
- }
162348
- function getNameAndVer(pkg) {
162349
- const handelVer = (version3) => version3?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version3;
162350
- if (typeof pkg.packageManager === "string") {
162351
- const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@");
162352
- return { name, ver: handelVer(ver) };
162353
- }
162354
- if (typeof pkg.devEngines?.packageManager?.name === "string") {
162355
- return {
162356
- name: pkg.devEngines.packageManager.name,
162357
- ver: handelVer(pkg.devEngines.packageManager.version)
162358
- };
162359
- }
162360
- return void 0;
162361
- }
162362
- async function handlePackageManager(filepath, options) {
162363
- try {
162364
- const content = await fs2.readFile(filepath, "utf8");
162365
- const pkg = options.packageJsonParser ? await options.packageJsonParser(content, filepath) : JSON.parse(content);
162366
- let agent2;
162367
- const nameAndVer = getNameAndVer(pkg);
162368
- if (nameAndVer) {
162369
- const name = nameAndVer.name;
162370
- const ver = nameAndVer.ver;
162371
- let version3 = ver;
162372
- if (name === "yarn" && ver && Number.parseInt(ver) > 1) {
162373
- agent2 = "yarn@berry";
162374
- version3 = "berry";
162375
- return { name, agent: agent2, version: version3 };
162376
- } else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) {
162377
- agent2 = "pnpm@6";
162378
- return { name, agent: agent2, version: version3 };
162379
- } else if (AGENTS.includes(name)) {
162380
- agent2 = name;
162381
- return { name, agent: agent2, version: version3 };
162382
- } else {
162383
- return options.onUnknown?.(pkg.packageManager) ?? null;
162384
- }
162385
- }
162386
- } catch {
162387
- }
162388
- return null;
162389
- }
162390
- function isMetadataYarnClassic(metadataPath) {
162391
- return metadataPath.endsWith(".yarn_integrity");
162392
- }
162393
-
162394
162616
  // utils/packageManager.ts
162395
162617
  var import_semver2 = __toESM(require_semver2(), 1);
162396
162618
  import { existsSync as existsSync5 } from "node:fs";
@@ -162476,11 +162698,7 @@ async function runCorepack(args2) {
162476
162698
  const result = await spawn3({
162477
162699
  cmd: "corepack",
162478
162700
  args: args2,
162479
- env: {
162480
- PATH: process.env.PATH || "",
162481
- HOME: process.env.HOME || "",
162482
- COREPACK_ENABLE_DOWNLOAD_PROMPT: "0"
162483
- },
162701
+ env: { ...filterEnvForUntrustedCode(), COREPACK_ENABLE_DOWNLOAD_PROMPT: "0" },
162484
162702
  onStdout: (chunk) => process.stdout.write(chunk),
162485
162703
  onStderr: (chunk) => process.stderr.write(chunk)
162486
162704
  });
@@ -162490,7 +162708,7 @@ async function currentVersion(name) {
162490
162708
  const result = await spawn3({
162491
162709
  cmd: name,
162492
162710
  args: ["--version"],
162493
- env: { PATH: process.env.PATH || "" }
162711
+ env: filterEnvForUntrustedCode()
162494
162712
  });
162495
162713
  if (result.exitCode !== 0) return null;
162496
162714
  return result.stdout.trim();
@@ -162542,14 +162760,8 @@ async function ensurePackageManager(params) {
162542
162760
  }
162543
162761
  return true;
162544
162762
  }
162545
-
162546
- // prep/installNodeDependencies.ts
162547
162763
  async function isCommandAvailable(command) {
162548
- const result = await spawn3({
162549
- cmd: "which",
162550
- args: [command],
162551
- env: { PATH: process.env.PATH || "" }
162552
- });
162764
+ const result = await spawn3({ cmd: "which", args: [command], env: filterEnvForUntrustedCode() });
162553
162765
  return result.exitCode === 0;
162554
162766
  }
162555
162767
  async function installFallback(name, installSpec) {
@@ -162560,19 +162772,41 @@ async function installFallback(name, installSpec) {
162560
162772
  const result = await spawn3({
162561
162773
  cmd,
162562
162774
  args: args2,
162563
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
162775
+ env: filterEnvForUntrustedCode(),
162564
162776
  onStderr: (chunk) => process.stderr.write(chunk)
162565
162777
  });
162566
- if (result.exitCode !== 0) {
162567
- return result.stderr || `failed to install ${name}`;
162568
- }
162778
+ if (result.exitCode !== 0) return result.stderr || `failed to install ${name}`;
162569
162779
  if (name === "deno") {
162570
- const denoPath = join18(process.env.HOME || "", ".deno", "bin");
162780
+ const denoPath = join17(process.env.HOME || "", ".deno", "bin");
162571
162781
  process.env.PATH = `${denoPath}:${process.env.PATH}`;
162572
162782
  }
162573
162783
  log.info(`\xBB installed ${name}`);
162574
162784
  return null;
162575
162785
  }
162786
+ async function provisionPackageManager(params) {
162787
+ if (await isCommandAvailable(params.name)) {
162788
+ if (params.declared) {
162789
+ await ensurePackageManager({ spec: params.declared, binDir: params.binDir });
162790
+ }
162791
+ return null;
162792
+ }
162793
+ if (params.declared) {
162794
+ const activated = await ensurePackageManager({ spec: params.declared, binDir: params.binDir });
162795
+ if (activated) return null;
162796
+ }
162797
+ const spec = params.declared ? `${params.declared.name}@${params.declared.version}` : params.name;
162798
+ return installFallback(params.name, spec);
162799
+ }
162800
+
162801
+ // prep/installNodeDependencies.ts
162802
+ async function isCommandAvailable2(command) {
162803
+ const result = await spawn3({
162804
+ cmd: "which",
162805
+ args: [command],
162806
+ env: filterEnvForUntrustedCode()
162807
+ });
162808
+ return result.exitCode === 0;
162809
+ }
162576
162810
  var installNodeDependencies = {
162577
162811
  name: "installNodeDependencies",
162578
162812
  shouldRun: () => {
@@ -162593,8 +162827,8 @@ var installNodeDependencies = {
162593
162827
  } else {
162594
162828
  log.info(`\xBB no package manager declared, defaulting to npm`);
162595
162829
  }
162596
- if (!await isCommandAvailable(packageManager)) {
162597
- if (options.ignoreScripts) {
162830
+ if (options.ignoreScripts) {
162831
+ if (!await isCommandAvailable2(packageManager)) {
162598
162832
  return {
162599
162833
  language: "node",
162600
162834
  packageManager,
@@ -162604,23 +162838,20 @@ var installNodeDependencies = {
162604
162838
  ]
162605
162839
  };
162606
162840
  }
162607
- let provisioned = false;
162608
- if (declared)
162609
- provisioned = await ensurePackageManager({ spec: declared, binDir: options.binDir });
162610
- if (!provisioned) {
162611
- const fallbackSpec = declared ? `${declared.name}@${declared.version}` : packageManager;
162612
- const installError = await installFallback(packageManager, fallbackSpec);
162613
- if (installError) {
162614
- return {
162615
- language: "node",
162616
- packageManager,
162617
- dependenciesInstalled: false,
162618
- issues: [installError]
162619
- };
162620
- }
162841
+ } else {
162842
+ const installError = await provisionPackageManager({
162843
+ name: packageManager,
162844
+ declared,
162845
+ binDir: options.binDir
162846
+ });
162847
+ if (installError) {
162848
+ return {
162849
+ language: "node",
162850
+ packageManager,
162851
+ dependenciesInstalled: false,
162852
+ issues: [installError]
162853
+ };
162621
162854
  }
162622
- } else if (declared) {
162623
- await ensurePackageManager({ spec: declared, binDir: options.binDir });
162624
162855
  }
162625
162856
  if (!detected) {
162626
162857
  log.info(
@@ -162646,7 +162877,7 @@ var installNodeDependencies = {
162646
162877
  const result = await spawn3({
162647
162878
  cmd: resolved.command,
162648
162879
  args: resolved.args,
162649
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }
162880
+ env: filterEnvForUntrustedCode()
162650
162881
  });
162651
162882
  const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
162652
162883
  if (output) {
@@ -162720,11 +162951,11 @@ var TOOL_INSTALL_COMMANDS = {
162720
162951
  pipenv: ["pip", "install", "pipenv"],
162721
162952
  poetry: ["pip", "install", "poetry"]
162722
162953
  };
162723
- async function isCommandAvailable2(command) {
162954
+ async function isCommandAvailable3(command) {
162724
162955
  const result = await spawn3({
162725
162956
  cmd: "which",
162726
162957
  args: [command],
162727
- env: { PATH: process.env.PATH || "" }
162958
+ env: filterEnvForUntrustedCode()
162728
162959
  });
162729
162960
  return result.exitCode === 0;
162730
162961
  }
@@ -162738,7 +162969,7 @@ async function installTool(name) {
162738
162969
  const result = await spawn3({
162739
162970
  cmd,
162740
162971
  args: args2,
162741
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
162972
+ env: filterEnvForUntrustedCode(),
162742
162973
  onStderr: (chunk) => process.stderr.write(chunk)
162743
162974
  });
162744
162975
  if (result.exitCode !== 0) {
@@ -162750,7 +162981,7 @@ async function installTool(name) {
162750
162981
  var installPythonDependencies = {
162751
162982
  name: "installPythonDependencies",
162752
162983
  shouldRun: async () => {
162753
- const hasPython = await isCommandAvailable2("python3") || await isCommandAvailable2("python");
162984
+ const hasPython = await isCommandAvailable3("python3") || await isCommandAvailable3("python");
162754
162985
  if (!hasPython) {
162755
162986
  return false;
162756
162987
  }
@@ -162784,7 +163015,7 @@ var installPythonDependencies = {
162784
163015
  ]
162785
163016
  };
162786
163017
  }
162787
- const isAvailable = await isCommandAvailable2(config3.tool);
163018
+ const isAvailable = await isCommandAvailable3(config3.tool);
162788
163019
  if (!isAvailable) {
162789
163020
  log.info(`\xBB ${config3.tool} not found, attempting to install...`);
162790
163021
  const installError = await installTool(config3.tool);
@@ -162804,7 +163035,7 @@ var installPythonDependencies = {
162804
163035
  const result = await spawn3({
162805
163036
  cmd,
162806
163037
  args: args2,
162807
- env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }
163038
+ env: filterEnvForUntrustedCode()
162808
163039
  });
162809
163040
  const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
162810
163041
  if (output) {
@@ -162833,37 +163064,6 @@ var installPythonDependencies = {
162833
163064
 
162834
163065
  // prep/index.ts
162835
163066
  var prepSteps = [installNodeDependencies, installPythonDependencies];
162836
- async function dirtyTrackedPaths() {
162837
- const result = await spawn3({
162838
- cmd: "git",
162839
- args: ["diff", "--name-only", "HEAD"],
162840
- env: process.env,
162841
- activityTimeout: 0
162842
- });
162843
- if (result.exitCode !== 0) {
162844
- throw new Error(
162845
- `git diff --name-only HEAD failed (exit ${result.exitCode}): ${result.stderr.trim() || "(no stderr)"}`
162846
- );
162847
- }
162848
- return new Set(result.stdout.split("\n").filter(Boolean));
162849
- }
162850
- async function restorePrepDirtiedFiles(preDirty) {
162851
- const dirtied = [...await dirtyTrackedPaths()].filter((path4) => !preDirty.has(path4));
162852
- if (dirtied.length === 0) return;
162853
- const result = await spawn3({
162854
- cmd: "git",
162855
- args: ["restore", "--staged", "--worktree", "--", ...dirtied],
162856
- env: process.env,
162857
- activityTimeout: 0
162858
- });
162859
- if (result.exitCode !== 0) {
162860
- log.warning(
162861
- `\xBB failed to restore ${dirtied.length} tracked file(s) modified by prep: ${result.stderr.trim() || "(no stderr)"}`
162862
- );
162863
- return;
162864
- }
162865
- log.info(`\xBB restored ${dirtied.length} tracked file(s) modified by prep: ${dirtied.join(", ")}`);
162866
- }
162867
163067
  async function runPrepPhase(options) {
162868
163068
  log.debug("\xBB starting prep phase...");
162869
163069
  const startTime = performance8.now();
@@ -162886,7 +163086,7 @@ async function runPrepPhase(options) {
162886
163086
  }
162887
163087
  }
162888
163088
  } finally {
162889
- await restorePrepDirtiedFiles(preDirty);
163089
+ await restoreDirtiedSince({ before: preDirty, actor: "prep" });
162890
163090
  }
162891
163091
  const totalDurationMs = performance8.now() - startTime;
162892
163092
  log.debug(`\xBB prep phase completed (${Math.round(totalDurationMs)}ms)`);
@@ -164102,13 +164302,38 @@ function buildThreadBlocks(threads, filePatchMap, reviewId) {
164102
164302
  }
164103
164303
  return threadBlocks;
164104
164304
  }
164305
+ var fetchAllReviewThreads = op(
164306
+ async (key, ctx) => {
164307
+ const response = await ctx.octokit.graphql(REVIEW_THREADS_QUERY, {
164308
+ owner: key.owner,
164309
+ name: key.name,
164310
+ prNumber: key.pullNumber
164311
+ });
164312
+ return response.repository?.pullRequest?.reviewThreads?.nodes ?? [];
164313
+ },
164314
+ { ttl: 6e4, name: "reviewThreads" }
164315
+ );
164316
+ var fetchPrFiles = op(
164317
+ async (key, ctx) => ctx.octokit.paginate(ctx.octokit.rest.pulls.listFiles, {
164318
+ owner: key.owner,
164319
+ repo: key.name,
164320
+ pull_number: key.pullNumber,
164321
+ per_page: 100
164322
+ }),
164323
+ { ttl: 6e4, name: "prFiles" }
164324
+ );
164325
+ function invalidateReviewThreadCache(repo) {
164326
+ fetchAllReviewThreads.invalidate(
164327
+ (cached4) => cached4.owner === repo.owner && cached4.name === repo.name
164328
+ );
164329
+ }
164105
164330
  async function getReviewThreads(input) {
164106
- const response = await input.octokit.graphql(REVIEW_THREADS_QUERY, {
164107
- owner: input.owner,
164108
- name: input.name,
164109
- prNumber: input.pullNumber
164110
- });
164111
- const allThreads = response.repository?.pullRequest?.reviewThreads?.nodes ?? [];
164331
+ const allThreads = structuredClone(
164332
+ await fetchAllReviewThreads(
164333
+ { owner: input.owner, name: input.name, pullNumber: input.pullNumber },
164334
+ { octokit: input.octokit }
164335
+ )
164336
+ );
164112
164337
  if (allThreads.length >= 100) {
164113
164338
  log.warning(
164114
164339
  `PR ${input.owner}/${input.name}#${input.pullNumber}: reviewThreads returned 100 results (limit reached, some threads may be missing)`
@@ -164165,12 +164390,10 @@ async function getReviewData(input) {
164165
164390
  }),
164166
164391
  getReviewThreads(input)
164167
164392
  ]);
164168
- const prFiles = threads.length > 0 ? await input.octokit.paginate(input.octokit.rest.pulls.listFiles, {
164169
- owner: input.owner,
164170
- repo: input.name,
164171
- pull_number: input.pullNumber,
164172
- per_page: 100
164173
- }) : [];
164393
+ const prFiles = threads.length > 0 ? await fetchPrFiles(
164394
+ { owner: input.owner, name: input.name, pullNumber: input.pullNumber },
164395
+ { octokit: input.octokit }
164396
+ ) : [];
164174
164397
  if (review.data.body) {
164175
164398
  review.data.body = await resolveBodyAssets({
164176
164399
  body: review.data.body,
@@ -164314,6 +164537,7 @@ function ResolveReviewThreadTool(ctx) {
164314
164537
  });
164315
164538
  const thread = response.resolveReviewThread.thread;
164316
164539
  log.info(`\xBB resolved review thread ${thread.id}`);
164540
+ invalidateReviewThreadCache({ owner: ctx.repo.owner, name: ctx.repo.name });
164317
164541
  return {
164318
164542
  thread_id: thread.id,
164319
164543
  is_resolved: thread.isResolved,
@@ -164488,7 +164712,10 @@ import { join as join21 } from "node:path";
164488
164712
  import { setTimeout as sleep2 } from "node:timers/promises";
164489
164713
  var ShellParams = type({
164490
164714
  command: "string",
164491
- description: "string",
164715
+ // advisory and unread — no code path consumes it. kept in the schema only
164716
+ // because it nudges the model to state intent before running a command;
164717
+ // REQUIRING it cost a full rejected turn every time one was omitted. #1140.
164718
+ "description?": "string",
164492
164719
  "timeout?": type.number.describe(
164493
164720
  "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."
164494
164721
  ),
@@ -164758,6 +164985,8 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
164758
164985
  proc.on("exit", done);
164759
164986
  proc.on("error", () => done(null));
164760
164987
  });
164988
+ proc.stdout?.destroy();
164989
+ proc.stderr?.destroy();
164761
164990
  let output = stderr ? stdout ? `${stdout}
164762
164991
  ${stderr}` : stderr : stdout;
164763
164992
  if (timedOut)
@@ -165001,6 +165230,7 @@ function CheckoutRepoTool(ctx) {
165001
165230
  owner,
165002
165231
  name: repo,
165003
165232
  gitToken: rc.gitToken,
165233
+ refreshGitToken: rc.refreshGitToken,
165004
165234
  octokit: rc.octokit,
165005
165235
  toolState: ctx.toolState,
165006
165236
  shell: ctx.payload.shell,
@@ -165497,14 +165727,22 @@ function validateAgentApiKey(params) {
165497
165727
  }
165498
165728
  function isApiKeyAuthError(text) {
165499
165729
  if (!text) return false;
165500
- 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);
165730
+ 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);
165501
165731
  }
165502
165732
  function isOAuthCredentialExpiredError(text) {
165503
- return /authentication token has (expired|been invalidated)/i.test(text) || /OAuth access token has expired/i.test(text) || /Token refresh failed/i.test(text);
165733
+ return /(?:authentication|OAuth access) token has (?:expired|been (?:invalidated|revoked))/i.test(
165734
+ text
165735
+ ) || // the provider no longer recognises the token at all (#1086) — same dead
165736
+ // credential, phrased as a lookup miss rather than a state transition.
165737
+ /Could not find the appropriate key in your authentication token/i.test(text) || /Token refresh failed/i.test(text);
165504
165738
  }
165505
165739
  function isClaudeSubscriptionDisabledError(text) {
165506
165740
  return /disabled Claude subscription access/i.test(text);
165507
165741
  }
165742
+ var CLAUDE_SESSION_LIMIT_PATTERN = /hit your (?:session|weekly|five-hour|Opus|Sonnet|Haiku)\s+limit(?:\s*·\s*resets\s+([^"\n]+))?/i;
165743
+ function isClaudeSessionLimitError(text) {
165744
+ return CLAUDE_SESSION_LIMIT_PATTERN.test(text);
165745
+ }
165508
165746
  function formatApiKeyErrorSummary(params) {
165509
165747
  if (params.raw.includes(MISSING_KEY_MARKER)) {
165510
165748
  if (params.raw.startsWith(`**${MISSING_KEY_MARKER}**`)) return params.raw;
@@ -165512,6 +165750,15 @@ function formatApiKeyErrorSummary(params) {
165512
165750
  }
165513
165751
  const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
165514
165752
  const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
165753
+ if (isClaudeSessionLimitError(params.raw)) {
165754
+ const reset = CLAUDE_SESSION_LIMIT_PATTERN.exec(params.raw)?.[1]?.trim();
165755
+ const resets = reset ? ` It resets at **${reset}**.` : "";
165756
+ return [
165757
+ `**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.`,
165758
+ "",
165759
+ `[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)`
165760
+ ].join("\n");
165761
+ }
165515
165762
  if (isClaudeSubscriptionDisabledError(params.raw)) {
165516
165763
  return [
165517
165764
  `**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.`,
@@ -166321,7 +166568,9 @@ function decideModelAccess(input) {
166321
166568
  if (input.proxyActive) {
166322
166569
  const target = resolveOpenRouterModel(input.model);
166323
166570
  if (input.oss) {
166324
- if (target && target === input.subsidyTarget) return { kind: "proxy", target };
166571
+ if (target && (target === input.subsidyTarget || isOssAllowedModel(input.model))) {
166572
+ return { kind: "proxy", target };
166573
+ }
166325
166574
  if (byokAuthorized) return { kind: "byok" };
166326
166575
  return { kind: "error", reason: "oss" };
166327
166576
  }
@@ -166333,6 +166582,11 @@ function decideModelAccess(input) {
166333
166582
  return { kind: "error", reason: "byok_no_key" };
166334
166583
  }
166335
166584
  var MODEL_ACCESS_MARKER = "requested model is not available";
166585
+ function ossAllowedLabels() {
166586
+ return OSS_MODEL_ALLOWLIST.map(
166587
+ (slug2) => `\`${resolveDisplayAlias(slug2)?.displayName ?? slug2}\``
166588
+ ).join(", ");
166589
+ }
166336
166590
  function buildModelAccessError(input) {
166337
166591
  const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
166338
166592
  const secretsUrl = `https://github.com/${input.owner}/${input.name}/settings/secrets/actions`;
@@ -166340,8 +166594,8 @@ function buildModelAccessError(input) {
166340
166594
  const headline = `**The ${MODEL_ACCESS_MARKER}: \`${input.model}\`.**`;
166341
166595
  const branch = {
166342
166596
  oss: {
166343
- 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.",
166344
- cta: `[Add a provider key \u2192](${secretsUrl}) \xB7 [Setup docs \u2192](${docsUrl})`
166597
+ 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.`,
166598
+ cta: `[Configure model \u2192](${settingsUrl}) \xB7 [Add a provider key \u2192](${secretsUrl}) \xB7 [Setup docs \u2192](${docsUrl})`
166345
166599
  },
166346
166600
  byok_no_key: {
166347
166601
  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.`,
@@ -166588,6 +166842,14 @@ function resolvePromptFile(input) {
166588
166842
  }
166589
166843
  return content;
166590
166844
  }
166845
+ function warnIfDeprecatedStatusChecks(value2) {
166846
+ if (value2 !== void 0) {
166847
+ core6.warning(
166848
+ "`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."
166849
+ );
166850
+ }
166851
+ return value2;
166852
+ }
166591
166853
  function resolveNonPromptInputs() {
166592
166854
  return Inputs.omit("prompt", "prompt_file").assert({
166593
166855
  model: core6.getInput("model") || void 0,
@@ -166596,7 +166858,7 @@ function resolveNonPromptInputs() {
166596
166858
  cwd: core6.getInput("cwd") || void 0,
166597
166859
  push: core6.getInput("push") || void 0,
166598
166860
  shell: core6.getInput("shell") || void 0,
166599
- status_checks: core6.getInput("status_checks") || void 0,
166861
+ status_checks: warnIfDeprecatedStatusChecks(core6.getInput("status_checks") || void 0),
166600
166862
  progress_comments: core6.getInput("progress_comments") || void 0
166601
166863
  });
166602
166864
  }
@@ -166649,9 +166911,11 @@ function resolvePayload(resolvedPromptInput, repoSettings) {
166649
166911
  // input is the source of truth when set (mirrors `push`); otherwise the repo
166650
166912
  // setting decides.
166651
166913
  runStatusCheck: inputs.status_checks === void 0 ? repoSettings.statusChecks : inputs.status_checks === "enabled",
166652
- // the `pullfrog-approval` verdict check stays opt-in and workflow-only. it exists to
166653
- // be *required* by branch protection, so it must never turn itself on.
166654
- approvalCheck: inputs.status_checks === "enabled",
166914
+ // the `pullfrog-approval` verdict check. `Repo.approvalCheck` is authoritative; the
166915
+ // `status_checks` input is DEPRECATED but still honoured, for the dormant installs the
166916
+ // backfill could not read (see `warnIfDeprecatedStatusChecks`). OR rather than override:
166917
+ // this can only ever turn the check ON, never off, so no existing user loses it.
166918
+ approvalCheck: repoSettings.approvalCheck || inputs.status_checks === "enabled",
166655
166919
  // temporary progress chrome. the workflow input is the source of truth when
166656
166920
  // set (mirrors `push`); otherwise the repo setting decides. defaults to true.
166657
166921
  progressComments: inputs.progress_comments === void 0 ? repoSettings.progressComments : inputs.progress_comments === "enabled",
@@ -167023,7 +167287,7 @@ async function resolveProxyModel(ctx) {
167023
167287
  if (ctx.oss) {
167024
167288
  ctx.toolState.modelClamped = { from: ctx.payload.model, reason: "oss" };
167025
167289
  log.info(
167026
- `\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.`
167290
+ `\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.`
167027
167291
  );
167028
167292
  } else if (isCardGatedModel(ctx.payload.model)) {
167029
167293
  ctx.toolState.modelClamped = { from: ctx.payload.model, reason: "card" };
@@ -167225,6 +167489,7 @@ var defaultSettings = {
167225
167489
  repoIntelligence: false,
167226
167490
  progressComments: true,
167227
167491
  statusChecks: true,
167492
+ approvalCheck: false,
167228
167493
  modeInstructions: {},
167229
167494
  learnings: null,
167230
167495
  learningsHeadings: [],
@@ -167452,6 +167717,40 @@ function formatBillingExhaustedBody(diagnostic) {
167452
167717
  function isProviderModelNotFoundError(message) {
167453
167718
  return message.includes("ProviderModelNotFoundError");
167454
167719
  }
167720
+ function isContextOverflowError(message) {
167721
+ 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);
167722
+ }
167723
+ function isNoProviderAvailableError(message) {
167724
+ return /\bNo provider available\b/i.test(message);
167725
+ }
167726
+ function formatNoProviderAvailableSummary(input) {
167727
+ const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
167728
+ return [
167729
+ "**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.",
167730
+ "",
167731
+ "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.",
167732
+ "",
167733
+ `[Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
167734
+ "",
167735
+ `\`\`\`
167736
+ ${input.raw}
167737
+ \`\`\``
167738
+ ].join("\n");
167739
+ }
167740
+ function formatContextOverflowSummary(input) {
167741
+ const settingsUrl = `${getApiUrl()}/console/${input.owner}/${input.name}`;
167742
+ return [
167743
+ "**This run exceeded the model's context window.** Pullfrog read more than the model could hold, so it stopped before finishing.",
167744
+ "",
167745
+ `Pick a model with a larger context window, or split this PR into smaller ones and re-trigger.`,
167746
+ "",
167747
+ `[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
167748
+ "",
167749
+ `\`\`\`
167750
+ ${input.raw}
167751
+ \`\`\``
167752
+ ].join("\n");
167753
+ }
167455
167754
  function formatGenericFailure(errorMessage) {
167456
167755
  return [
167457
167756
  "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.",
@@ -167473,12 +167772,18 @@ var PROVIDER_BILLING_URLS = {
167473
167772
  anthropic: "https://console.anthropic.com/settings/billing",
167474
167773
  openai: "https://platform.openai.com/account/billing",
167475
167774
  google: "https://aistudio.google.com/usage",
167476
- opencode: "https://opencode.ai/zen"
167775
+ opencode: "https://opencode.ai/zen",
167776
+ xai: "https://console.x.ai/team/default/billing",
167777
+ openrouter: "https://openrouter.ai/settings/credits"
167477
167778
  };
167478
167779
  function detectProviderId(message) {
167479
167780
  const harnessId = extractProviderId(message);
167480
167781
  if (harnessId) return harnessId;
167481
167782
  if (/credit balance is too low/i.test(message)) return "anthropic";
167783
+ if (/used all available credits/i.test(message)) return "xai";
167784
+ if (/requires more credits|Key limit exceeded \(total limit\)|openrouter\.ai/i.test(message)) {
167785
+ return "openrouter";
167786
+ }
167482
167787
  return null;
167483
167788
  }
167484
167789
  function formatProviderBillingExhausted(input) {
@@ -167506,7 +167811,7 @@ ${input.raw}
167506
167811
  \`\`\``;
167507
167812
  }
167508
167813
  function renderRunError(input) {
167509
- const billingError = isRouterKeylimitExhaustedError(input.errorMessage) ? new BillingError(input.errorMessage, { code: "router_keylimit_exhausted" }) : null;
167814
+ const billingError = input.routerActive && isRouterKeylimitExhaustedError(input.errorMessage) ? new BillingError(input.errorMessage, { code: "router_keylimit_exhausted" }) : null;
167510
167815
  if (billingError) {
167511
167816
  const body = formatBillingErrorSummary(billingError, input.repo.owner);
167512
167817
  return { summary: body, comment: body };
@@ -167546,6 +167851,26 @@ ${body}`, comment: body };
167546
167851
  });
167547
167852
  return { summary: body, comment: body };
167548
167853
  }
167854
+ if (isNoProviderAvailableError(input.errorMessage)) {
167855
+ const body = formatNoProviderAvailableSummary({
167856
+ owner: input.repo.owner,
167857
+ name: input.repo.name,
167858
+ raw: input.errorMessage
167859
+ });
167860
+ return { summary: `### \u274C Pullfrog failed
167861
+
167862
+ ${body}`, comment: body };
167863
+ }
167864
+ if (isContextOverflowError(input.errorMessage)) {
167865
+ const body = formatContextOverflowSummary({
167866
+ owner: input.repo.owner,
167867
+ name: input.repo.name,
167868
+ raw: input.errorMessage
167869
+ });
167870
+ return { summary: `### \u274C Pullfrog failed
167871
+
167872
+ ${body}`, comment: body };
167873
+ }
167549
167874
  if (hangBody) {
167550
167875
  const isBillingExhausted = input.agentDiagnostic?.lastProviderError === "provider billing exhausted";
167551
167876
  return {
@@ -167926,7 +168251,8 @@ async function finalizeSuccessRun(input) {
167926
168251
  const rendered = !input.result.success ? renderRunError({
167927
168252
  errorMessage: input.result.error || "agent run failed",
167928
168253
  repo: input.repo,
167929
- agentDiagnostic: input.toolState.agentDiagnostic
168254
+ agentDiagnostic: input.toolState.agentDiagnostic,
168255
+ routerActive: !!input.toolContext.payload.proxyModel
167930
168256
  }) : null;
167931
168257
  if (rendered) {
167932
168258
  await reportErrorToComment({
@@ -168374,7 +168700,9 @@ async function main() {
168374
168700
  }
168375
168701
  if (access.kind === "proxy") payload.proxyModel = access.target;
168376
168702
  if (access.kind === "byok") payload.proxyModel = void 0;
168377
- if (runContext.oss && payload.proxyModel) payload.effort = 0;
168703
+ if (runContext.oss && payload.proxyModel) {
168704
+ payload.effort = ossEffortFloor({ payload });
168705
+ }
168378
168706
  const resolvedModel = payload.proxyModel ? void 0 : resolveModel({ slug: payload.model });
168379
168707
  vertexCredentials = materializeVertexCredentials({ model: resolvedModel });
168380
168708
  const agent2 = resolveAgent({ model: resolvedModel });
@@ -168401,8 +168729,15 @@ async function main() {
168401
168729
  });
168402
168730
  timer.checkpoint("git");
168403
168731
  const pmSpec = await resolvePackageManagerSpec(process.cwd());
168404
- if (pmSpec) {
168405
- await ensurePackageManager({ spec: pmSpec, binDir: packageManagerBinDir(tmpdir4) });
168732
+ const pmDetected = await detect({ cwd: process.cwd(), strategies: ["lockfile"] });
168733
+ const pmName = pmSpec?.name ?? pmDetected?.name ?? "npm";
168734
+ if (payload.shell !== "disabled") {
168735
+ const pmError = await provisionPackageManager({
168736
+ name: pmName,
168737
+ declared: pmSpec,
168738
+ binDir: packageManagerBinDir(tmpdir4)
168739
+ });
168740
+ if (pmError) log.warning(`\xBB could not provision ${pmName}: ${pmError}`);
168406
168741
  }
168407
168742
  timer.checkpoint("packageManager");
168408
168743
  const setupHook = await executeLifecycleHook({
@@ -168682,7 +169017,8 @@ ${instructions.user}` : null,
168682
169017
  const rendered = renderRunError({
168683
169018
  errorMessage,
168684
169019
  repo: runContext.repo,
168685
- agentDiagnostic: toolState.agentDiagnostic
169020
+ agentDiagnostic: toolState.agentDiagnostic,
169021
+ routerActive: !!payload.proxyModel
168686
169022
  });
168687
169023
  await writeRunErrorOutputs({ rendered, toolState });
168688
169024
  if (toolContext) {
@@ -169717,7 +170053,7 @@ async function runCli4(input) {
169717
170053
  }
169718
170054
 
169719
170055
  // cli.ts
169720
- var VERSION10 = "0.1.50";
170056
+ var VERSION10 = "0.1.52";
169721
170057
  var bin = basename2(process.argv[1] || "");
169722
170058
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
169723
170059
  var rawArgs = process.argv.slice(2);
@@ -169820,6 +170156,7 @@ async function run3() {
169820
170156
  }
169821
170157
  try {
169822
170158
  await run3();
170159
+ process.exit(process.exitCode ?? 0);
169823
170160
  } catch (error49) {
169824
170161
  const message = error49 instanceof Error ? error49.message : String(error49);
169825
170162
  console.error(import_picocolors5.default.red(message));