diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..517f386 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v22.14.0 diff --git a/entry b/entry index c95b967..658ea19 100755 --- a/entry +++ b/entry @@ -9222,7 +9222,7 @@ var require_readable = __commonJS({ var kBody = Symbol("kBody"); var kAbort = Symbol("abort"); var kContentType = Symbol("kContentType"); - var noop3 = () => { + var noop4 = () => { }; module.exports = class BodyReadable extends Readable { constructor({ @@ -9344,7 +9344,7 @@ var require_readable = __commonJS({ return new Promise((resolve, reject) => { const signalListenerCleanup = signal ? util3.addAbortListener(signal, () => { this.destroy(); - }) : noop3; + }) : noop4; this.on("close", function() { signalListenerCleanup(); if (signal && signal.aborted) { @@ -9352,7 +9352,7 @@ var require_readable = __commonJS({ } else { resolve(null); } - }).on("error", noop3).on("data", function(chunk) { + }).on("error", noop4).on("data", function(chunk) { limit -= chunk.length; if (limit <= 0) { this.destroy(); @@ -12402,15 +12402,15 @@ var require_request2 = __commonJS({ signal = input[kSignal]; } const origin = this[kRealm].settingsObject.origin; - let window = "client"; + let window2 = "client"; if (request2.window?.constructor?.name === "EnvironmentSettingsObject" && sameOrigin(request2.window, origin)) { - window = request2.window; + window2 = request2.window; } if (init.window != null) { - throw new TypeError(`'window' option '${window}' must be null`); + throw new TypeError(`'window' option '${window2}' must be null`); } if ("window" in init) { - window = "no-window"; + window2 = "no-window"; } request2 = makeRequest({ // URL request’s URL. @@ -12425,7 +12425,7 @@ var require_request2 = __commonJS({ // client This’s relevant settings object. client: this[kRealm].settingsObject, // window window. - window, + window: window2, // priority request’s priority. priority: request2.priority, // origin request’s origin. The propagation of the origin is only significant for navigation requests @@ -19928,8 +19928,8 @@ var require_string_width = __commonJS({ var require_astral_regex = __commonJS({ "node_modules/.pnpm/astral-regex@2.0.0/node_modules/astral-regex/index.js"(exports, module) { "use strict"; - var regex3 = "[\uD800-\uDBFF][\uDC00-\uDFFF]"; - var astralRegex = (options) => options && options.exact ? new RegExp(`^${regex3}$`) : new RegExp(regex3, "g"); + var regex4 = "[\uD800-\uDBFF][\uDC00-\uDFFF]"; + var astralRegex = (options) => options && options.exact ? new RegExp(`^${regex4}$`) : new RegExp(regex4, "g"); module.exports = astralRegex; } }); @@ -25505,6 +25505,1325 @@ var require_src = __commonJS({ } }); +// node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/light.js +var require_light = __commonJS({ + "node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/light.js"(exports, module) { + (function(global2, factory) { + typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : global2.Bottleneck = factory(); + })(exports, (function() { + "use strict"; + var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {}; + function getCjsExportFromNamespace(n) { + return n && n["default"] || n; + } + var load = function(received, defaults, onto = {}) { + var k, ref, v; + for (k in defaults) { + v = defaults[k]; + onto[k] = (ref = received[k]) != null ? ref : v; + } + return onto; + }; + var overwrite = function(received, defaults, onto = {}) { + var k, v; + for (k in received) { + v = received[k]; + if (defaults[k] !== void 0) { + onto[k] = v; + } + } + return onto; + }; + var parser = { + load, + overwrite + }; + var DLList; + DLList = class DLList { + constructor(incr, decr) { + this.incr = incr; + this.decr = decr; + this._first = null; + this._last = null; + this.length = 0; + } + push(value2) { + var node2; + this.length++; + if (typeof this.incr === "function") { + this.incr(); + } + node2 = { + value: value2, + prev: this._last, + next: null + }; + if (this._last != null) { + this._last.next = node2; + this._last = node2; + } else { + this._first = this._last = node2; + } + return void 0; + } + shift() { + var value2; + if (this._first == null) { + return; + } else { + this.length--; + if (typeof this.decr === "function") { + this.decr(); + } + } + value2 = this._first.value; + if ((this._first = this._first.next) != null) { + this._first.prev = null; + } else { + this._last = null; + } + return value2; + } + first() { + if (this._first != null) { + return this._first.value; + } + } + getArray() { + var node2, ref, results; + node2 = this._first; + results = []; + while (node2 != null) { + results.push((ref = node2, node2 = node2.next, ref.value)); + } + return results; + } + forEachShift(cb) { + var node2; + node2 = this.shift(); + while (node2 != null) { + cb(node2), node2 = this.shift(); + } + return void 0; + } + debug() { + var node2, ref, ref1, ref2, results; + node2 = this._first; + results = []; + while (node2 != null) { + results.push((ref = node2, node2 = node2.next, { + value: ref.value, + prev: (ref1 = ref.prev) != null ? ref1.value : void 0, + next: (ref2 = ref.next) != null ? ref2.value : void 0 + })); + } + return results; + } + }; + var DLList_1 = DLList; + var Events; + Events = class Events { + constructor(instance) { + this.instance = instance; + this._events = {}; + if (this.instance.on != null || this.instance.once != null || this.instance.removeAllListeners != null) { + throw new Error("An Emitter already exists for this object"); + } + this.instance.on = (name, cb) => { + return this._addListener(name, "many", cb); + }; + this.instance.once = (name, cb) => { + return this._addListener(name, "once", cb); + }; + this.instance.removeAllListeners = (name = null) => { + if (name != null) { + return delete this._events[name]; + } else { + return this._events = {}; + } + }; + } + _addListener(name, status, cb) { + var base; + if ((base = this._events)[name] == null) { + base[name] = []; + } + this._events[name].push({ cb, status }); + return this.instance; + } + listenerCount(name) { + if (this._events[name] != null) { + return this._events[name].length; + } else { + return 0; + } + } + async trigger(name, ...args3) { + var e, promises; + try { + if (name !== "debug") { + this.trigger("debug", `Event triggered: ${name}`, args3); + } + if (this._events[name] == null) { + return; + } + this._events[name] = this._events[name].filter(function(listener) { + return listener.status !== "none"; + }); + promises = this._events[name].map(async (listener) => { + var e2, returned; + if (listener.status === "none") { + return; + } + if (listener.status === "once") { + listener.status = "none"; + } + try { + returned = typeof listener.cb === "function" ? listener.cb(...args3) : void 0; + if (typeof (returned != null ? returned.then : void 0) === "function") { + return await returned; + } else { + return returned; + } + } catch (error41) { + e2 = error41; + { + this.trigger("error", e2); + } + return null; + } + }); + return (await Promise.all(promises)).find(function(x) { + return x != null; + }); + } catch (error41) { + e = error41; + { + this.trigger("error", e); + } + return null; + } + } + }; + var Events_1 = Events; + var DLList$1, Events$1, Queues; + DLList$1 = DLList_1; + Events$1 = Events_1; + Queues = class Queues { + constructor(num_priorities) { + var i; + this.Events = new Events$1(this); + this._length = 0; + this._lists = (function() { + var j, ref, results; + results = []; + for (i = j = 1, ref = num_priorities; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) { + results.push(new DLList$1((() => { + return this.incr(); + }), (() => { + return this.decr(); + }))); + } + return results; + }).call(this); + } + incr() { + if (this._length++ === 0) { + return this.Events.trigger("leftzero"); + } + } + decr() { + if (--this._length === 0) { + return this.Events.trigger("zero"); + } + } + push(job) { + return this._lists[job.options.priority].push(job); + } + queued(priority) { + if (priority != null) { + return this._lists[priority].length; + } else { + return this._length; + } + } + shiftAll(fn2) { + return this._lists.forEach(function(list) { + return list.forEachShift(fn2); + }); + } + getFirst(arr = this._lists) { + var j, len, list; + for (j = 0, len = arr.length; j < len; j++) { + list = arr[j]; + if (list.length > 0) { + return list; + } + } + return []; + } + shiftLastFrom(priority) { + return this.getFirst(this._lists.slice(priority).reverse()).shift(); + } + }; + var Queues_1 = Queues; + var BottleneckError; + BottleneckError = class BottleneckError extends Error { + }; + var BottleneckError_1 = BottleneckError; + var BottleneckError$1, DEFAULT_PRIORITY, Job, NUM_PRIORITIES, parser$1; + NUM_PRIORITIES = 10; + DEFAULT_PRIORITY = 5; + parser$1 = parser; + BottleneckError$1 = BottleneckError_1; + Job = class Job { + constructor(task, args3, options, jobDefaults, rejectOnDrop, Events2, _states, Promise2) { + this.task = task; + this.args = args3; + this.rejectOnDrop = rejectOnDrop; + this.Events = Events2; + this._states = _states; + this.Promise = Promise2; + this.options = parser$1.load(options, jobDefaults); + this.options.priority = this._sanitizePriority(this.options.priority); + if (this.options.id === jobDefaults.id) { + this.options.id = `${this.options.id}-${this._randomIndex()}`; + } + this.promise = new this.Promise((_resolve, _reject) => { + this._resolve = _resolve; + this._reject = _reject; + }); + this.retryCount = 0; + } + _sanitizePriority(priority) { + var sProperty; + sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority; + if (sProperty < 0) { + return 0; + } else if (sProperty > NUM_PRIORITIES - 1) { + return NUM_PRIORITIES - 1; + } else { + return sProperty; + } + } + _randomIndex() { + return Math.random().toString(36).slice(2); + } + doDrop({ error: error41, message = "This job has been dropped by Bottleneck" } = {}) { + if (this._states.remove(this.options.id)) { + if (this.rejectOnDrop) { + this._reject(error41 != null ? error41 : new BottleneckError$1(message)); + } + this.Events.trigger("dropped", { args: this.args, options: this.options, task: this.task, promise: this.promise }); + return true; + } else { + return false; + } + } + _assertStatus(expected) { + var status; + status = this._states.jobStatus(this.options.id); + if (!(status === expected || expected === "DONE" && status === null)) { + throw new BottleneckError$1(`Invalid job status ${status}, expected ${expected}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`); + } + } + doReceive() { + this._states.start(this.options.id); + return this.Events.trigger("received", { args: this.args, options: this.options }); + } + doQueue(reachedHWM, blocked) { + this._assertStatus("RECEIVED"); + this._states.next(this.options.id); + return this.Events.trigger("queued", { args: this.args, options: this.options, reachedHWM, blocked }); + } + doRun() { + if (this.retryCount === 0) { + this._assertStatus("QUEUED"); + this._states.next(this.options.id); + } else { + this._assertStatus("EXECUTING"); + } + return this.Events.trigger("scheduled", { args: this.args, options: this.options }); + } + async doExecute(chained, clearGlobalState, run2, free) { + var error41, eventInfo, passed; + if (this.retryCount === 0) { + this._assertStatus("RUNNING"); + this._states.next(this.options.id); + } else { + this._assertStatus("EXECUTING"); + } + eventInfo = { args: this.args, options: this.options, retryCount: this.retryCount }; + this.Events.trigger("executing", eventInfo); + try { + passed = await (chained != null ? chained.schedule(this.options, this.task, ...this.args) : this.task(...this.args)); + if (clearGlobalState()) { + this.doDone(eventInfo); + await free(this.options, eventInfo); + this._assertStatus("DONE"); + return this._resolve(passed); + } + } catch (error1) { + error41 = error1; + return this._onFailure(error41, eventInfo, clearGlobalState, run2, free); + } + } + doExpire(clearGlobalState, run2, free) { + var error41, eventInfo; + if (this._states.jobStatus(this.options.id === "RUNNING")) { + this._states.next(this.options.id); + } + this._assertStatus("EXECUTING"); + eventInfo = { args: this.args, options: this.options, retryCount: this.retryCount }; + error41 = new BottleneckError$1(`This job timed out after ${this.options.expiration} ms.`); + return this._onFailure(error41, eventInfo, clearGlobalState, run2, free); + } + async _onFailure(error41, eventInfo, clearGlobalState, run2, free) { + var retry2, retryAfter; + if (clearGlobalState()) { + retry2 = await this.Events.trigger("failed", error41, eventInfo); + if (retry2 != null) { + retryAfter = ~~retry2; + this.Events.trigger("retry", `Retrying ${this.options.id} after ${retryAfter} ms`, eventInfo); + this.retryCount++; + return run2(retryAfter); + } else { + this.doDone(eventInfo); + await free(this.options, eventInfo); + this._assertStatus("DONE"); + return this._reject(error41); + } + } + } + doDone(eventInfo) { + this._assertStatus("EXECUTING"); + this._states.next(this.options.id); + return this.Events.trigger("done", eventInfo); + } + }; + var Job_1 = Job; + var BottleneckError$2, LocalDatastore, parser$2; + parser$2 = parser; + BottleneckError$2 = BottleneckError_1; + LocalDatastore = class LocalDatastore { + constructor(instance, storeOptions, storeInstanceOptions) { + this.instance = instance; + this.storeOptions = storeOptions; + this.clientId = this.instance._randomIndex(); + parser$2.load(storeInstanceOptions, storeInstanceOptions, this); + this._nextRequest = this._lastReservoirRefresh = this._lastReservoirIncrease = Date.now(); + this._running = 0; + this._done = 0; + this._unblockTime = 0; + this.ready = this.Promise.resolve(); + this.clients = {}; + this._startHeartbeat(); + } + _startHeartbeat() { + var base; + if (this.heartbeat == null && (this.storeOptions.reservoirRefreshInterval != null && this.storeOptions.reservoirRefreshAmount != null || this.storeOptions.reservoirIncreaseInterval != null && this.storeOptions.reservoirIncreaseAmount != null)) { + return typeof (base = this.heartbeat = setInterval(() => { + var amount, incr, maximum, now, reservoir; + now = Date.now(); + if (this.storeOptions.reservoirRefreshInterval != null && now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) { + this._lastReservoirRefresh = now; + this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount; + this.instance._drainAll(this.computeCapacity()); + } + if (this.storeOptions.reservoirIncreaseInterval != null && now >= this._lastReservoirIncrease + this.storeOptions.reservoirIncreaseInterval) { + ({ + reservoirIncreaseAmount: amount, + reservoirIncreaseMaximum: maximum, + reservoir + } = this.storeOptions); + this._lastReservoirIncrease = now; + incr = maximum != null ? Math.min(amount, maximum - reservoir) : amount; + if (incr > 0) { + this.storeOptions.reservoir += incr; + return this.instance._drainAll(this.computeCapacity()); + } + } + }, this.heartbeatInterval)).unref === "function" ? base.unref() : void 0; + } else { + return clearInterval(this.heartbeat); + } + } + async __publish__(message) { + await this.yieldLoop(); + return this.instance.Events.trigger("message", message.toString()); + } + async __disconnect__(flush) { + await this.yieldLoop(); + clearInterval(this.heartbeat); + return this.Promise.resolve(); + } + yieldLoop(t = 0) { + return new this.Promise(function(resolve, reject) { + return setTimeout(resolve, t); + }); + } + computePenalty() { + var ref; + return (ref = this.storeOptions.penalty) != null ? ref : 15 * this.storeOptions.minTime || 5e3; + } + async __updateSettings__(options) { + await this.yieldLoop(); + parser$2.overwrite(options, options, this.storeOptions); + this._startHeartbeat(); + this.instance._drainAll(this.computeCapacity()); + return true; + } + async __running__() { + await this.yieldLoop(); + return this._running; + } + async __queued__() { + await this.yieldLoop(); + return this.instance.queued(); + } + async __done__() { + await this.yieldLoop(); + return this._done; + } + async __groupCheck__(time2) { + await this.yieldLoop(); + return this._nextRequest + this.timeout < time2; + } + computeCapacity() { + var maxConcurrent, reservoir; + ({ maxConcurrent, reservoir } = this.storeOptions); + if (maxConcurrent != null && reservoir != null) { + return Math.min(maxConcurrent - this._running, reservoir); + } else if (maxConcurrent != null) { + return maxConcurrent - this._running; + } else if (reservoir != null) { + return reservoir; + } else { + return null; + } + } + conditionsCheck(weight) { + var capacity; + capacity = this.computeCapacity(); + return capacity == null || weight <= capacity; + } + async __incrementReservoir__(incr) { + var reservoir; + await this.yieldLoop(); + reservoir = this.storeOptions.reservoir += incr; + this.instance._drainAll(this.computeCapacity()); + return reservoir; + } + async __currentReservoir__() { + await this.yieldLoop(); + return this.storeOptions.reservoir; + } + isBlocked(now) { + return this._unblockTime >= now; + } + check(weight, now) { + return this.conditionsCheck(weight) && this._nextRequest - now <= 0; + } + async __check__(weight) { + var now; + await this.yieldLoop(); + now = Date.now(); + return this.check(weight, now); + } + async __register__(index, weight, expiration) { + var now, wait; + await this.yieldLoop(); + now = Date.now(); + if (this.conditionsCheck(weight)) { + this._running += weight; + if (this.storeOptions.reservoir != null) { + this.storeOptions.reservoir -= weight; + } + wait = Math.max(this._nextRequest - now, 0); + this._nextRequest = now + wait + this.storeOptions.minTime; + return { + success: true, + wait, + reservoir: this.storeOptions.reservoir + }; + } else { + return { + success: false + }; + } + } + strategyIsBlock() { + return this.storeOptions.strategy === 3; + } + async __submit__(queueLength, weight) { + var blocked, now, reachedHWM; + await this.yieldLoop(); + if (this.storeOptions.maxConcurrent != null && weight > this.storeOptions.maxConcurrent) { + throw new BottleneckError$2(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${this.storeOptions.maxConcurrent}`); + } + now = Date.now(); + reachedHWM = this.storeOptions.highWater != null && queueLength === this.storeOptions.highWater && !this.check(weight, now); + blocked = this.strategyIsBlock() && (reachedHWM || this.isBlocked(now)); + if (blocked) { + this._unblockTime = now + this.computePenalty(); + this._nextRequest = this._unblockTime + this.storeOptions.minTime; + this.instance._dropAllQueued(); + } + return { + reachedHWM, + blocked, + strategy: this.storeOptions.strategy + }; + } + async __free__(index, weight) { + await this.yieldLoop(); + this._running -= weight; + this._done += weight; + this.instance._drainAll(this.computeCapacity()); + return { + running: this._running + }; + } + }; + var LocalDatastore_1 = LocalDatastore; + var BottleneckError$3, States; + BottleneckError$3 = BottleneckError_1; + States = class States { + constructor(status1) { + this.status = status1; + this._jobs = {}; + this.counts = this.status.map(function() { + return 0; + }); + } + next(id) { + var current, next2; + current = this._jobs[id]; + next2 = current + 1; + if (current != null && next2 < this.status.length) { + this.counts[current]--; + this.counts[next2]++; + return this._jobs[id]++; + } else if (current != null) { + this.counts[current]--; + return delete this._jobs[id]; + } + } + start(id) { + var initial; + initial = 0; + this._jobs[id] = initial; + return this.counts[initial]++; + } + remove(id) { + var current; + current = this._jobs[id]; + if (current != null) { + this.counts[current]--; + delete this._jobs[id]; + } + return current != null; + } + jobStatus(id) { + var ref; + return (ref = this.status[this._jobs[id]]) != null ? ref : null; + } + statusJobs(status) { + var k, pos, ref, results, v; + if (status != null) { + pos = this.status.indexOf(status); + if (pos < 0) { + throw new BottleneckError$3(`status must be one of ${this.status.join(", ")}`); + } + ref = this._jobs; + results = []; + for (k in ref) { + v = ref[k]; + if (v === pos) { + results.push(k); + } + } + return results; + } else { + return Object.keys(this._jobs); + } + } + statusCounts() { + return this.counts.reduce(((acc, v, i) => { + acc[this.status[i]] = v; + return acc; + }), {}); + } + }; + var States_1 = States; + var DLList$2, Sync; + DLList$2 = DLList_1; + Sync = class Sync { + constructor(name, Promise2) { + this.schedule = this.schedule.bind(this); + this.name = name; + this.Promise = Promise2; + this._running = 0; + this._queue = new DLList$2(); + } + isEmpty() { + return this._queue.length === 0; + } + async _tryToRun() { + var args3, cb, error41, reject, resolve, returned, task; + if (this._running < 1 && this._queue.length > 0) { + this._running++; + ({ task, args: args3, resolve, reject } = this._queue.shift()); + cb = await (async function() { + try { + returned = await task(...args3); + return function() { + return resolve(returned); + }; + } catch (error1) { + error41 = error1; + return function() { + return reject(error41); + }; + } + })(); + this._running--; + this._tryToRun(); + return cb(); + } + } + schedule(task, ...args3) { + var promise, reject, resolve; + resolve = reject = null; + promise = new this.Promise(function(_resolve, _reject) { + resolve = _resolve; + return reject = _reject; + }); + this._queue.push({ task, args: args3, resolve, reject }); + this._tryToRun(); + return promise; + } + }; + var Sync_1 = Sync; + var version2 = "2.19.5"; + var version$1 = { + version: version2 + }; + var version$2 = /* @__PURE__ */ Object.freeze({ + version: version2, + default: version$1 + }); + var require$$2 = () => console.log("You must import the full version of Bottleneck in order to use this feature."); + var require$$3 = () => console.log("You must import the full version of Bottleneck in order to use this feature."); + var require$$4 = () => console.log("You must import the full version of Bottleneck in order to use this feature."); + var Events$2, Group, IORedisConnection$1, RedisConnection$1, Scripts$1, parser$3; + parser$3 = parser; + Events$2 = Events_1; + RedisConnection$1 = require$$2; + IORedisConnection$1 = require$$3; + Scripts$1 = require$$4; + Group = (function() { + class Group2 { + constructor(limiterOptions = {}) { + this.deleteKey = this.deleteKey.bind(this); + this.limiterOptions = limiterOptions; + parser$3.load(this.limiterOptions, this.defaults, this); + this.Events = new Events$2(this); + this.instances = {}; + this.Bottleneck = Bottleneck_1; + this._startAutoCleanup(); + this.sharedConnection = this.connection != null; + if (this.connection == null) { + if (this.limiterOptions.datastore === "redis") { + this.connection = new RedisConnection$1(Object.assign({}, this.limiterOptions, { Events: this.Events })); + } else if (this.limiterOptions.datastore === "ioredis") { + this.connection = new IORedisConnection$1(Object.assign({}, this.limiterOptions, { Events: this.Events })); + } + } + } + key(key = "") { + var ref; + return (ref = this.instances[key]) != null ? ref : (() => { + var limiter; + limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, { + id: `${this.id}-${key}`, + timeout: this.timeout, + connection: this.connection + })); + this.Events.trigger("created", limiter, key); + return limiter; + })(); + } + async deleteKey(key = "") { + var deleted, instance; + instance = this.instances[key]; + if (this.connection) { + deleted = await this.connection.__runCommand__(["del", ...Scripts$1.allKeys(`${this.id}-${key}`)]); + } + if (instance != null) { + delete this.instances[key]; + await instance.disconnect(); + } + return instance != null || deleted > 0; + } + limiters() { + var k, ref, results, v; + ref = this.instances; + results = []; + for (k in ref) { + v = ref[k]; + results.push({ + key: k, + limiter: v + }); + } + return results; + } + keys() { + return Object.keys(this.instances); + } + async clusterKeys() { + var cursor2, end, found, i, k, keys, len, next2, start; + if (this.connection == null) { + return this.Promise.resolve(this.keys()); + } + keys = []; + cursor2 = null; + start = `b_${this.id}-`.length; + end = "_settings".length; + while (cursor2 !== 0) { + [next2, found] = await this.connection.__runCommand__(["scan", cursor2 != null ? cursor2 : 0, "match", `b_${this.id}-*_settings`, "count", 1e4]); + cursor2 = ~~next2; + for (i = 0, len = found.length; i < len; i++) { + k = found[i]; + keys.push(k.slice(start, -end)); + } + } + return keys; + } + _startAutoCleanup() { + var base; + clearInterval(this.interval); + return typeof (base = this.interval = setInterval(async () => { + var e, k, ref, results, time2, v; + time2 = Date.now(); + ref = this.instances; + results = []; + for (k in ref) { + v = ref[k]; + try { + if (await v._store.__groupCheck__(time2)) { + results.push(this.deleteKey(k)); + } else { + results.push(void 0); + } + } catch (error41) { + e = error41; + results.push(v.Events.trigger("error", e)); + } + } + return results; + }, this.timeout / 2)).unref === "function" ? base.unref() : void 0; + } + updateSettings(options = {}) { + parser$3.overwrite(options, this.defaults, this); + parser$3.overwrite(options, options, this.limiterOptions); + if (options.timeout != null) { + return this._startAutoCleanup(); + } + } + disconnect(flush = true) { + var ref; + if (!this.sharedConnection) { + return (ref = this.connection) != null ? ref.disconnect(flush) : void 0; + } + } + } + Group2.prototype.defaults = { + timeout: 1e3 * 60 * 5, + connection: null, + Promise, + id: "group-key" + }; + return Group2; + }).call(commonjsGlobal); + var Group_1 = Group; + var Batcher, Events$3, parser$4; + parser$4 = parser; + Events$3 = Events_1; + Batcher = (function() { + class Batcher2 { + constructor(options = {}) { + this.options = options; + parser$4.load(this.options, this.defaults, this); + this.Events = new Events$3(this); + this._arr = []; + this._resetPromise(); + this._lastFlush = Date.now(); + } + _resetPromise() { + return this._promise = new this.Promise((res, rej) => { + return this._resolve = res; + }); + } + _flush() { + clearTimeout(this._timeout); + this._lastFlush = Date.now(); + this._resolve(); + this.Events.trigger("batch", this._arr); + this._arr = []; + return this._resetPromise(); + } + add(data) { + var ret; + this._arr.push(data); + ret = this._promise; + if (this._arr.length === this.maxSize) { + this._flush(); + } else if (this.maxTime != null && this._arr.length === 1) { + this._timeout = setTimeout(() => { + return this._flush(); + }, this.maxTime); + } + return ret; + } + } + Batcher2.prototype.defaults = { + maxTime: null, + maxSize: null, + Promise + }; + return Batcher2; + }).call(commonjsGlobal); + var Batcher_1 = Batcher; + var require$$4$1 = () => console.log("You must import the full version of Bottleneck in order to use this feature."); + var require$$8 = getCjsExportFromNamespace(version$2); + var Bottleneck, DEFAULT_PRIORITY$1, Events$4, Job$1, LocalDatastore$1, NUM_PRIORITIES$1, Queues$1, RedisDatastore$1, States$1, Sync$1, parser$5, splice2 = [].splice; + NUM_PRIORITIES$1 = 10; + DEFAULT_PRIORITY$1 = 5; + parser$5 = parser; + Queues$1 = Queues_1; + Job$1 = Job_1; + LocalDatastore$1 = LocalDatastore_1; + RedisDatastore$1 = require$$4$1; + Events$4 = Events_1; + States$1 = States_1; + Sync$1 = Sync_1; + Bottleneck = (function() { + class Bottleneck2 { + constructor(options = {}, ...invalid) { + var storeInstanceOptions, storeOptions; + this._addToQueue = this._addToQueue.bind(this); + this._validateOptions(options, invalid); + parser$5.load(options, this.instanceDefaults, this); + this._queues = new Queues$1(NUM_PRIORITIES$1); + this._scheduled = {}; + this._states = new States$1(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : [])); + this._limiter = null; + this.Events = new Events$4(this); + this._submitLock = new Sync$1("submit", this.Promise); + this._registerLock = new Sync$1("register", this.Promise); + storeOptions = parser$5.load(options, this.storeDefaults, {}); + this._store = (function() { + if (this.datastore === "redis" || this.datastore === "ioredis" || this.connection != null) { + storeInstanceOptions = parser$5.load(options, this.redisStoreDefaults, {}); + return new RedisDatastore$1(this, storeOptions, storeInstanceOptions); + } else if (this.datastore === "local") { + storeInstanceOptions = parser$5.load(options, this.localStoreDefaults, {}); + return new LocalDatastore$1(this, storeOptions, storeInstanceOptions); + } else { + throw new Bottleneck2.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`); + } + }).call(this); + this._queues.on("leftzero", () => { + var ref; + return (ref = this._store.heartbeat) != null ? typeof ref.ref === "function" ? ref.ref() : void 0 : void 0; + }); + this._queues.on("zero", () => { + var ref; + return (ref = this._store.heartbeat) != null ? typeof ref.unref === "function" ? ref.unref() : void 0 : void 0; + }); + } + _validateOptions(options, invalid) { + if (!(options != null && typeof options === "object" && invalid.length === 0)) { + throw new Bottleneck2.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1."); + } + } + ready() { + return this._store.ready; + } + clients() { + return this._store.clients; + } + channel() { + return `b_${this.id}`; + } + channel_client() { + return `b_${this.id}_${this._store.clientId}`; + } + publish(message) { + return this._store.__publish__(message); + } + disconnect(flush = true) { + return this._store.__disconnect__(flush); + } + chain(_limiter) { + this._limiter = _limiter; + return this; + } + queued(priority) { + return this._queues.queued(priority); + } + clusterQueued() { + return this._store.__queued__(); + } + empty() { + return this.queued() === 0 && this._submitLock.isEmpty(); + } + running() { + return this._store.__running__(); + } + done() { + return this._store.__done__(); + } + jobStatus(id) { + return this._states.jobStatus(id); + } + jobs(status) { + return this._states.statusJobs(status); + } + counts() { + return this._states.statusCounts(); + } + _randomIndex() { + return Math.random().toString(36).slice(2); + } + check(weight = 1) { + return this._store.__check__(weight); + } + _clearGlobalState(index) { + if (this._scheduled[index] != null) { + clearTimeout(this._scheduled[index].expiration); + delete this._scheduled[index]; + return true; + } else { + return false; + } + } + async _free(index, job, options, eventInfo) { + var e, running; + try { + ({ running } = await this._store.__free__(index, options.weight)); + this.Events.trigger("debug", `Freed ${options.id}`, eventInfo); + if (running === 0 && this.empty()) { + return this.Events.trigger("idle"); + } + } catch (error1) { + e = error1; + return this.Events.trigger("error", e); + } + } + _run(index, job, wait) { + var clearGlobalState, free, run2; + job.doRun(); + clearGlobalState = this._clearGlobalState.bind(this, index); + run2 = this._run.bind(this, index, job); + free = this._free.bind(this, index, job); + return this._scheduled[index] = { + timeout: setTimeout(() => { + return job.doExecute(this._limiter, clearGlobalState, run2, free); + }, wait), + expiration: job.options.expiration != null ? setTimeout(function() { + return job.doExpire(clearGlobalState, run2, free); + }, wait + job.options.expiration) : void 0, + job + }; + } + _drainOne(capacity) { + return this._registerLock.schedule(() => { + var args3, index, next2, options, queue; + if (this.queued() === 0) { + return this.Promise.resolve(null); + } + queue = this._queues.getFirst(); + ({ options, args: args3 } = next2 = queue.first()); + if (capacity != null && options.weight > capacity) { + return this.Promise.resolve(null); + } + this.Events.trigger("debug", `Draining ${options.id}`, { args: args3, options }); + index = this._randomIndex(); + return this._store.__register__(index, options.weight, options.expiration).then(({ success, wait, reservoir }) => { + var empty; + this.Events.trigger("debug", `Drained ${options.id}`, { success, args: args3, options }); + if (success) { + queue.shift(); + empty = this.empty(); + if (empty) { + this.Events.trigger("empty"); + } + if (reservoir === 0) { + this.Events.trigger("depleted", empty); + } + this._run(index, next2, wait); + return this.Promise.resolve(options.weight); + } else { + return this.Promise.resolve(null); + } + }); + }); + } + _drainAll(capacity, total = 0) { + return this._drainOne(capacity).then((drained) => { + var newCapacity; + if (drained != null) { + newCapacity = capacity != null ? capacity - drained : capacity; + return this._drainAll(newCapacity, total + drained); + } else { + return this.Promise.resolve(total); + } + }).catch((e) => { + return this.Events.trigger("error", e); + }); + } + _dropAllQueued(message) { + return this._queues.shiftAll(function(job) { + return job.doDrop({ message }); + }); + } + stop(options = {}) { + var done, waitForExecuting; + options = parser$5.load(options, this.stopDefaults); + waitForExecuting = (at) => { + var finished; + finished = () => { + var counts; + counts = this._states.counts; + return counts[0] + counts[1] + counts[2] + counts[3] === at; + }; + return new this.Promise((resolve, reject) => { + if (finished()) { + return resolve(); + } else { + return this.on("done", () => { + if (finished()) { + this.removeAllListeners("done"); + return resolve(); + } + }); + } + }); + }; + done = options.dropWaitingJobs ? (this._run = function(index, next2) { + return next2.doDrop({ + message: options.dropErrorMessage + }); + }, this._drainOne = () => { + return this.Promise.resolve(null); + }, this._registerLock.schedule(() => { + return this._submitLock.schedule(() => { + var k, ref, v; + ref = this._scheduled; + for (k in ref) { + v = ref[k]; + if (this.jobStatus(v.job.options.id) === "RUNNING") { + clearTimeout(v.timeout); + clearTimeout(v.expiration); + v.job.doDrop({ + message: options.dropErrorMessage + }); + } + } + this._dropAllQueued(options.dropErrorMessage); + return waitForExecuting(0); + }); + })) : this.schedule({ + priority: NUM_PRIORITIES$1 - 1, + weight: 0 + }, () => { + return waitForExecuting(1); + }); + this._receive = function(job) { + return job._reject(new Bottleneck2.prototype.BottleneckError(options.enqueueErrorMessage)); + }; + this.stop = () => { + return this.Promise.reject(new Bottleneck2.prototype.BottleneckError("stop() has already been called")); + }; + return done; + } + async _addToQueue(job) { + var args3, blocked, error41, options, reachedHWM, shifted, strategy; + ({ args: args3, options } = job); + try { + ({ reachedHWM, blocked, strategy } = await this._store.__submit__(this.queued(), options.weight)); + } catch (error1) { + error41 = error1; + this.Events.trigger("debug", `Could not queue ${options.id}`, { args: args3, options, error: error41 }); + job.doDrop({ error: error41 }); + return false; + } + if (blocked) { + job.doDrop(); + return true; + } else if (reachedHWM) { + shifted = strategy === Bottleneck2.prototype.strategy.LEAK ? this._queues.shiftLastFrom(options.priority) : strategy === Bottleneck2.prototype.strategy.OVERFLOW_PRIORITY ? this._queues.shiftLastFrom(options.priority + 1) : strategy === Bottleneck2.prototype.strategy.OVERFLOW ? job : void 0; + if (shifted != null) { + shifted.doDrop(); + } + if (shifted == null || strategy === Bottleneck2.prototype.strategy.OVERFLOW) { + if (shifted == null) { + job.doDrop(); + } + return reachedHWM; + } + } + job.doQueue(reachedHWM, blocked); + this._queues.push(job); + await this._drainAll(); + return reachedHWM; + } + _receive(job) { + if (this._states.jobStatus(job.options.id) != null) { + job._reject(new Bottleneck2.prototype.BottleneckError(`A job with the same id already exists (id=${job.options.id})`)); + return false; + } else { + job.doReceive(); + return this._submitLock.schedule(this._addToQueue, job); + } + } + submit(...args3) { + var cb, fn2, job, options, ref, ref1, task; + if (typeof args3[0] === "function") { + ref = args3, [fn2, ...args3] = ref, [cb] = splice2.call(args3, -1); + options = parser$5.load({}, this.jobDefaults); + } else { + ref1 = args3, [options, fn2, ...args3] = ref1, [cb] = splice2.call(args3, -1); + options = parser$5.load(options, this.jobDefaults); + } + task = (...args4) => { + return new this.Promise(function(resolve, reject) { + return fn2(...args4, function(...args5) { + return (args5[0] != null ? reject : resolve)(args5); + }); + }); + }; + job = new Job$1(task, args3, options, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); + job.promise.then(function(args4) { + return typeof cb === "function" ? cb(...args4) : void 0; + }).catch(function(args4) { + if (Array.isArray(args4)) { + return typeof cb === "function" ? cb(...args4) : void 0; + } else { + return typeof cb === "function" ? cb(args4) : void 0; + } + }); + return this._receive(job); + } + schedule(...args3) { + var job, options, task; + if (typeof args3[0] === "function") { + [task, ...args3] = args3; + options = {}; + } else { + [options, task, ...args3] = args3; + } + job = new Job$1(task, args3, options, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); + this._receive(job); + return job.promise; + } + wrap(fn2) { + var schedule, wrapped; + schedule = this.schedule.bind(this); + wrapped = function(...args3) { + return schedule(fn2.bind(this), ...args3); + }; + wrapped.withOptions = function(options, ...args3) { + return schedule(options, fn2, ...args3); + }; + return wrapped; + } + async updateSettings(options = {}) { + await this._store.__updateSettings__(parser$5.overwrite(options, this.storeDefaults)); + parser$5.overwrite(options, this.instanceDefaults, this); + return this; + } + currentReservoir() { + return this._store.__currentReservoir__(); + } + incrementReservoir(incr = 0) { + return this._store.__incrementReservoir__(incr); + } + } + Bottleneck2.default = Bottleneck2; + Bottleneck2.Events = Events$4; + Bottleneck2.version = Bottleneck2.prototype.version = require$$8.version; + Bottleneck2.strategy = Bottleneck2.prototype.strategy = { + LEAK: 1, + OVERFLOW: 2, + OVERFLOW_PRIORITY: 4, + BLOCK: 3 + }; + Bottleneck2.BottleneckError = Bottleneck2.prototype.BottleneckError = BottleneckError_1; + Bottleneck2.Group = Bottleneck2.prototype.Group = Group_1; + Bottleneck2.RedisConnection = Bottleneck2.prototype.RedisConnection = require$$2; + Bottleneck2.IORedisConnection = Bottleneck2.prototype.IORedisConnection = require$$3; + Bottleneck2.Batcher = Bottleneck2.prototype.Batcher = Batcher_1; + Bottleneck2.prototype.jobDefaults = { + priority: DEFAULT_PRIORITY$1, + weight: 1, + expiration: null, + id: "" + }; + Bottleneck2.prototype.storeDefaults = { + maxConcurrent: null, + minTime: 0, + highWater: null, + strategy: Bottleneck2.prototype.strategy.LEAK, + penalty: null, + reservoir: null, + reservoirRefreshInterval: null, + reservoirRefreshAmount: null, + reservoirIncreaseInterval: null, + reservoirIncreaseAmount: null, + reservoirIncreaseMaximum: null + }; + Bottleneck2.prototype.localStoreDefaults = { + Promise, + timeout: null, + heartbeatInterval: 250 + }; + Bottleneck2.prototype.redisStoreDefaults = { + Promise, + timeout: null, + heartbeatInterval: 5e3, + clientTimeout: 1e4, + Redis: null, + clientOptions: {}, + clusterNodes: null, + clearDatastore: false, + connection: null + }; + Bottleneck2.prototype.instanceDefaults = { + datastore: "local", + connection: null, + id: "", + rejectOnDrop: true, + trackDoneStatus: false, + Promise + }; + Bottleneck2.prototype.stopDefaults = { + enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.", + dropWaitingJobs: true, + dropErrorMessage: "This limiter has been stopped." + }; + return Bottleneck2; + }).call(commonjsGlobal); + var Bottleneck_1 = Bottleneck; + var lib = Bottleneck_1; + return lib; + })); + } +}); + // node_modules/.pnpm/fast-content-type-parse@3.0.0/node_modules/fast-content-type-parse/index.js var require_fast_content_type_parse = __commonJS({ "node_modules/.pnpm/fast-content-type-parse@3.0.0/node_modules/fast-content-type-parse/index.js"(exports, module) { @@ -26159,13 +27478,13 @@ function timeRegex2(args3) { return new RegExp(`^${timeRegexSource2(args3)}$`); } function datetimeRegex2(args3) { - let regex3 = `${dateRegexSource2}T${timeRegexSource2(args3)}`; + let regex4 = `${dateRegexSource2}T${timeRegexSource2(args3)}`; const opts = []; opts.push(args3.local ? `Z?` : `Z`); if (args3.offset) opts.push(`([+-]\\d{2}:?\\d{2})`); - regex3 = `${regex3}(${opts.join("|")})`; - return new RegExp(`^${regex3}$`); + regex4 = `${regex4}(${opts.join("|")})`; + return new RegExp(`^${regex4}$`); } function isValidIP2(ip2, version2) { if ((version2 === "v4" || !version2) && ipv4Regex2.test(ip2)) { @@ -26863,8 +28182,8 @@ var init_types = __esm({ status.dirty(); } } else if (check.kind === "datetime") { - const regex3 = datetimeRegex2(check); - if (!regex3.test(input.data)) { + const regex4 = datetimeRegex2(check); + if (!regex4.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext2(ctx, { code: ZodIssueCode2.invalid_string, @@ -26874,8 +28193,8 @@ var init_types = __esm({ status.dirty(); } } else if (check.kind === "date") { - const regex3 = dateRegex2; - if (!regex3.test(input.data)) { + const regex4 = dateRegex2; + if (!regex4.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext2(ctx, { code: ZodIssueCode2.invalid_string, @@ -26885,8 +28204,8 @@ var init_types = __esm({ status.dirty(); } } else if (check.kind === "time") { - const regex3 = timeRegex2(check); - if (!regex3.test(input.data)) { + const regex4 = timeRegex2(check); + if (!regex4.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext2(ctx, { code: ZodIssueCode2.invalid_string, @@ -26961,8 +28280,8 @@ var init_types = __esm({ } return { status: status.value, value: input.data }; } - _regex(regex3, validation, message) { - return this.refinement((data) => regex3.test(data), { + _regex(regex4, validation, message) { + return this.refinement((data) => regex4.test(data), { validation, code: ZodIssueCode2.invalid_string, ...errorUtil2.errToObj(message) @@ -27054,10 +28373,10 @@ var init_types = __esm({ duration(message) { return this._addCheck({ kind: "duration", ...errorUtil2.errToObj(message) }); } - regex(regex3, message) { + regex(regex4, message) { return this._addCheck({ kind: "regex", - regex: regex3, + regex: regex4, ...errorUtil2.errToObj(message) }); } @@ -32131,7 +33450,7 @@ var require_formats2 = __commonJS({ ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, // optimized http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex3, + regex: regex4, // uuid: http://tools.ietf.org/html/rfc4122 uuid: UUID, // JSON-pointer: https://tools.ietf.org/html/rfc6901 @@ -32153,7 +33472,7 @@ var require_formats2 = __commonJS({ hostname: HOSTNAME, ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex3, + regex: regex4, uuid: UUID, "json-pointer": JSON_POINTER, "json-pointer-uri-fragment": JSON_POINTER_URI_FRAGMENT, @@ -32189,7 +33508,7 @@ var require_formats2 = __commonJS({ return NOT_URI_FRAGMENT.test(str) && URI.test(str); } var Z_ANCHOR = /[^\\]\\Z/; - function regex3(str) { + function regex4(str) { if (Z_ANCHOR.test(str)) return false; try { new RegExp(str); @@ -35717,10 +37036,10 @@ var require_ajv2 = __commonJS({ } return this; } - function _removeAllSchemas(self2, schemas, regex3) { + function _removeAllSchemas(self2, schemas, regex4) { for (var keyRef in schemas) { var schemaObj = schemas[keyRef]; - if (!schemaObj.meta && (!regex3 || regex3.test(keyRef))) { + if (!schemaObj.meta && (!regex4 || regex4.test(keyRef))) { self2._cache.del(schemaObj.cacheKey); delete schemas[keyRef]; } @@ -35875,7 +37194,7 @@ var require_ajv2 = __commonJS({ function setLogger(self2) { var logger = self2._opts.logger; if (logger === false) { - self2.logger = { log: noop3, warn: noop3, error: noop3 }; + self2.logger = { log: noop4, warn: noop4, error: noop4 }; } else { if (logger === void 0) logger = console; if (!(typeof logger == "object" && logger.log && logger.warn && logger.error)) @@ -35883,7 +37202,7 @@ var require_ajv2 = __commonJS({ self2.logger = logger; } } - function noop3() { + function noop4() { } } }); @@ -36871,7 +38190,7 @@ var require_util11 = __commonJS({ yield* this[kBody]; } }; - function noop3() { + function noop4() { } function wrapRequestBody(body) { if (isStream(body)) { @@ -37282,7 +38601,7 @@ var require_util11 = __commonJS({ } var setupConnectTimeout = process.platform === "win32" ? (socketWeakRef, opts) => { if (!opts.timeout) { - return noop3; + return noop4; } let s1 = null; let s2 = null; @@ -37298,7 +38617,7 @@ var require_util11 = __commonJS({ }; } : (socketWeakRef, opts) => { if (!opts.timeout) { - return noop3; + return noop4; } let s1 = null; const fastTimer = timers.setFastTimeout(() => { @@ -41548,12 +42867,12 @@ var require_body2 = __commonJS({ random = (max) => Math.floor(Math.random() * max); } var textEncoder = new TextEncoder(); - function noop3() { + function noop4() { } var streamRegistry = new FinalizationRegistry((weakRef) => { const stream = weakRef.deref(); if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) { - stream.cancel("Response object has been garbage collected").catch(noop3); + stream.cancel("Response object has been garbage collected").catch(noop4); } }); function extractBody(object2, keepalive = false) { @@ -43642,7 +44961,7 @@ var require_client2 = __commonJS({ var getDefaultNodeMaxHeaderSize = http2 && http2.maxHeaderSize && Number.isInteger(http2.maxHeaderSize) && http2.maxHeaderSize > 0 ? () => http2.maxHeaderSize : () => { throw new InvalidArgumentError("http module not available or http.maxHeaderSize invalid"); }; - var noop3 = () => { + var noop4 = () => { }; function getPipelining(client) { return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1; @@ -43916,7 +45235,7 @@ var require_client2 = __commonJS({ return; } if (client.destroyed) { - util3.destroy(socket.on("error", noop3), new ClientDestroyedError()); + util3.destroy(socket.on("error", noop4), new ClientDestroyedError()); client[kResume](); return; } @@ -43924,7 +45243,7 @@ var require_client2 = __commonJS({ try { client[kHTTPContext] = socket.alpnProtocol === "h2" ? connectH2(client, socket) : connectH1(client, socket); } catch (err2) { - socket.destroy().on("error", noop3); + socket.destroy().on("error", noop4); handleConnectError(client, err2, { host, hostname: hostname2, protocol, port }); client[kResume](); return; @@ -44708,7 +46027,7 @@ var require_proxy_agent2 = __commonJS({ function defaultFactory(origin, opts) { return new Pool(origin, opts); } - var noop3 = () => { + var noop4 = () => { }; function defaultAgentFactory(origin, opts) { if (opts.connections === 1) { @@ -44825,7 +46144,7 @@ var require_proxy_agent2 = __commonJS({ servername: this[kProxyTls]?.servername || proxyHostname }); if (statusCode !== 200) { - socket.on("error", noop3).destroy(); + socket.on("error", noop4).destroy(); callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`)); } if (opts2.protocol !== "https:") { @@ -45492,7 +46811,7 @@ var require_readable2 = __commonJS({ var kContentLength = Symbol("kContentLength"); var kUsed = Symbol("kUsed"); var kBytesRead = Symbol("kBytesRead"); - var noop3 = () => { + var noop4 = () => { }; var BodyReadable = class extends Readable { /** @@ -45717,7 +47036,7 @@ var require_readable2 = __commonJS({ } else { this.on("close", resolve); } - this.on("error", noop3).on("data", () => { + this.on("error", noop4).on("data", () => { if (this[kBytesRead] > limit) { this.destroy(); } @@ -45886,7 +47205,7 @@ var require_api_request2 = __commonJS({ var { Readable } = require_readable2(); var { InvalidArgumentError, RequestAbortedError } = require_errors2(); var util3 = require_util11(); - function noop3() { + function noop4() { } var RequestHandler = class extends AsyncResource { constructor(opts, callback) { @@ -45913,7 +47232,7 @@ var require_api_request2 = __commonJS({ super("UNDICI_REQUEST"); } catch (err) { if (util3.isStream(body)) { - util3.destroy(body.on("error", noop3), err); + util3.destroy(body.on("error", noop4), err); } throw err; } @@ -45936,7 +47255,7 @@ var require_api_request2 = __commonJS({ this.removeAbortListener = util3.addAbortListener(signal, () => { this.reason = signal.reason ?? new RequestAbortedError(); if (this.res) { - util3.destroy(this.res.on("error", noop3), this.reason); + util3.destroy(this.res.on("error", noop4), this.reason); } else if (this.abort) { this.abort(this.reason); } @@ -45989,7 +47308,7 @@ var require_api_request2 = __commonJS({ }); } catch (err) { this.res = null; - util3.destroy(res.on("error", noop3), err); + util3.destroy(res.on("error", noop4), err); queueMicrotask(() => { throw err; }); @@ -46014,13 +47333,13 @@ var require_api_request2 = __commonJS({ if (res) { this.res = null; queueMicrotask(() => { - util3.destroy(res.on("error", noop3), err); + util3.destroy(res.on("error", noop4), err); }); } if (body) { this.body = null; if (util3.isStream(body)) { - body.on("error", noop3); + body.on("error", noop4); util3.destroy(body, err); } } @@ -46116,7 +47435,7 @@ var require_api_stream2 = __commonJS({ var { InvalidArgumentError, InvalidReturnValueError } = require_errors2(); var util3 = require_util11(); var { addSignal, removeSignal } = require_abort_signal2(); - function noop3() { + function noop4() { } var StreamHandler = class extends AsyncResource { constructor(opts, factory, callback) { @@ -46143,7 +47462,7 @@ var require_api_stream2 = __commonJS({ super("UNDICI_STREAM"); } catch (err) { if (util3.isStream(body)) { - util3.destroy(body.on("error", noop3), err); + util3.destroy(body.on("error", noop4), err); } throw err; } @@ -46285,7 +47604,7 @@ var require_api_pipeline2 = __commonJS({ } = require_errors2(); var util3 = require_util11(); var { addSignal, removeSignal } = require_abort_signal2(); - function noop3() { + function noop4() { } var kResume = Symbol("resume"); var PipelineRequest = class extends Readable { @@ -46345,7 +47664,7 @@ var require_api_pipeline2 = __commonJS({ this.abort = null; this.context = null; this.onInfo = onInfo || null; - this.req = new PipelineRequest().on("error", noop3); + this.req = new PipelineRequest().on("error", noop4); this.ret = new Duplex({ readableObjectMode: opts.objectMode, autoDestroy: true, @@ -46416,7 +47735,7 @@ var require_api_pipeline2 = __commonJS({ context }); } catch (err) { - this.res.on("error", noop3); + this.res.on("error", noop4); throw err; } if (!body || typeof body.on !== "function") { @@ -48638,7 +49957,7 @@ var require_redirect_handler = __commonJS({ var EE = __require("node:events"); var redirectableStatusCodes = [300, 301, 302, 303, 307, 308]; var kBody = Symbol("body"); - var noop3 = () => { + var noop4 = () => { }; var BodyAsyncIterable = class { constructor(body) { @@ -48701,14 +50020,14 @@ var require_redirect_handler = __commonJS({ if ((statusCode === 301 || statusCode === 302) && this.opts.method === "POST") { this.opts.method = "GET"; if (util3.isStream(this.opts.body)) { - util3.destroy(this.opts.body.on("error", noop3)); + util3.destroy(this.opts.body.on("error", noop4)); } this.opts.body = null; } if (statusCode === 303 && this.opts.method !== "HEAD") { this.opts.method = "GET"; if (util3.isStream(this.opts.body)) { - util3.destroy(this.opts.body.on("error", noop3)); + util3.destroy(this.opts.body.on("error", noop4)); } this.opts.body = null; } @@ -50096,7 +51415,7 @@ var require_cache_handler = __commonJS({ isEtagUsable } = require_cache5(); var { parseHttpDate } = require_date(); - function noop3() { + function noop4() { } var HEURISTICALLY_CACHEABLE_STATUS_CODES = [ 200, @@ -50177,7 +51496,7 @@ var require_cache_handler = __commonJS({ ); if (!util3.safeHTTPMethods.includes(this.#cacheKey.method) && statusCode >= 200 && statusCode <= 399) { try { - this.#store.delete(this.#cacheKey)?.catch?.(noop3); + this.#store.delete(this.#cacheKey)?.catch?.(noop4); } catch { } return downstreamOnHeaders(); @@ -51173,7 +52492,7 @@ var require_sqlite_cache_store = __commonJS({ var { Writable } = __require("node:stream"); var { assertCacheKey, assertCacheValue } = require_cache5(); var DatabaseSync; - var VERSION9 = 3; + var VERSION10 = 3; var MAX_ENTRY_SIZE = 2 * 1e3 * 1e3 * 1e3; module.exports = class SqliteCacheStore { #maxEntrySize = MAX_ENTRY_SIZE; @@ -51244,7 +52563,7 @@ var require_sqlite_cache_store = __commonJS({ PRAGMA temp_store = memory; PRAGMA optimize; - CREATE TABLE IF NOT EXISTS cacheInterceptorV${VERSION9} ( + CREATE TABLE IF NOT EXISTS cacheInterceptorV${VERSION10} ( -- Data specific to us id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL, @@ -51263,8 +52582,8 @@ var require_sqlite_cache_store = __commonJS({ staleAt INTEGER NOT NULL ); - CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION9}_getValuesQuery ON cacheInterceptorV${VERSION9}(url, method, deleteAt); - CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION9}_deleteByUrlQuery ON cacheInterceptorV${VERSION9}(deleteAt); + CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION10}_getValuesQuery ON cacheInterceptorV${VERSION10}(url, method, deleteAt); + CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION10}_deleteByUrlQuery ON cacheInterceptorV${VERSION10}(deleteAt); `); this.#getValuesQuery = this.#db.prepare(` SELECT @@ -51279,7 +52598,7 @@ var require_sqlite_cache_store = __commonJS({ vary, cachedAt, staleAt - FROM cacheInterceptorV${VERSION9} + FROM cacheInterceptorV${VERSION10} WHERE url = ? AND method = ? @@ -51287,7 +52606,7 @@ var require_sqlite_cache_store = __commonJS({ deleteAt ASC `); this.#updateValueQuery = this.#db.prepare(` - UPDATE cacheInterceptorV${VERSION9} SET + UPDATE cacheInterceptorV${VERSION10} SET body = ?, deleteAt = ?, statusCode = ?, @@ -51301,7 +52620,7 @@ var require_sqlite_cache_store = __commonJS({ id = ? `); this.#insertValueQuery = this.#db.prepare(` - INSERT INTO cacheInterceptorV${VERSION9} ( + INSERT INTO cacheInterceptorV${VERSION10} ( url, method, body, @@ -51317,20 +52636,20 @@ var require_sqlite_cache_store = __commonJS({ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); this.#deleteByUrlQuery = this.#db.prepare( - `DELETE FROM cacheInterceptorV${VERSION9} WHERE url = ?` + `DELETE FROM cacheInterceptorV${VERSION10} WHERE url = ?` ); this.#countEntriesQuery = this.#db.prepare( - `SELECT COUNT(*) AS total FROM cacheInterceptorV${VERSION9}` + `SELECT COUNT(*) AS total FROM cacheInterceptorV${VERSION10}` ); this.#deleteExpiredValuesQuery = this.#db.prepare( - `DELETE FROM cacheInterceptorV${VERSION9} WHERE deleteAt <= ?` + `DELETE FROM cacheInterceptorV${VERSION10} WHERE deleteAt <= ?` ); this.#deleteOldValuesQuery = this.#maxCount === Infinity ? null : this.#db.prepare(` - DELETE FROM cacheInterceptorV${VERSION9} + DELETE FROM cacheInterceptorV${VERSION10} WHERE id IN ( SELECT id - FROM cacheInterceptorV${VERSION9} + FROM cacheInterceptorV${VERSION10} ORDER BY cachedAt DESC LIMIT ? ) @@ -52518,15 +53837,15 @@ var require_request4 = __commonJS({ this.#dispatcher = init.dispatcher || input.#dispatcher; } const origin = environmentSettingsObject.settingsObject.origin; - let window = "client"; + let window2 = "client"; if (request2.window?.constructor?.name === "EnvironmentSettingsObject" && sameOrigin(request2.window, origin)) { - window = request2.window; + window2 = request2.window; } if (init.window != null) { - throw new TypeError(`'window' option '${window}' must be null`); + throw new TypeError(`'window' option '${window2}' must be null`); } if ("window" in init) { - window = "no-window"; + window2 = "no-window"; } request2 = makeRequest({ // URL request’s URL. @@ -52541,7 +53860,7 @@ var require_request4 = __commonJS({ // client This’s relevant settings object. client: environmentSettingsObject.settingsObject, // window window. - window, + window: window2, // priority request’s priority. priority: request2.priority, // origin request’s origin. The propagation of the origin is only significant for navigation requests @@ -59686,8 +61005,8 @@ function emoji() { } function timeSource(args3) { const hhmm = `(?:[01]\\d|2[0-3]):[0-5]\\d`; - const regex3 = typeof args3.precision === "number" ? args3.precision === -1 ? `${hhmm}` : args3.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args3.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; - return regex3; + const regex4 = typeof args3.precision === "number" ? args3.precision === -1 ? `${hhmm}` : args3.precision === 0 ? `${hhmm}:[0-5]\\d` : `${hhmm}:[0-5]\\d\\.\\d{${args3.precision}}` : `${hhmm}(?::[0-5]\\d(?:\\.\\d+)?)?`; + return regex4; } function time(args3) { return new RegExp(`^${timeSource(args3)}$`); @@ -59740,8 +61059,8 @@ var init_regexes = __esm({ dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`; date = /* @__PURE__ */ new RegExp(`^${dateSource}$`); string2 = (params) => { - const regex3 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; - return new RegExp(`^${regex3}$`); + const regex4 = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`; + return new RegExp(`^${regex4}$`); }; bigint = /^\d+n?$/; integer2 = /^\d+$/; @@ -68244,9 +69563,9 @@ var init_to_json_schema = __esm({ json3.pattern = regexes[0].source; else if (regexes.length > 1) { result.schema.allOf = [ - ...regexes.map((regex3) => ({ + ...regexes.map((regex4) => ({ ...this.target === "draft-7" ? { type: "string" } : {}, - pattern: regex3.source + pattern: regex4.source })) ]; } @@ -69672,7 +70991,7 @@ function addFormat(schema2, value2, message, refs) { setResponseValueAndErrors(schema2, "format", value2, message, refs); } } -function addPattern(schema2, regex3, message, refs) { +function addPattern(schema2, regex4, message, refs) { if (schema2.pattern || schema2.allOf?.some((x) => x.pattern)) { if (!schema2.allOf) { schema2.allOf = []; @@ -69693,24 +71012,24 @@ function addPattern(schema2, regex3, message, refs) { } } schema2.allOf.push({ - pattern: stringifyRegExpWithFlags(regex3, refs), + pattern: stringifyRegExpWithFlags(regex4, refs), ...message && refs.errorMessages && { errorMessage: { pattern: message } } }); } else { - setResponseValueAndErrors(schema2, "pattern", stringifyRegExpWithFlags(regex3, refs), message, refs); + setResponseValueAndErrors(schema2, "pattern", stringifyRegExpWithFlags(regex4, refs), message, refs); } } -function stringifyRegExpWithFlags(regex3, refs) { - if (!refs.applyRegexFlags || !regex3.flags) { - return regex3.source; +function stringifyRegExpWithFlags(regex4, refs) { + if (!refs.applyRegexFlags || !regex4.flags) { + return regex4.source; } const flags = { - i: regex3.flags.includes("i"), - m: regex3.flags.includes("m"), - s: regex3.flags.includes("s") + i: regex4.flags.includes("i"), + m: regex4.flags.includes("m"), + s: regex4.flags.includes("s") // `.` matches newlines }; - const source = flags.i ? regex3.source.toLowerCase() : regex3.source; + const source = flags.i ? regex4.source.toLowerCase() : regex4.source; let pattern = ""; let isEscaped = false; let inCharGroup = false; @@ -69771,7 +71090,7 @@ function stringifyRegExpWithFlags(regex3, refs) { new RegExp(pattern); } catch { console.warn(`Could not convert regex pattern at ${refs.currentPath.join("/")} to a flag-independent form! Falling back to the flag-ignorant source`); - return regex3.source; + return regex4.source; } return pattern; } @@ -70984,9 +72303,9 @@ var isomorphic = { }; // node_modules/.pnpm/@ark+util@0.53.0/node_modules/@ark/util/out/strings.js -var anchoredRegex = (regex3) => new RegExp(anchoredSource(regex3), typeof regex3 === "string" ? "" : regex3.flags); -var anchoredSource = (regex3) => { - const source = typeof regex3 === "string" ? regex3 : regex3.source; +var anchoredRegex = (regex4) => new RegExp(anchoredSource(regex4), typeof regex4 === "string" ? "" : regex4.flags); +var anchoredSource = (regex4) => { + const source = typeof regex4 === "string" ? regex4 : regex4.source; return `^(?:${source})$`; }; var RegexPatterns = { @@ -73514,7 +74833,7 @@ var require_formats = __commonJS2((exports, module) => { hostname: HOSTNAME, ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex3, + regex: regex4, uuid: UUID, "json-pointer": JSON_POINTER, "json-pointer-uri-fragment": JSON_POINTER_URI_FRAGMENT, @@ -73532,7 +74851,7 @@ var require_formats = __commonJS2((exports, module) => { hostname: HOSTNAME, ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex3, + regex: regex4, uuid: UUID, "json-pointer": JSON_POINTER, "json-pointer-uri-fragment": JSON_POINTER_URI_FRAGMENT, @@ -73570,7 +74889,7 @@ var require_formats = __commonJS2((exports, module) => { return NOT_URI_FRAGMENT.test(str) && URI.test(str); } var Z_ANCHOR = /[^\\]\\Z/; - function regex3(str) { + function regex4(str) { if (Z_ANCHOR.test(str)) return false; try { @@ -76959,10 +78278,10 @@ var require_ajv = __commonJS2((exports, module) => { } return this; } - function _removeAllSchemas(self2, schemas, regex3) { + function _removeAllSchemas(self2, schemas, regex4) { for (var keyRef in schemas) { var schemaObj = schemas[keyRef]; - if (!schemaObj.meta && (!regex3 || regex3.test(keyRef))) { + if (!schemaObj.meta && (!regex4 || regex4.test(keyRef))) { self2._cache.del(schemaObj.cacheKey); delete schemas[keyRef]; } @@ -77133,7 +78452,7 @@ var require_ajv = __commonJS2((exports, module) => { function setLogger(self2) { var logger = self2._opts.logger; if (logger === false) { - self2.logger = { log: noop3, warn: noop3, error: noop3 }; + self2.logger = { log: noop4, warn: noop4, error: noop4 }; } else { if (logger === void 0) logger = console; @@ -77142,7 +78461,7 @@ var require_ajv = __commonJS2((exports, module) => { self2.logger = logger; } } - function noop3() { + function noop4() { } }); var DEFAULT_MAX_LISTENERS = 50; @@ -79638,13 +80957,13 @@ function timeRegex(args3) { return new RegExp(`^${timeRegexSource(args3)}$`); } function datetimeRegex(args3) { - let regex3 = `${dateRegexSource}T${timeRegexSource(args3)}`; + let regex4 = `${dateRegexSource}T${timeRegexSource(args3)}`; const opts = []; opts.push(args3.local ? `Z?` : `Z`); if (args3.offset) opts.push(`([+-]\\d{2}:?\\d{2})`); - regex3 = `${regex3}(${opts.join("|")})`; - return new RegExp(`^${regex3}$`); + regex4 = `${regex4}(${opts.join("|")})`; + return new RegExp(`^${regex4}$`); } function isValidIP(ip2, version2) { if ((version2 === "v4" || !version2) && ipv4Regex.test(ip2)) { @@ -79890,8 +81209,8 @@ var ZodString = class _ZodString extends ZodType { status.dirty(); } } else if (check.kind === "datetime") { - const regex3 = datetimeRegex(check); - if (!regex3.test(input.data)) { + const regex4 = datetimeRegex(check); + if (!regex4.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, @@ -79901,8 +81220,8 @@ var ZodString = class _ZodString extends ZodType { status.dirty(); } } else if (check.kind === "date") { - const regex3 = dateRegex; - if (!regex3.test(input.data)) { + const regex4 = dateRegex; + if (!regex4.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, @@ -79912,8 +81231,8 @@ var ZodString = class _ZodString extends ZodType { status.dirty(); } } else if (check.kind === "time") { - const regex3 = timeRegex(check); - if (!regex3.test(input.data)) { + const regex4 = timeRegex(check); + if (!regex4.test(input.data)) { ctx = this._getOrReturnCtx(input, ctx); addIssueToContext(ctx, { code: ZodIssueCode.invalid_string, @@ -79988,8 +81307,8 @@ var ZodString = class _ZodString extends ZodType { } return { status: status.value, value: input.data }; } - _regex(regex3, validation, message) { - return this.refinement((data) => regex3.test(data), { + _regex(regex4, validation, message) { + return this.refinement((data) => regex4.test(data), { validation, code: ZodIssueCode.invalid_string, ...errorUtil.errToObj(message) @@ -80081,10 +81400,10 @@ var ZodString = class _ZodString extends ZodType { duration(message) { return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message) }); } - regex(regex3, message) { + regex(regex4, message) { return this._addCheck({ kind: "regex", - regex: regex3, + regex: regex4, ...errorUtil.errToObj(message) }); } @@ -83356,11 +84675,13 @@ var package_default = { "@anthropic-ai/claude-agent-sdk": "0.1.37", "@ark/fs": "0.53.0", "@ark/util": "0.53.0", + "@octokit/plugin-throttling": "^11.0.3", "@octokit/rest": "^22.0.0", "@octokit/webhooks-types": "^7.6.1", "@openai/codex-sdk": "0.58.0", "@opencode-ai/sdk": "^1.0.143", "@standard-schema/spec": "1.0.0", + "@toon-format/toon": "^1.0.0", arktype: "2.1.28", "package-manager-detector": "^1.6.0", dotenv: "^17.2.3", @@ -83398,7 +84719,8 @@ var package_default = { import: "./dist/index.js", require: "./dist/index.cjs" } - } + }, + packageManager: "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a" }; // utils/cli.ts @@ -83667,7 +84989,7 @@ function formatJsonValue(value2) { // agents/instructions.ts import { execSync } from "node:child_process"; -// ../node_modules/.pnpm/@toon-format+toon@1.0.0/node_modules/@toon-format/toon/dist/index.js +// node_modules/.pnpm/@toon-format+toon@1.4.0/node_modules/@toon-format/toon/dist/index.mjs var LIST_ITEM_MARKER = "-"; var LIST_ITEM_PREFIX = "- "; var COMMA = ","; @@ -83688,6 +85010,9 @@ var DEFAULT_DELIMITER = DELIMITERS.comma; function escapeString(value2) { return value2.replace(/\\/g, `${BACKSLASH}${BACKSLASH}`).replace(/"/g, `${BACKSLASH}${DOUBLE_QUOTE}`).replace(/\n/g, `${BACKSLASH}n`).replace(/\r/g, `${BACKSLASH}r`).replace(/\t/g, `${BACKSLASH}t`); } +function isBooleanOrNullLiteral(token) { + return token === TRUE_LITERAL || token === FALSE_LITERAL || token === NULL_LITERAL; +} function normalizeValue(value2) { if (value2 === null) return null; if (typeof value2 === "string" || typeof value2 === "boolean") return value2; @@ -83737,9 +85062,6 @@ function isArrayOfArrays(value2) { function isArrayOfObjects(value2) { return value2.length === 0 || value2.every((item) => isJsonObject(item)); } -function isBooleanOrNullLiteral(token) { - return token === TRUE_LITERAL || token === FALSE_LITERAL || token === NULL_LITERAL; -} function isValidUnquotedKey(key) { return /^[A-Z_][\w.]*$/i.test(key); } @@ -83836,37 +85158,22 @@ function formatHeader(length, options) { header += ":"; return header; } -var LineWriter = class { - lines = []; - indentationString; - constructor(indentSize) { - this.indentationString = " ".repeat(indentSize); +function* encodeJsonValue(value2, options, depth) { + if (isJsonPrimitive(value2)) { + const encodedPrimitive = encodePrimitive(value2, options.delimiter); + if (encodedPrimitive !== "") yield encodedPrimitive; + return; } - push(depth, content) { - const indent2 = this.indentationString.repeat(depth); - this.lines.push(indent2 + content); - } - pushListItem(depth, content) { - this.push(depth, `${LIST_ITEM_PREFIX}${content}`); - } - toString() { - return this.lines.join("\n"); - } -}; -function encodeValue(value2, options) { - if (isJsonPrimitive(value2)) return encodePrimitive(value2, options.delimiter); - const writer = new LineWriter(options.indent); - if (isJsonArray(value2)) encodeArray(void 0, value2, writer, 0, options); - else if (isJsonObject(value2)) encodeObject(value2, writer, 0, options); - return writer.toString(); + if (isJsonArray(value2)) yield* encodeArrayLines(void 0, value2, depth, options); + else if (isJsonObject(value2)) yield* encodeObjectLines(value2, depth, options); } -function encodeObject(value2, writer, depth, options, rootLiteralKeys, pathPrefix, remainingDepth) { +function* encodeObjectLines(value2, depth, options, rootLiteralKeys, pathPrefix, remainingDepth) { const keys = Object.keys(value2); if (depth === 0 && !rootLiteralKeys) rootLiteralKeys = new Set(keys.filter((k) => k.includes("."))); const effectiveFlattenDepth = remainingDepth ?? options.flattenDepth; - for (const [key, val] of Object.entries(value2)) encodeKeyValuePair(key, val, writer, depth, options, keys, rootLiteralKeys, pathPrefix, effectiveFlattenDepth); + for (const [key, val] of Object.entries(value2)) yield* encodeKeyValuePairLines(key, val, depth, options, keys, rootLiteralKeys, pathPrefix, effectiveFlattenDepth); } -function encodeKeyValuePair(key, value2, writer, depth, options, siblings, rootLiteralKeys, pathPrefix, flattenDepth) { +function* encodeKeyValuePairLines(key, value2, depth, options, siblings, rootLiteralKeys, pathPrefix, flattenDepth) { const currentPath = pathPrefix ? `${pathPrefix}${DOT}${key}` : key; const effectiveFlattenDepth = flattenDepth ?? options.flattenDepth; if (options.keyFolding === "safe" && siblings) { @@ -83876,70 +85183,67 @@ function encodeKeyValuePair(key, value2, writer, depth, options, siblings, rootL const encodedFoldedKey = encodeKey(foldedKey); if (remainder === void 0) { if (isJsonPrimitive(leafValue)) { - writer.push(depth, `${encodedFoldedKey}: ${encodePrimitive(leafValue, options.delimiter)}`); + yield indentedLine(depth, `${encodedFoldedKey}: ${encodePrimitive(leafValue, options.delimiter)}`, options.indent); return; } else if (isJsonArray(leafValue)) { - encodeArray(foldedKey, leafValue, writer, depth, options); + yield* encodeArrayLines(foldedKey, leafValue, depth, options); return; } else if (isJsonObject(leafValue) && isEmptyObject(leafValue)) { - writer.push(depth, `${encodedFoldedKey}:`); + yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent); return; } } if (isJsonObject(remainder)) { - writer.push(depth, `${encodedFoldedKey}:`); + yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent); const remainingDepth = effectiveFlattenDepth - segmentCount; const foldedPath = pathPrefix ? `${pathPrefix}${DOT}${foldedKey}` : foldedKey; - encodeObject(remainder, writer, depth + 1, options, rootLiteralKeys, foldedPath, remainingDepth); + yield* encodeObjectLines(remainder, depth + 1, options, rootLiteralKeys, foldedPath, remainingDepth); return; } } } const encodedKey = encodeKey(key); - if (isJsonPrimitive(value2)) writer.push(depth, `${encodedKey}: ${encodePrimitive(value2, options.delimiter)}`); - else if (isJsonArray(value2)) encodeArray(key, value2, writer, depth, options); + if (isJsonPrimitive(value2)) yield indentedLine(depth, `${encodedKey}: ${encodePrimitive(value2, options.delimiter)}`, options.indent); + else if (isJsonArray(value2)) yield* encodeArrayLines(key, value2, depth, options); else if (isJsonObject(value2)) { - writer.push(depth, `${encodedKey}:`); - if (!isEmptyObject(value2)) encodeObject(value2, writer, depth + 1, options, rootLiteralKeys, currentPath, effectiveFlattenDepth); + yield indentedLine(depth, `${encodedKey}:`, options.indent); + if (!isEmptyObject(value2)) yield* encodeObjectLines(value2, depth + 1, options, rootLiteralKeys, currentPath, effectiveFlattenDepth); } } -function encodeArray(key, value2, writer, depth, options) { +function* encodeArrayLines(key, value2, depth, options) { if (value2.length === 0) { - const header = formatHeader(0, { + yield indentedLine(depth, formatHeader(0, { key, delimiter: options.delimiter - }); - writer.push(depth, header); + }), options.indent); return; } if (isArrayOfPrimitives(value2)) { - const arrayLine = encodeInlineArrayLine(value2, options.delimiter, key); - writer.push(depth, arrayLine); + yield indentedLine(depth, encodeInlineArrayLine(value2, options.delimiter, key), options.indent); return; } if (isArrayOfArrays(value2)) { if (value2.every((arr) => isArrayOfPrimitives(arr))) { - encodeArrayOfArraysAsListItems(key, value2, writer, depth, options); + yield* encodeArrayOfArraysAsListItemsLines(key, value2, depth, options); return; } } if (isArrayOfObjects(value2)) { const header = extractTabularHeader(value2); - if (header) encodeArrayOfObjectsAsTabular(key, value2, header, writer, depth, options); - else encodeMixedArrayAsListItems(key, value2, writer, depth, options); + if (header) yield* encodeArrayOfObjectsAsTabularLines(key, value2, header, depth, options); + else yield* encodeMixedArrayAsListItemsLines(key, value2, depth, options); return; } - encodeMixedArrayAsListItems(key, value2, writer, depth, options); + yield* encodeMixedArrayAsListItemsLines(key, value2, depth, options); } -function encodeArrayOfArraysAsListItems(prefix, values, writer, depth, options) { - const header = formatHeader(values.length, { +function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) { + yield indentedLine(depth, formatHeader(values.length, { key: prefix, delimiter: options.delimiter - }); - writer.push(depth, header); + }), options.indent); for (const arr of values) if (isArrayOfPrimitives(arr)) { const arrayLine = encodeInlineArrayLine(arr, options.delimiter); - writer.pushListItem(depth + 1, arrayLine); + yield indentedListItem(depth + 1, arrayLine, options.indent); } } function encodeInlineArrayLine(values, delimiter, prefix) { @@ -83951,14 +85255,13 @@ function encodeInlineArrayLine(values, delimiter, prefix) { if (values.length === 0) return header; return `${header} ${joinedValue}`; } -function encodeArrayOfObjectsAsTabular(prefix, rows, header, writer, depth, options) { - const formattedHeader = formatHeader(rows.length, { +function* encodeArrayOfObjectsAsTabularLines(prefix, rows, header, depth, options) { + yield indentedLine(depth, formatHeader(rows.length, { key: prefix, fields: header, delimiter: options.delimiter - }); - writer.push(depth, `${formattedHeader}`); - writeTabularRows(rows, header, writer, depth + 1, options); + }), options.indent); + yield* writeTabularRowsLines(rows, header, depth + 1, options); } function extractTabularHeader(rows) { if (rows.length === 0) return; @@ -83977,68 +85280,60 @@ function isTabularArray(rows, header) { } return true; } -function writeTabularRows(rows, header, writer, depth, options) { - for (const row of rows) { - const joinedValue = encodeAndJoinPrimitives(header.map((key) => row[key]), options.delimiter); - writer.push(depth, joinedValue); - } +function* writeTabularRowsLines(rows, header, depth, options) { + for (const row of rows) yield indentedLine(depth, encodeAndJoinPrimitives(header.map((key) => row[key]), options.delimiter), options.indent); } -function encodeMixedArrayAsListItems(prefix, items, writer, depth, options) { - const header = formatHeader(items.length, { +function* encodeMixedArrayAsListItemsLines(prefix, items, depth, options) { + yield indentedLine(depth, formatHeader(items.length, { key: prefix, delimiter: options.delimiter - }); - writer.push(depth, header); - for (const item of items) encodeListItemValue(item, writer, depth + 1, options); + }), options.indent); + for (const item of items) yield* encodeListItemValueLines(item, depth + 1, options); } -function encodeObjectAsListItem(obj, writer, depth, options) { +function* encodeObjectAsListItemLines(obj, depth, options) { if (isEmptyObject(obj)) { - writer.push(depth, LIST_ITEM_MARKER); + yield indentedLine(depth, LIST_ITEM_MARKER, options.indent); return; } const entries = Object.entries(obj); - const [firstKey, firstValue] = entries[0]; - const encodedKey = encodeKey(firstKey); - if (isJsonPrimitive(firstValue)) writer.pushListItem(depth, `${encodedKey}: ${encodePrimitive(firstValue, options.delimiter)}`); - else if (isJsonArray(firstValue)) if (isArrayOfPrimitives(firstValue)) { - const arrayPropertyLine = encodeInlineArrayLine(firstValue, options.delimiter, firstKey); - writer.pushListItem(depth, arrayPropertyLine); - } else if (isArrayOfObjects(firstValue)) { - const header = extractTabularHeader(firstValue); - if (header) { - const formattedHeader = formatHeader(firstValue.length, { - key: firstKey, - fields: header, - delimiter: options.delimiter - }); - writer.pushListItem(depth, formattedHeader); - writeTabularRows(firstValue, header, writer, depth + 1, options); - } else { - writer.pushListItem(depth, `${encodedKey}[${firstValue.length}]:`); - for (const item of firstValue) encodeObjectAsListItem(item, writer, depth + 1, options); + if (entries.length === 1) { + const [key, value2] = entries[0]; + if (isJsonArray(value2) && isArrayOfObjects(value2)) { + const header = extractTabularHeader(value2); + if (header) { + yield indentedListItem(depth, formatHeader(value2.length, { + key, + fields: header, + delimiter: options.delimiter + }), options.indent); + yield* writeTabularRowsLines(value2, header, depth + 1, options); + return; + } } - } else { - writer.pushListItem(depth, `${encodedKey}[${firstValue.length}]:`); - for (const item of firstValue) encodeListItemValue(item, writer, depth + 1, options); - } - else if (isJsonObject(firstValue)) { - writer.pushListItem(depth, `${encodedKey}:`); - if (!isEmptyObject(firstValue)) encodeObject(firstValue, writer, depth + 2, options); - } - for (let i = 1; i < entries.length; i++) { - const [key, value2] = entries[i]; - encodeKeyValuePair(key, value2, writer, depth + 1, options); } + yield indentedLine(depth, LIST_ITEM_MARKER, options.indent); + yield* encodeObjectLines(obj, depth + 1, options); } -function encodeListItemValue(value2, writer, depth, options) { - if (isJsonPrimitive(value2)) writer.pushListItem(depth, encodePrimitive(value2, options.delimiter)); - else if (isJsonArray(value2) && isArrayOfPrimitives(value2)) { - const arrayLine = encodeInlineArrayLine(value2, options.delimiter); - writer.pushListItem(depth, arrayLine); - } else if (isJsonObject(value2)) encodeObjectAsListItem(value2, writer, depth, options); +function* encodeListItemValueLines(value2, depth, options) { + if (isJsonPrimitive(value2)) yield indentedListItem(depth, encodePrimitive(value2, options.delimiter), options.indent); + else if (isJsonArray(value2)) if (isArrayOfPrimitives(value2)) yield indentedListItem(depth, encodeInlineArrayLine(value2, options.delimiter), options.indent); + else { + yield indentedListItem(depth, formatHeader(value2.length, { delimiter: options.delimiter }), options.indent); + for (const item of value2) yield* encodeListItemValueLines(item, depth + 1, options); + } + else if (isJsonObject(value2)) yield* encodeObjectAsListItemLines(value2, depth, options); +} +function indentedLine(depth, content, indentSize) { + return " ".repeat(indentSize * depth) + content; +} +function indentedListItem(depth, content, indentSize) { + return indentedLine(depth, LIST_ITEM_PREFIX + content, indentSize); } function encode(input, options) { - return encodeValue(normalizeValue(input), resolveOptions(options)); + return Array.from(encodeLines(input, options)).join("\n"); +} +function encodeLines(input, options) { + return encodeJsonValue(normalizeValue(input), resolveOptions(options), 0); } function resolveOptions(options) { return { @@ -84420,9 +85715,9 @@ var isomorphic2 = { // node_modules/.pnpm/@ark+util@0.56.0/node_modules/@ark/util/out/strings.js var capitalize = (s) => s[0].toUpperCase() + s.slice(1); var uncapitalize = (s) => s[0].toLowerCase() + s.slice(1); -var anchoredRegex2 = (regex3) => new RegExp(anchoredSource2(regex3), typeof regex3 === "string" ? "" : regex3.flags); -var anchoredSource2 = (regex3) => { - const source = typeof regex3 === "string" ? regex3 : regex3.source; +var anchoredRegex2 = (regex4) => new RegExp(anchoredSource2(regex4), typeof regex4 === "string" ? "" : regex4.flags); +var anchoredSource2 = (regex4) => { + const source = typeof regex4 === "string" ? regex4 : regex4.source; return `^(?:${source})$`; }; var RegexPatterns2 = { @@ -90734,9 +92029,9 @@ var parseEnclosed = (s, enclosing) => { return s.error(writeUnterminatedEnclosedMessage(enclosed, enclosing)); s.scanner.shift(); if (enclosing in enclosingRegexTokens) { - let regex3; + let regex4; try { - regex3 = new RegExp(enclosed); + regex4 = new RegExp(enclosed); } catch (e) { throwParseError2(String(e)); } @@ -90747,7 +92042,7 @@ var parseEnclosed = (s, enclosing) => { if (enclosing === "x/") { s.root = s.ctx.$.node("morph", { in: s.root, - morphs: (s2) => regex3.exec(s2), + morphs: (s2) => regex4.exec(s2), declaredOut: regexExecArray }); } @@ -91981,12 +93276,12 @@ var number = Scope.module({ }); // node_modules/.pnpm/arktype@2.1.28/node_modules/arktype/out/keywords/string.js -var regexStringNode = (regex3, description, jsonSchemaFormat) => { +var regexStringNode = (regex4, description, jsonSchemaFormat) => { const schema2 = { domain: "string", pattern: { - rule: regex3.source, - flags: regex3.flags, + rule: regex4.source, + flags: regex4.flags, meta: description } }; @@ -92856,1914 +94151,222 @@ import { pipeline } from "node:stream/promises"; // utils/github.ts var core2 = __toESM(require_core(), 1); -import { createSign } from "node:crypto"; -// utils/retry.ts -var defaultShouldRetry = (error41) => { - if (!(error41 instanceof Error)) return false; - return error41.name === "AbortError" || error41.message.includes("fetch failed") || error41.message.includes("ECONNRESET") || error41.message.includes("ETIMEDOUT"); -}; -async function retry(fn2, options = {}) { - const maxAttempts = options.maxAttempts ?? 3; - const delayMs = options.delayMs ?? 1e3; - const shouldRetry = options.shouldRetry ?? defaultShouldRetry; - const label = options.label ?? "operation"; - let lastError; - for (let attempt = 1; attempt <= maxAttempts; attempt++) { - try { - return await fn2(); - } catch (error41) { - lastError = error41; - if (attempt === maxAttempts || !shouldRetry(error41)) { - throw error41; - } - const delay2 = delayMs * attempt; - log.warning( - `\xBB ${label} failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay2}ms...` - ); - await new Promise((resolve) => setTimeout(resolve, delay2)); - } - } - throw lastError; +// node_modules/.pnpm/@octokit+plugin-throttling@11.0.3_@octokit+core@7.0.5/node_modules/@octokit/plugin-throttling/dist-bundle/index.js +var import_light = __toESM(require_light(), 1); +var VERSION = "0.0.0-development"; +var noop = () => Promise.resolve(); +function wrapRequest(state, request2, options) { + return state.retryLimiter.schedule(doRequest, state, request2, options); } - -// utils/github.ts -function isGitHubActionsEnvironment() { - return Boolean(process.env.GITHUB_ACTIONS); -} -async function acquireTokenViaOIDC() { - log.info("\xBB generating OIDC token..."); - const oidcToken = await core2.getIDToken("pullfrog-api"); - const apiUrl = process.env.API_URL || "https://pullfrog.com"; - log.info("\xBB exchanging OIDC token for installation token..."); - const timeoutMs = 3e4; - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); - try { - const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, { - method: "POST", - headers: { - Authorization: `Bearer ${oidcToken}`, - "Content-Type": "application/json" - }, - signal: controller.signal - }); - clearTimeout(timeoutId); - if (!tokenResponse.ok) { - throw new Error(`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`); - } - const tokenData = await tokenResponse.json(); - log.info(`\xBB installation token obtained for ${tokenData.repository || "all repositories"}`); - return tokenData.token; - } catch (error41) { - clearTimeout(timeoutId); - if (error41 instanceof Error && error41.name === "AbortError") { - throw new Error(`Token exchange timed out after ${timeoutMs}ms`); - } - throw error41; +async function doRequest(state, request2, options) { + const { pathname } = new URL(options.url, "http://github.test"); + const isAuth = isAuthRequest(options.method, pathname); + const isWrite = !isAuth && options.method !== "GET" && options.method !== "HEAD"; + const isSearch = options.method === "GET" && pathname.startsWith("/search/"); + const isGraphQL = pathname.startsWith("/graphql"); + const retryCount = ~~request2.retryCount; + const jobOptions = retryCount > 0 ? { priority: 0, weight: 0 } : {}; + if (state.clustering) { + jobOptions.expiration = 1e3 * 60; } -} -var base64UrlEncode = (str) => { - return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); -}; -var generateJWT = (appId, privateKey) => { - const now = Math.floor(Date.now() / 1e3); - const payload = { - iat: now - 60, - exp: now + 5 * 60, - iss: appId - }; - const header = { - alg: "RS256", - typ: "JWT" - }; - const encodedHeader = base64UrlEncode(JSON.stringify(header)); - const encodedPayload = base64UrlEncode(JSON.stringify(payload)); - const signaturePart = `${encodedHeader}.${encodedPayload}`; - const signature = createSign("RSA-SHA256").update(signaturePart).sign(privateKey, "base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); - return `${signaturePart}.${signature}`; -}; -var githubRequest = async (path4, options = {}) => { - const { method = "GET", headers = {}, body } = options; - const url2 = `https://api.github.com${path4}`; - const requestHeaders = { - Accept: "application/vnd.github.v3+json", - "User-Agent": "Pullfrog-Installation-Token-Generator/1.0", - ...headers - }; - const response = await fetch(url2, { - method, - headers: requestHeaders, - ...body && { body } - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error( - `GitHub API request failed: ${response.status} ${response.statusText} -${errorText}` - ); + if (isWrite || isGraphQL) { + await state.write.key(state.id).schedule(jobOptions, noop); } - return response.json(); -}; -var checkRepositoryAccess = async (token, repoOwner, repoName) => { - try { - const response = await githubRequest("/installation/repositories", { - headers: { Authorization: `token ${token}` } - }); - return response.repositories.some( - (repo) => repo.owner.login === repoOwner && repo.name === repoName - ); - } catch { - return false; + if (isWrite && state.triggersNotification(pathname)) { + await state.notifications.key(state.id).schedule(jobOptions, noop); } -}; -var createInstallationToken = async (jwt, installationId) => { - const response = await githubRequest( - `/app/installations/${installationId}/access_tokens`, - { - method: "POST", - headers: { Authorization: `Bearer ${jwt}` } - } - ); - return response.token; -}; -var findInstallationId = async (jwt, repoOwner, repoName) => { - const installations = await githubRequest("/app/installations", { - headers: { Authorization: `Bearer ${jwt}` } - }); - for (const installation of installations) { - try { - const tempToken = await createInstallationToken(jwt, installation.id); - const hasAccess = await checkRepositoryAccess(tempToken, repoOwner, repoName); - if (hasAccess) { - return installation.id; - } - } catch { - } + if (isSearch) { + await state.search.key(state.id).schedule(jobOptions, noop); } - throw new Error( - `No installation found with access to ${repoOwner}/${repoName}. Ensure the GitHub App is installed on the target repository.` - ); -}; -async function acquireTokenViaGitHubApp() { - const repoContext = parseRepoContext(); - const config2 = { - appId: process.env.GITHUB_APP_ID, - privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n"), - repoOwner: repoContext.owner, - repoName: repoContext.name - }; - const jwt = generateJWT(config2.appId, config2.privateKey); - const installationId = await findInstallationId(jwt, config2.repoOwner, config2.repoName); - const token = await createInstallationToken(jwt, installationId); - return token; -} -async function acquireNewToken() { - if (isGitHubActionsEnvironment()) { - return await retry(() => acquireTokenViaOIDC(), { label: "token exchange" }); - } else { - return await acquireTokenViaGitHubApp(); - } -} -var githubInstallationToken; -async function setupGitHubInstallationToken() { - const acquiredToken = await acquireNewToken(); - core2.setSecret(acquiredToken); - githubInstallationToken = acquiredToken; - return acquiredToken; -} -function getGitHubInstallationToken() { - if (!githubInstallationToken) { - throw new Error("GitHub installation token not set. Call setupGitHubInstallationToken first."); - } - return githubInstallationToken; -} -async function revokeGitHubInstallationToken() { - if (!githubInstallationToken) { - return; - } - const token = githubInstallationToken; - githubInstallationToken = void 0; - const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com"; - try { - await fetch(`${apiUrl}/installation/token`, { - method: "DELETE", - headers: { - Accept: "application/vnd.github+json", - Authorization: `Bearer ${token}`, - "X-GitHub-Api-Version": "2022-11-28" - } - }); - log.debug("\xBB installation token revoked"); - } catch (error41) { - log.warning( - `Failed to revoke installation token: ${error41 instanceof Error ? error41.message : String(error41)}` - ); - } -} -function parseRepoContext() { - const githubRepo = process.env.GITHUB_REPOSITORY; - if (!githubRepo) { - throw new Error("GITHUB_REPOSITORY environment variable is required"); - } - const [owner, name] = githubRepo.split("/"); - if (!owner || !name) { - throw new Error(`Invalid GITHUB_REPOSITORY format: ${githubRepo}. Expected 'owner/repo'`); - } - return { owner, name }; -} - -// agents/shared.ts -function createAgentEnv(agentSpecificVars) { - const home = agentSpecificVars.HOME || process.env.HOME; - return { - PATH: process.env.PATH, - HOME: home, - // XDG_CONFIG_HOME must match HOME to ensure CLI tools find config files in the right place. - // GitHub Actions sets XDG_CONFIG_HOME to /home/runner/.config which would override $HOME/.config lookup. - XDG_CONFIG_HOME: home ? join4(home, ".config") : void 0, - LOG_LEVEL: process.env.LOG_LEVEL, - NODE_ENV: process.env.NODE_ENV, - GITHUB_TOKEN: getGitHubInstallationToken(), - ...agentSpecificVars - // values could be undefined but will be ignored - }; -} -function setupProcessAgentEnv(agentSpecificVars) { - Object.assign(process.env, createAgentEnv(agentSpecificVars)); -} -async function installFromNpmTarball({ - packageName, - version: version2, - executablePath, - installDependencies -}) { - let resolvedVersion = version2; - if (version2.startsWith("^") || version2.startsWith("~") || version2 === "latest") { - const npmRegistry2 = process.env.NPM_REGISTRY || "https://registry.npmjs.org"; - log.debug(`\xBB resolving version for ${version2}...`); - try { - const registryResponse = await fetch(`${npmRegistry2}/${packageName}`); - if (!registryResponse.ok) { - throw new Error(`Failed to query registry: ${registryResponse.status}`); - } - const registryData = await registryResponse.json(); - resolvedVersion = registryData["dist-tags"].latest; - log.debug(`\xBB resolved to version ${resolvedVersion}`); - } catch (error41) { - log.warning( - `Failed to resolve version from registry: ${error41 instanceof Error ? error41.message : String(error41)}` - ); + const req = (isAuth ? state.auth : state.global).key(state.id).schedule(jobOptions, request2, options); + if (isGraphQL) { + const res = await req; + if (res.data.errors != null && res.data.errors.some((error41) => error41.type === "RATE_LIMITED")) { + const error41 = Object.assign(new Error("GraphQL Rate Limit Exceeded"), { + response: res, + data: res.data + }); throw error41; } } - log.debug(`\xBB installing ${packageName}@${resolvedVersion}...`); - const tempDir = process.env.PULLFROG_TEMP_DIR; - const tarballPath = join4(tempDir, "package.tgz"); - const npmRegistry = process.env.NPM_REGISTRY || "https://registry.npmjs.org"; - let tarballUrl; - if (packageName.startsWith("@")) { - const [scope2, name] = packageName.slice(1).split("/"); - const scopedPackageName = `@${scope2}%2F${name}`; - tarballUrl = `${npmRegistry}/${scopedPackageName}/-/${name}-${resolvedVersion}.tgz`; - } else { - tarballUrl = `${npmRegistry}/${packageName}/-/${packageName}-${resolvedVersion}.tgz`; - } - log.debug(`\xBB downloading from ${tarballUrl}...`); - const response = await fetch(tarballUrl); - if (!response.ok) { - throw new Error(`Failed to download tarball: ${response.status} ${response.statusText}`); - } - if (!response.body) throw new Error("Response body is null"); - const fileStream = createWriteStream2(tarballPath); - await pipeline(response.body, fileStream); - log.debug(`\xBB downloaded tarball to ${tarballPath}`); - log.debug(`\xBB extracting tarball...`); - const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C", tempDir], { - stdio: "pipe", - encoding: "utf-8" + return req; +} +function isAuthRequest(method, pathname) { + return method === "PATCH" && // https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-a-scoped-access-token + /^\/applications\/[^/]+\/token\/scoped$/.test(pathname) || method === "POST" && // https://docs.github.com/en/rest/apps/oauth-applications?apiVersion=2022-11-28#reset-a-token + (/^\/applications\/[^/]+\/token$/.test(pathname) || // https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app + /^\/app\/installations\/[^/]+\/access_tokens$/.test(pathname) || // https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps + pathname === "/login/oauth/access_token"); +} +var triggers_notification_paths_default = [ + "/orgs/{org}/invitations", + "/orgs/{org}/invitations/{invitation_id}", + "/orgs/{org}/teams/{team_slug}/discussions", + "/orgs/{org}/teams/{team_slug}/discussions/{discussion_number}/comments", + "/repos/{owner}/{repo}/collaborators/{username}", + "/repos/{owner}/{repo}/commits/{commit_sha}/comments", + "/repos/{owner}/{repo}/issues", + "/repos/{owner}/{repo}/issues/{issue_number}/comments", + "/repos/{owner}/{repo}/issues/{issue_number}/sub_issue", + "/repos/{owner}/{repo}/issues/{issue_number}/sub_issues/priority", + "/repos/{owner}/{repo}/pulls", + "/repos/{owner}/{repo}/pulls/{pull_number}/comments", + "/repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies", + "/repos/{owner}/{repo}/pulls/{pull_number}/merge", + "/repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers", + "/repos/{owner}/{repo}/pulls/{pull_number}/reviews", + "/repos/{owner}/{repo}/releases", + "/teams/{team_id}/discussions", + "/teams/{team_id}/discussions/{discussion_number}/comments" +]; +function routeMatcher(paths) { + const regexes = paths.map( + (path4) => path4.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/") + ); + const regex22 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`; + return new RegExp(regex22, "i"); +} +var regex3 = routeMatcher(triggers_notification_paths_default); +var triggersNotification = regex3.test.bind(regex3); +var groups = {}; +var createGroups = function(Bottleneck, common) { + groups.global = new Bottleneck.Group({ + id: "octokit-global", + maxConcurrent: 10, + ...common }); - if (extractResult.status !== 0) { - throw new Error( - `Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}` - ); + groups.auth = new Bottleneck.Group({ + id: "octokit-auth", + maxConcurrent: 1, + ...common + }); + groups.search = new Bottleneck.Group({ + id: "octokit-search", + maxConcurrent: 1, + minTime: 2e3, + ...common + }); + groups.write = new Bottleneck.Group({ + id: "octokit-write", + maxConcurrent: 1, + minTime: 1e3, + ...common + }); + groups.notifications = new Bottleneck.Group({ + id: "octokit-notifications", + maxConcurrent: 1, + minTime: 3e3, + ...common + }); +}; +function throttling(octokit, octokitOptions) { + const { + enabled = true, + Bottleneck = import_light.default, + id = "no-id", + timeout = 1e3 * 60 * 2, + // Redis TTL: 2 minutes + connection + } = octokitOptions.throttle || {}; + if (!enabled) { + return {}; } - const extractedDir = join4(tempDir, "package"); - const cliPath = join4(extractedDir, executablePath); - if (!existsSync2(cliPath)) { - throw new Error(`Executable not found in extracted package at ${cliPath}`); + const common = { timeout }; + if (typeof connection !== "undefined") { + common.connection = connection; } - if (installDependencies) { - log.debug(`\xBB installing dependencies for ${packageName}...`); - const installResult = spawnSync("npm", ["install", "--production"], { - cwd: extractedDir, - stdio: "pipe", - encoding: "utf-8" - }); - if (installResult.status !== 0) { - throw new Error( - `Failed to install dependencies: ${installResult.stderr || installResult.stdout || "Unknown error"}` - ); - } - log.debug(`\xBB dependencies installed`); + if (groups.global == null) { + createGroups(Bottleneck, common); } - chmodSync(cliPath, 493); - log.debug(`\xBB ${packageName} installed at ${cliPath}`); - return cliPath; -} -async function fetchWithRetry(url2, headers, errorMessage) { - const response = await fetch(url2, { headers }); - if (!response.ok) { - const retryAfter = response.headers.get("Retry-After") || response.headers.get("retry-after"); - if (retryAfter) { - const waitSeconds = parseInt(retryAfter, 10); - if (!Number.isNaN(waitSeconds) && waitSeconds > 0) { - log.info(`Rate limited, waiting ${waitSeconds} seconds before retry...`); - await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1e3)); - const retryResponse = await fetch(url2, { headers }); - if (!retryResponse.ok) { - throw new Error( - `${errorMessage}: ${retryResponse.status} ${retryResponse.statusText} (retry failed)` - ); - } - return retryResponse; - } - } - throw new Error(`${errorMessage}: ${response.status} ${response.statusText}`); - } - return response; -} -async function installFromGithub({ - owner, - repo, - assetName, - executablePath, - githubInstallationToken: githubInstallationToken2 -}) { - log.info(`\u{1F4E6} Installing ${owner}/${repo} from GitHub releases...`); - const releaseUrl = `https://api.github.com/repos/${owner}/${repo}/releases/latest`; - log.info(`Fetching release from ${releaseUrl}...`); - const headers = {}; - if (githubInstallationToken2) { - headers.Authorization = `Bearer ${githubInstallationToken2}`; - } - const releaseResponse = await fetchWithRetry(releaseUrl, headers, "Failed to fetch release"); - const releaseData = await releaseResponse.json(); - log.info(`Found release: ${releaseData.tag_name}`); - const asset = releaseData.assets.find((a) => a.name === assetName); - if (!asset) { - throw new Error(`Asset '${assetName}' not found in release ${releaseData.tag_name}`); - } - const assetUrl = asset.browser_download_url; - log.info(`Downloading asset from ${assetUrl}...`); - const tempDirPrefix = `${owner}-${repo}-github-`; - const tempDir = await mkdtemp(join4(tmpdir(), tempDirPrefix)); - const urlPath = new URL(assetUrl).pathname; - const fileName3 = urlPath.split("/").pop() || "asset"; - const downloadPath = join4(tempDir, fileName3); - const assetResponse = await fetchWithRetry(assetUrl, headers, "Failed to download asset"); - if (!assetResponse.body) throw new Error("Response body is null"); - const fileStream = createWriteStream2(downloadPath); - await pipeline(assetResponse.body, fileStream); - log.info(`Downloaded asset to ${downloadPath}`); - let cliPath; - if (executablePath) { - cliPath = join4(tempDir, executablePath); - } else { - cliPath = downloadPath; - } - if (!existsSync2(cliPath)) { - throw new Error(`Executable not found at ${cliPath}`); - } - chmodSync(cliPath, 493); - log.info(`\u2713 Installed from GitHub release at ${cliPath}`); - return cliPath; -} -async function installFromCurl({ - installUrl, - executableName -}) { - log.info(`\u{1F4E6} Installing ${executableName}...`); - const tempDir = process.env.PULLFROG_TEMP_DIR; - const installScriptPath = join4(tempDir, "install.sh"); - log.info(`Downloading install script from ${installUrl}...`); - const installScriptResponse = await fetch(installUrl); - if (!installScriptResponse.ok) { - throw new Error(`Failed to download install script: ${installScriptResponse.status}`); - } - if (!installScriptResponse.body) throw new Error("Response body is null"); - const fileStream = createWriteStream2(installScriptPath); - await pipeline(installScriptResponse.body, fileStream); - log.info(`Downloaded install script to ${installScriptPath}`); - chmodSync(installScriptPath, 493); - log.info(`Installing to temp directory at ${tempDir}...`); - const installResult = spawnSync("bash", [installScriptPath], { - cwd: tempDir, - env: { - // Run the install script with HOME set to temp directory - // ensuring a fresh install for each run - HOME: tempDir, - // XDG_CONFIG_HOME must match HOME so CLI tools find config in the right place - XDG_CONFIG_HOME: join4(tempDir, ".config"), - SHELL: process.env.SHELL, - USER: process.env.USER + const state = Object.assign( + { + clustering: connection != null, + triggersNotification, + fallbackSecondaryRateRetryAfter: 60, + retryAfterBaseValue: 1e3, + retryLimiter: new Bottleneck(), + id, + ...groups }, - stdio: "pipe", - encoding: "utf-8" - }); - if (installResult.status !== 0) { - const errorOutput = installResult.stderr || installResult.stdout || "No output"; - throw new Error( - `Failed to install ${executableName}. Install script exited with code ${installResult.status}. Output: ${errorOutput}` - ); - } - const cliPath = join4(tempDir, ".local", "bin", executableName); - if (!existsSync2(cliPath)) { - throw new Error(`Executable not found at ${cliPath}`); - } - chmodSync(cliPath, 493); - log.info(`\u2713 ${executableName} installed at ${cliPath}`); - return cliPath; -} -var agent = (input) => { - return { ...input, ...agentsManifest[input.name] }; -}; + octokitOptions.throttle + ); + if (typeof state.onSecondaryRateLimit !== "function" || typeof state.onRateLimit !== "function") { + throw new Error(`octokit/plugin-throttling error: + You must pass the onSecondaryRateLimit and onRateLimit error handlers. + See https://octokit.github.io/rest.js/#throttling -// agents/claude.ts -var claude = agent({ - name: "claude", - install: async () => { - const versionRange = package_default.dependencies["@anthropic-ai/claude-agent-sdk"] || "latest"; - return await installFromNpmTarball({ - packageName: "@anthropic-ai/claude-agent-sdk", - version: versionRange, - executablePath: "cli.js" - }); - }, - run: async ({ payload, mcpServers, apiKey, cliPath, repo }) => { - delete process.env.ANTHROPIC_API_KEY; - const prompt = addInstructions({ payload, repo }); - log.group("Full prompt", () => log.info(prompt)); - const sandboxOptions = payload.sandbox ? { - permissionMode: "default", - disallowedTools: ["Bash", "WebSearch", "WebFetch", "Write"], - async canUseTool(toolName, input, _options) { - if (toolName.startsWith("mcp__gh_pullfrog__")) - return { - behavior: "allow", - updatedInput: input, - updatedPermissions: [] - }; - console.error("can i use this tool?", toolName); - return { - behavior: "deny", - message: "You are not allowed to use this tool." - }; - } - } : { - permissionMode: "bypassPermissions" - }; - if (payload.sandbox) { - log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); - } - const queryInstance = query({ - prompt, - options: { - ...sandboxOptions, - mcpServers, - // model: "claude-opus-4-5", - pathToClaudeCodeExecutable: cliPath, - env: createAgentEnv({ ANTHROPIC_API_KEY: apiKey }) - } - }); - for await (const message of queryInstance) { - log.debug(JSON.stringify(message, null, 2)); - const handler2 = messageHandlers[message.type]; - await handler2(message); - } - return { - success: true, - output: "" - }; - } -}); -var bashToolIds = /* @__PURE__ */ new Set(); -var messageHandlers = { - assistant: (data) => { - if (data.message?.content) { - for (const content of data.message.content) { - if (content.type === "text" && content.text?.trim()) { - log.box(content.text.trim(), { title: "Claude" }); - } else if (content.type === "tool_use") { - if (content.name === "bash" && content.id) { - bashToolIds.add(content.id); + const octokit = new Octokit({ + throttle: { + onSecondaryRateLimit: (retryAfter, options) => {/* ... */}, + onRateLimit: (retryAfter, options) => {/* ... */} } - log.toolCall({ - toolName: content.name, - input: content.input - }); - } - } - } - }, - user: (data) => { - if (data.message?.content) { - for (const content of data.message.content) { - if (content.type === "tool_result") { - const toolUseId = content.tool_use_id; - const isBashTool = toolUseId && bashToolIds.has(toolUseId); - if (isBashTool) { - const outputContent = typeof content.content === "string" ? content.content : Array.isArray(content.content) ? content.content.map((c) => typeof c === "string" ? c : c.text || JSON.stringify(c)).join("\n") : String(content.content); - log.startGroup(`bash output`); - if (content.is_error) { - log.warning(outputContent); - } else { - log.info(outputContent); - } - log.endGroup(); - bashToolIds.delete(toolUseId); - } else if (content.is_error) { - const errorContent = typeof content.content === "string" ? content.content : String(content.content); - log.warning(`Tool error: ${errorContent}`); - } - } - } - } - }, - result: async (data) => { - if (data.subtype === "success") { - const usage = data.usage; - const inputTokens = usage?.input_tokens || 0; - const cacheRead = usage?.cache_read_input_tokens || 0; - const cacheWrite = usage?.cache_creation_input_tokens || 0; - const outputTokens = usage?.output_tokens || 0; - const totalInput = inputTokens + cacheRead + cacheWrite; - await log.summaryTable([ - [ - { data: "Cost", header: true }, - { data: "Input", header: true }, - { data: "Cache Read", header: true }, - { data: "Cache Write", header: true }, - { data: "Output", header: true } - ], - [ - `$${data.total_cost_usd?.toFixed(4) || "0.0000"}`, - String(totalInput), - String(cacheRead), - String(cacheWrite), - String(outputTokens) - ] - ]); - } else if (data.subtype === "error_max_turns") { - log.error(`Max turns reached: ${JSON.stringify(data)}`); - } else if (data.subtype === "error_during_execution") { - log.error(`Execution error: ${JSON.stringify(data)}`); - } else { - log.error(`Failed: ${JSON.stringify(data)}`); - } - }, - system: () => { - }, - stream_event: () => { - }, - tool_progress: () => { - }, - auth_status: () => { + }) + `); } -}; - -// agents/codex.ts -import { spawnSync as spawnSync2 } from "node:child_process"; -import { mkdirSync as mkdirSync2 } from "node:fs"; -import { join as join5 } from "node:path"; - -// node_modules/.pnpm/@openai+codex-sdk@0.58.0/node_modules/@openai/codex-sdk/dist/index.js -import { promises as fs2 } from "fs"; -import os from "os"; -import path from "path"; -import { spawn as spawn2 } from "child_process"; -import path2 from "path"; -import readline from "readline"; -import { fileURLToPath as fileURLToPath2 } from "url"; -async function createOutputSchemaFile(schema2) { - if (schema2 === void 0) { - return { cleanup: async () => { - } }; - } - if (!isJsonObject2(schema2)) { - throw new Error("outputSchema must be a plain JSON object"); - } - const schemaDir = await fs2.mkdtemp(path.join(os.tmpdir(), "codex-output-schema-")); - const schemaPath = path.join(schemaDir, "schema.json"); - const cleanup = async () => { - try { - await fs2.rm(schemaDir, { recursive: true, force: true }); - } catch { + const events = {}; + const emitter = new Bottleneck.Events(events); + events.on("secondary-limit", state.onSecondaryRateLimit); + events.on("rate-limit", state.onRateLimit); + events.on( + "error", + (e) => octokit.log.warn("Error in throttling-plugin limit handler", e) + ); + state.retryLimiter.on("failed", async function(error41, info2) { + const [state2, request2, options] = info2.args; + const { pathname } = new URL(options.url, "http://github.test"); + const shouldRetryGraphQL = pathname.startsWith("/graphql") && error41.status !== 401; + if (!(shouldRetryGraphQL || error41.status === 403 || error41.status === 429)) { + return; } - }; - try { - await fs2.writeFile(schemaPath, JSON.stringify(schema2), "utf8"); - return { schemaPath, cleanup }; - } catch (error41) { - await cleanup(); - throw error41; - } -} -function isJsonObject2(value2) { - return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); -} -var Thread = class { - _exec; - _options; - _id; - _threadOptions; - /** Returns the ID of the thread. Populated after the first turn starts. */ - get id() { - return this._id; - } - /* @internal */ - constructor(exec, options, threadOptions, id = null) { - this._exec = exec; - this._options = options; - this._id = id; - this._threadOptions = threadOptions; - } - /** Provides the input to the agent and streams events as they are produced during the turn. */ - async runStreamed(input, turnOptions = {}) { - return { events: this.runStreamedInternal(input, turnOptions) }; - } - async *runStreamedInternal(input, turnOptions = {}) { - const { schemaPath, cleanup } = await createOutputSchemaFile(turnOptions.outputSchema); - const options = this._threadOptions; - const { prompt, images } = normalizeInput(input); - const generator = this._exec.run({ - input: prompt, - baseUrl: this._options.baseUrl, - apiKey: this._options.apiKey, - threadId: this._id, - images, - model: options?.model, - sandboxMode: options?.sandboxMode, - workingDirectory: options?.workingDirectory, - skipGitRepoCheck: options?.skipGitRepoCheck, - outputSchemaFile: schemaPath, - modelReasoningEffort: options?.modelReasoningEffort, - networkAccessEnabled: options?.networkAccessEnabled, - webSearchEnabled: options?.webSearchEnabled, - approvalPolicy: options?.approvalPolicy - }); - try { - for await (const item of generator) { - let parsed2; - try { - parsed2 = JSON.parse(item); - } catch (error41) { - throw new Error(`Failed to parse item: ${item}`, { cause: error41 }); - } - if (parsed2.type === "thread.started") { - this._id = parsed2.thread_id; - } - yield parsed2; - } - } finally { - await cleanup(); - } - } - /** Provides the input to the agent and returns the completed turn. */ - async run(input, turnOptions = {}) { - const generator = this.runStreamedInternal(input, turnOptions); - const items = []; - let finalResponse = ""; - let usage = null; - let turnFailure = null; - for await (const event of generator) { - if (event.type === "item.completed") { - if (event.item.type === "agent_message") { - finalResponse = event.item.text; - } - items.push(event.item); - } else if (event.type === "turn.completed") { - usage = event.usage; - } else if (event.type === "turn.failed") { - turnFailure = event.error; - break; - } - } - if (turnFailure) { - throw new Error(turnFailure.message); - } - return { items, finalResponse, usage }; - } -}; -function normalizeInput(input) { - if (typeof input === "string") { - return { prompt: input, images: [] }; - } - const promptParts = []; - const images = []; - for (const item of input) { - if (item.type === "text") { - promptParts.push(item.text); - } else if (item.type === "local_image") { - images.push(item.path); - } - } - return { prompt: promptParts.join("\n\n"), images }; -} -var INTERNAL_ORIGINATOR_ENV = "CODEX_INTERNAL_ORIGINATOR_OVERRIDE"; -var TYPESCRIPT_SDK_ORIGINATOR = "codex_sdk_ts"; -var CodexExec = class { - executablePath; - constructor(executablePath = null) { - this.executablePath = executablePath || findCodexPath(); - } - async *run(args3) { - const commandArgs = ["exec", "--experimental-json"]; - if (args3.model) { - commandArgs.push("--model", args3.model); - } - if (args3.sandboxMode) { - commandArgs.push("--sandbox", args3.sandboxMode); - } - if (args3.workingDirectory) { - commandArgs.push("--cd", args3.workingDirectory); - } - if (args3.skipGitRepoCheck) { - commandArgs.push("--skip-git-repo-check"); - } - if (args3.outputSchemaFile) { - commandArgs.push("--output-schema", args3.outputSchemaFile); - } - if (args3.modelReasoningEffort) { - commandArgs.push("--config", `model_reasoning_effort="${args3.modelReasoningEffort}"`); - } - if (args3.networkAccessEnabled !== void 0) { - commandArgs.push("--config", `sandbox_workspace_write.network_access=${args3.networkAccessEnabled}`); - } - if (args3.webSearchEnabled !== void 0) { - commandArgs.push("--config", `features.web_search_request=${args3.webSearchEnabled}`); - } - if (args3.approvalPolicy) { - commandArgs.push("--config", `approval_policy="${args3.approvalPolicy}"`); - } - if (args3.images?.length) { - for (const image of args3.images) { - commandArgs.push("--image", image); - } - } - if (args3.threadId) { - commandArgs.push("resume", args3.threadId); - } - const env3 = { - ...process.env - }; - if (!env3[INTERNAL_ORIGINATOR_ENV]) { - env3[INTERNAL_ORIGINATOR_ENV] = TYPESCRIPT_SDK_ORIGINATOR; - } - if (args3.baseUrl) { - env3.OPENAI_BASE_URL = args3.baseUrl; - } - if (args3.apiKey) { - env3.CODEX_API_KEY = args3.apiKey; - } - const child = spawn2(this.executablePath, commandArgs, { - env: env3 - }); - let spawnError = null; - child.once("error", (err) => spawnError = err); - if (!child.stdin) { - child.kill(); - throw new Error("Child process has no stdin"); - } - child.stdin.write(args3.input); - child.stdin.end(); - if (!child.stdout) { - child.kill(); - throw new Error("Child process has no stdout"); - } - const stderrChunks = []; - if (child.stderr) { - child.stderr.on("data", (data) => { - stderrChunks.push(data); - }); - } - const rl = readline.createInterface({ - input: child.stdout, - crlfDelay: Infinity - }); - try { - for await (const line of rl) { - yield line; - } - const exitCode = new Promise((resolve, reject) => { - child.once("exit", (code) => { - if (code === 0) { - resolve(code); - } else { - const stderrBuffer = Buffer.concat(stderrChunks); - reject( - new Error(`Codex Exec exited with code ${code}: ${stderrBuffer.toString("utf8")}`) - ); - } - }); - }); - if (spawnError) throw spawnError; - await exitCode; - } finally { - rl.close(); - child.removeAllListeners(); - try { - if (!child.killed) child.kill(); - } catch { - } - } - } -}; -var scriptFileName = fileURLToPath2(import.meta.url); -var scriptDirName = path2.dirname(scriptFileName); -function findCodexPath() { - const { platform, arch } = process; - let targetTriple = null; - switch (platform) { - case "linux": - case "android": - switch (arch) { - case "x64": - targetTriple = "x86_64-unknown-linux-musl"; - break; - case "arm64": - targetTriple = "aarch64-unknown-linux-musl"; - break; - default: - break; - } - break; - case "darwin": - switch (arch) { - case "x64": - targetTriple = "x86_64-apple-darwin"; - break; - case "arm64": - targetTriple = "aarch64-apple-darwin"; - break; - default: - break; - } - break; - case "win32": - switch (arch) { - case "x64": - targetTriple = "x86_64-pc-windows-msvc"; - break; - case "arm64": - targetTriple = "aarch64-pc-windows-msvc"; - break; - default: - break; - } - break; - default: - break; - } - if (!targetTriple) { - throw new Error(`Unsupported platform: ${platform} (${arch})`); - } - const vendorRoot = path2.join(scriptDirName, "..", "vendor"); - const archRoot = path2.join(vendorRoot, targetTriple); - const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex"; - const binaryPath = path2.join(archRoot, "codex", codexBinaryName); - return binaryPath; -} -var Codex = class { - exec; - options; - constructor(options = {}) { - this.exec = new CodexExec(options.codexPathOverride); - this.options = options; - } - /** - * Starts a new conversation with an agent. - * @returns A new thread instance. - */ - startThread(options = {}) { - return new Thread(this.exec, this.options, options); - } - /** - * Resumes a conversation with an agent based on the thread id. - * Threads are persisted in ~/.codex/sessions. - * - * @param id The id of the thread to resume. - * @returns A new thread instance. - */ - resumeThread(id, options = {}) { - return new Thread(this.exec, this.options, options, id); - } -}; - -// agents/codex.ts -var codex = agent({ - name: "codex", - install: async () => { - return await installFromNpmTarball({ - packageName: "@openai/codex", - version: "latest", - executablePath: "bin/codex.js" - }); - }, - run: async ({ payload, mcpServers, apiKey, cliPath, repo }) => { - const tempHome = process.env.PULLFROG_TEMP_DIR; - const configDir = join5(tempHome, ".config", "codex"); - mkdirSync2(configDir, { recursive: true }); - setupProcessAgentEnv({ - OPENAI_API_KEY: apiKey, - HOME: tempHome - }); - configureCodexMcpServers({ mcpServers, cliPath }); - const codexOptions = { - apiKey, - codexPathOverride: cliPath - }; - if (payload.sandbox) { - log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); - } - const codex2 = new Codex(codexOptions); - const thread = codex2.startThread( - payload.sandbox ? { - approvalPolicy: "never", - sandboxMode: "read-only", - networkAccessEnabled: false - } : { - approvalPolicy: "never", - // use danger-full-access to allow git operations (workspace-write blocks .git directory writes) - sandboxMode: "danger-full-access", - networkAccessEnabled: true - } - ); - try { - const streamedTurn = await thread.runStreamed(addInstructions({ payload, repo })); - let finalOutput2 = ""; - for await (const event of streamedTurn.events) { - const handler2 = messageHandlers2[event.type]; - log.debug(JSON.stringify(event, null, 2)); - if (handler2) { - handler2(event); - } - if (event.type === "item.completed" && event.item.type === "agent_message") { - finalOutput2 = event.item.text; - } - } - return { - success: true, - output: finalOutput2 - }; - } catch (error41) { - const errorMessage = error41 instanceof Error ? error41.message : String(error41); - log.error(`Codex execution failed: ${errorMessage}`); - return { - success: false, - error: errorMessage, - output: "" - }; - } - } -}); -var commandExecutionIds = /* @__PURE__ */ new Set(); -var messageHandlers2 = { - "thread.started": () => { - }, - "turn.started": () => { - }, - "turn.completed": async (event) => { - await log.summaryTable([ - [ - { data: "Input Tokens", header: true }, - { data: "Cached Input Tokens", header: true }, - { data: "Output Tokens", header: true } - ], - [ - String(event.usage.input_tokens || 0), - String(event.usage.cached_input_tokens || 0), - String(event.usage.output_tokens || 0) - ] - ]); - }, - "turn.failed": (event) => { - log.error(`Turn failed: ${event.error.message}`); - }, - "item.started": (event) => { - const item = event.item; - if (item.type === "command_execution") { - commandExecutionIds.add(item.id); - log.toolCall({ - toolName: item.command, - input: item.args || {} - }); - } else if (item.type === "agent_message") { - } else if (item.type === "mcp_tool_call") { - log.toolCall({ - toolName: item.tool, - input: { - server: item.server, - ...item.arguments || {} - } - }); - } - }, - "item.updated": (event) => { - const item = event.item; - if (item.type === "command_execution") { - if (item.status === "in_progress" && item.aggregated_output) { - } - } - }, - "item.completed": (event) => { - const item = event.item; - if (item.type === "agent_message") { - log.box(item.text.trim(), { title: "Codex" }); - } else if (item.type === "command_execution") { - const isTracked = commandExecutionIds.has(item.id); - if (isTracked) { - log.startGroup(`bash output`); - if (item.status === "failed" || item.exit_code !== void 0 && item.exit_code !== 0) { - log.warning(item.aggregated_output || "Command failed"); - } else { - log.info(item.aggregated_output || ""); - } - log.endGroup(); - commandExecutionIds.delete(item.id); - } - } else if (item.type === "mcp_tool_call") { - if (item.status === "failed" && item.error) { - log.warning(`MCP tool call failed: ${item.error.message}`); - } - } else if (item.type === "reasoning") { - const reasoningText = item.text.trim(); - const cleanText = reasoningText.replace(/\*\*/g, ""); - log.box(cleanText, { title: "Codex" }); - } - }, - error: (event) => { - log.error(`Error: ${event.message}`); - } -}; -function configureCodexMcpServers({ mcpServers, cliPath }) { - for (const [serverName, serverConfig] of Object.entries(mcpServers)) { - if (serverConfig.type === "http") { - const addArgs = ["mcp", "add", serverName, "--url", serverConfig.url]; - log.info(`Adding MCP server '${serverName}' at ${serverConfig.url}...`); - const addResult = spawnSync2("node", [cliPath, ...addArgs], { - stdio: "pipe", - encoding: "utf-8" - }); - if (addResult.status !== 0) { - throw new Error( - `codex mcp add failed: ${addResult.stderr || addResult.stdout || "Unknown error"}` + const retryCount = ~~request2.retryCount; + request2.retryCount = retryCount; + options.request.retryCount = retryCount; + const { wantRetry, retryAfter = 0 } = await (async function() { + if (/\bsecondary rate\b/i.test(error41.message)) { + const retryAfter2 = Number(error41.response.headers["retry-after"]) || state2.fallbackSecondaryRateRetryAfter; + const wantRetry2 = await emitter.trigger( + "secondary-limit", + retryAfter2, + options, + octokit, + retryCount ); + return { wantRetry: wantRetry2, retryAfter: retryAfter2 }; } - log.info(`\u2713 MCP server '${serverName}' configured`); - } else { - throw new Error( - `Unsupported MCP server type for Codex: ${serverConfig.type || "unknown"}` - ); - } - } -} - -// agents/cursor.ts -import { spawn as spawn3 } from "node:child_process"; -import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "node:fs"; -import { homedir as homedir2 } from "node:os"; -import { join as join6 } from "node:path"; -var cursor = agent({ - name: "cursor", - install: async () => { - return await installFromCurl({ - installUrl: "https://cursor.com/install", - executableName: "cursor-agent" - }); - }, - run: async ({ payload, apiKey, cliPath, mcpServers, repo }) => { - configureCursorMcpServers({ mcpServers, cliPath }); - configureCursorSandbox({ sandbox: payload.sandbox ?? false }); - const loggedModelCallIds = /* @__PURE__ */ new Set(); - const messageHandlers5 = { - system: (_event) => { - }, - user: (_event) => { - }, - thinking: (_event) => { - }, - assistant: (event) => { - const text = event.message?.content?.[0]?.text?.trim(); - if (!text) return; - if (event.model_call_id) { - if (!loggedModelCallIds.has(event.model_call_id)) { - loggedModelCallIds.add(event.model_call_id); - log.box(text, { title: "Cursor" }); - } - } else { - log.box(text, { title: "Cursor" }); - } - }, - tool_call: (event) => { - if (event.subtype === "started") { - const mcpToolCall = event.tool_call?.mcpToolCall; - const builtinToolCall = event.tool_call?.builtinToolCall; - if (mcpToolCall?.args?.toolName && mcpToolCall?.args?.args) { - log.toolCall({ - toolName: mcpToolCall.args.toolName, - input: mcpToolCall.args.args - }); - } else if (builtinToolCall?.args?.name && builtinToolCall?.args?.args) { - log.toolCall({ - toolName: builtinToolCall.args.name, - input: builtinToolCall.args.args - }); - } - } else if (event.subtype === "completed") { - const isError = event.tool_call?.mcpToolCall?.result?.success?.isError; - if (isError) { - log.warning("Tool call failed"); - } - } - }, - result: async (event) => { - if (event.subtype === "success" && event.duration_ms) { - const durationSec = (event.duration_ms / 1e3).toFixed(1); - log.debug(`Cursor completed in ${durationSec}s`); - } + if (error41.response.headers != null && error41.response.headers["x-ratelimit-remaining"] === "0" || (error41.response.data?.errors ?? []).some( + (error210) => error210.type === "RATE_LIMITED" + )) { + const rateLimitReset = new Date( + ~~error41.response.headers["x-ratelimit-reset"] * 1e3 + ).getTime(); + const retryAfter2 = Math.max( + // Add one second so we retry _after_ the reset time + // https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#exceeding-the-rate-limit + Math.ceil((rateLimitReset - Date.now()) / 1e3) + 1, + 0 + ); + const wantRetry2 = await emitter.trigger( + "rate-limit", + retryAfter2, + options, + octokit, + retryCount + ); + return { wantRetry: wantRetry2, retryAfter: retryAfter2 }; } - }; - try { - const fullPrompt = addInstructions({ payload, repo }); - log.group("Full prompt", () => log.info(fullPrompt)); - const cursorArgs = payload.sandbox ? [ - "--print", - fullPrompt, - "--output-format", - "stream-json", - "--approve-mcps" - // --force removed in sandbox mode to enforce safety checks - ] : ["--print", fullPrompt, "--output-format", "stream-json", "--approve-mcps", "--force"]; - if (payload.sandbox) { - log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); - } - log.info("Running Cursor CLI..."); - const startTime = Date.now(); - return new Promise((resolve) => { - const child = spawn3(cliPath, cursorArgs, { - cwd: process.cwd(), - env: createAgentEnv({ - CURSOR_API_KEY: apiKey - }), - stdio: ["ignore", "pipe", "pipe"] - // Ignore stdin, pipe stdout/stderr - }); - let stdout = ""; - let stderr = ""; - child.on("spawn", () => { - log.debug("Cursor CLI process spawned"); - }); - child.stdout?.on("data", async (data) => { - const text = data.toString(); - stdout += text; - try { - const event = JSON.parse(text); - log.debug(JSON.stringify(event, null, 2)); - if (event.type === "thinking" && event.subtype === "delta" && !event.text) { - return; - } - const handler2 = messageHandlers5[event.type]; - if (handler2) { - await handler2(event); - } - } catch { - } - }); - child.stderr?.on("data", (data) => { - const text = data.toString(); - stderr += text; - process.stderr.write(text); - log.warning(text); - }); - child.on("close", async (code, signal) => { - if (signal) { - log.warning(`Cursor CLI terminated by signal: ${signal}`); - } - const duration2 = ((Date.now() - startTime) / 1e3).toFixed(1); - if (code === 0) { - log.success(`Cursor CLI completed successfully in ${duration2}s`); - resolve({ - success: true, - output: stdout.trim() - }); - } else { - const errorMessage = stderr || `Cursor CLI exited with code ${code}`; - log.error(`Cursor CLI failed after ${duration2}s: ${errorMessage}`); - resolve({ - success: false, - error: errorMessage, - output: stdout.trim() - }); - } - }); - child.on("error", (error41) => { - const duration2 = ((Date.now() - startTime) / 1e3).toFixed(1); - const errorMessage = error41.message || String(error41); - log.error(`Cursor CLI execution failed after ${duration2}s: ${errorMessage}`); - resolve({ - success: false, - error: errorMessage, - output: stdout.trim() - }); - }); - }); - } catch (error41) { - const errorMessage = error41 instanceof Error ? error41.message : String(error41); - log.error(`Cursor execution failed: ${errorMessage}`); - return { - success: false, - error: errorMessage, - output: "" - }; - } - } -}); -function configureCursorMcpServers({ mcpServers }) { - const realHome = homedir2(); - const cursorConfigDir = join6(realHome, ".cursor"); - const mcpConfigPath = join6(cursorConfigDir, "mcp.json"); - mkdirSync3(cursorConfigDir, { recursive: true }); - const cursorMcpServers = {}; - for (const [serverName, serverConfig] of Object.entries(mcpServers)) { - if (serverConfig.type !== "http") { - throw new Error( - `Unsupported MCP server type for Cursor: ${serverConfig.type || "unknown"}` - ); - } - cursorMcpServers[serverName] = { - type: "http", - url: serverConfig.url - }; - } - writeFileSync2(mcpConfigPath, JSON.stringify({ mcpServers: cursorMcpServers }, null, 2), "utf-8"); - log.info(`\xBB MCP config written to ${mcpConfigPath}`); -} -function configureCursorSandbox({ sandbox }) { - const realHome = homedir2(); - const cursorConfigDir = join6(realHome, ".cursor"); - const cliConfigPath = join6(cursorConfigDir, "cli-config.json"); - mkdirSync3(cursorConfigDir, { recursive: true }); - const config2 = sandbox ? { - // sandbox mode: deny all writes and shell commands - permissions: { - allow: [ - "Read(**)" - // allow reading all files - ], - deny: [ - "Write(**)", - // deny all file writes - "Shell(**)" - // deny all shell commands - ] - } - } : { - // normal mode: allow everything - permissions: { - allow: ["Read(**)", "Write(**)", "Shell(**)"], - deny: [] - } - }; - writeFileSync2(cliConfigPath, JSON.stringify(config2, null, 2), "utf-8"); - log.info(`\xBB CLI config written to ${cliConfigPath} (sandbox: ${sandbox})`); -} - -// agents/gemini.ts -import { mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs"; -import { homedir as homedir3 } from "node:os"; -import { join as join7 } from "node:path"; - -// utils/subprocess.ts -import { spawn as nodeSpawn } from "node:child_process"; -async function spawn4(options) { - const { cmd, args: args3, env: env3, input, timeout, cwd: cwd2, stdio, onStdout, onStderr } = options; - const startTime = Date.now(); - let stdoutBuffer = ""; - let stderrBuffer = ""; - return new Promise((resolve, reject) => { - const child = nodeSpawn(cmd, args3, { - env: env3 || { - PATH: process.env.PATH || "", - HOME: process.env.HOME || "" - }, - stdio: stdio || ["pipe", "pipe", "pipe"], - cwd: cwd2 || process.cwd() - }); - let timeoutId; - let isTimedOut = false; - if (timeout) { - timeoutId = setTimeout(() => { - isTimedOut = true; - child.kill("SIGTERM"); - setTimeout(() => { - if (!child.killed) { - child.kill("SIGKILL"); - } - }, 5e3); - }, timeout); - } - if (child.stdout) { - child.stdout.on("data", (data) => { - const chunk = data.toString(); - stdoutBuffer += chunk; - onStdout?.(chunk); - }); - } - if (child.stderr) { - child.stderr.on("data", (data) => { - const chunk = data.toString(); - stderrBuffer += chunk; - onStderr?.(chunk); - }); - } - child.on("close", (exitCode) => { - const durationMs = Date.now() - startTime; - if (timeoutId) { - clearTimeout(timeoutId); - } - if (isTimedOut) { - reject(new Error(`Process timed out after ${timeout}ms`)); - return; - } - resolve({ - stdout: stdoutBuffer, - stderr: stderrBuffer, - exitCode: exitCode || 0, - durationMs - }); - }); - child.on("error", (error41) => { - const durationMs = Date.now() - startTime; - if (timeoutId) { - clearTimeout(timeoutId); - } - console.error(`[spawn] Process spawn error: ${error41.message}`); - resolve({ - stdout: stdoutBuffer, - stderr: stderrBuffer, - exitCode: 1, - durationMs - }); - }); - if (input && child.stdin && stdio?.[0] !== "ignore") { - child.stdin.write(input); - child.stdin.end(); + return {}; + })(); + if (wantRetry) { + request2.retryCount++; + return retryAfter * state2.retryAfterBaseValue; } }); + octokit.hook.wrap("request", wrapRequest.bind(null, state)); + return {}; } - -// agents/gemini.ts -var assistantMessageBuffer = ""; -var messageHandlers3 = { - init: (_event) => { - log.debug(JSON.stringify(_event, null, 2)); - assistantMessageBuffer = ""; - }, - message: (event) => { - log.debug(JSON.stringify(event, null, 2)); - if (event.role === "assistant" && event.content?.trim()) { - if (event.delta) { - assistantMessageBuffer += event.content; - } else { - const message = event.content.trim(); - if (message) { - log.box(message, { title: "Gemini" }); - } - assistantMessageBuffer = ""; - } - } else if (event.role === "assistant" && !event.delta && assistantMessageBuffer.trim()) { - log.box(assistantMessageBuffer.trim(), { title: "Gemini" }); - assistantMessageBuffer = ""; - } - }, - tool_use: (event) => { - log.debug(JSON.stringify(event, null, 2)); - if (event.tool_name) { - log.toolCall({ - toolName: event.tool_name, - input: event.parameters || {} - }); - } - }, - tool_result: (event) => { - log.debug(JSON.stringify(event, null, 2)); - if (event.status === "error") { - const errorMsg = typeof event.output === "string" ? event.output : JSON.stringify(event.output); - log.warning(`Tool call failed: ${errorMsg}`); - } - }, - result: async (event) => { - log.debug(JSON.stringify(event, null, 2)); - if (assistantMessageBuffer.trim()) { - log.box(assistantMessageBuffer.trim(), { title: "Gemini" }); - assistantMessageBuffer = ""; - } - if (event.status === "success" && event.stats) { - const stats = event.stats; - const rows = [ - [ - { data: "Input Tokens", header: true }, - { data: "Output Tokens", header: true }, - { data: "Total Tokens", header: true }, - { data: "Tool Calls", header: true }, - { data: "Duration (ms)", header: true } - ], - [ - String(stats.input_tokens || 0), - String(stats.output_tokens || 0), - String(stats.total_tokens || 0), - String(stats.tool_calls || 0), - String(stats.duration_ms || 0) - ] - ]; - await log.summaryTable(rows); - } else if (event.status === "error") { - log.error(`Gemini CLI failed: ${JSON.stringify(event)}`); - } - } -}; -var gemini = agent({ - name: "gemini", - install: async (githubInstallationToken2) => { - return await installFromGithub({ - owner: "google-gemini", - repo: "gemini-cli", - assetName: "gemini.js", - ...githubInstallationToken2 && { githubInstallationToken: githubInstallationToken2 } - }); - }, - run: async ({ payload, apiKey, mcpServers, cliPath, repo }) => { - configureGeminiMcpServers({ mcpServers, cliPath }); - if (!apiKey) { - throw new Error("google_api_key or gemini_api_key is required for gemini agent"); - } - const sessionPrompt = addInstructions({ payload, repo }); - log.group("Full prompt", () => log.info(sessionPrompt)); - const args3 = payload.sandbox ? [ - "--allowed-tools", - "read_file,list_directory,search_file_content,glob,save_memory,write_todos", - "--allowed-mcp-server-names", - "gh_pullfrog", - "--output-format=stream-json", - "-p", - sessionPrompt - ] : ["--yolo", "--output-format=stream-json", "-p", sessionPrompt]; - if (payload.sandbox) { - log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); - } - let finalOutput2 = ""; - let stdoutBuffer = ""; - try { - const result = await spawn4({ - cmd: "node", - args: [cliPath, ...args3], - env: createAgentEnv({ - GEMINI_API_KEY: apiKey - }), - onStdout: async (chunk) => { - const text = chunk.toString(); - finalOutput2 += text; - stdoutBuffer += text; - const lines = stdoutBuffer.split("\n"); - stdoutBuffer = lines.pop() || ""; - for (const line of lines) { - const trimmed = line.trim(); - if (!trimmed) continue; - log.debug(`[gemini stdout] ${trimmed}`); - try { - const event = JSON.parse(trimmed); - const handler2 = messageHandlers3[event.type]; - if (handler2) { - await handler2(event); - } - } catch { - log.debug(`[gemini] non-JSON stdout line: ${trimmed.substring(0, 200)}`); - } - } - }, - onStderr: (chunk) => { - const trimmed = chunk.trim(); - if (trimmed) { - log.debug(`[gemini stderr] ${trimmed}`); - log.warning(trimmed); - finalOutput2 += trimmed + "\n"; - } - } - }); - if (result.exitCode !== 0) { - const errorMessage = result.stderr || finalOutput2 || result.stdout || "Unknown error - no output from Gemini CLI"; - log.error(`Gemini CLI exited with code ${result.exitCode}: ${errorMessage}`); - return { - success: false, - error: errorMessage, - output: finalOutput2 || result.stdout || "" - }; - } - finalOutput2 = finalOutput2 || result.stdout || "Gemini CLI completed successfully."; - log.info("\u2713 Gemini CLI completed successfully"); - return { - success: true, - output: finalOutput2 - }; - } catch (error41) { - const errorMessage = error41 instanceof Error ? error41.message : String(error41); - log.error(`Failed to run Gemini CLI: ${errorMessage}`); - return { - success: false, - error: errorMessage, - output: finalOutput2 || "" - }; - } - } -}); -function configureGeminiMcpServers({ mcpServers }) { - const realHome = homedir3(); - const geminiConfigDir = join7(realHome, ".gemini"); - const settingsPath = join7(geminiConfigDir, "settings.json"); - mkdirSync4(geminiConfigDir, { recursive: true }); - let existingSettings = {}; - try { - const content = readFileSync2(settingsPath, "utf-8"); - existingSettings = JSON.parse(content); - } catch { - } - const geminiMcpServers = {}; - for (const [serverName, serverConfig] of Object.entries(mcpServers)) { - if (serverConfig.type !== "http") { - throw new Error( - `Unsupported MCP server type for Gemini: ${serverConfig.type || "unknown"}` - ); - } - geminiMcpServers[serverName] = { - httpUrl: serverConfig.url, - trust: true - // trust our own MCP server to avoid confirmation prompts - }; - log.info(`Adding MCP server '${serverName}' at ${serverConfig.url}...`); - } - const newSettings = { - ...existingSettings, - mcpServers: geminiMcpServers - }; - writeFileSync3(settingsPath, JSON.stringify(newSettings, null, 2), "utf-8"); - log.info(`\xBB MCP config written to ${settingsPath}`); -} - -// agents/opencode.ts -import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs"; -import { join as join8 } from "node:path"; -var opencode = agent({ - name: "opencode", - install: async () => { - return await installFromNpmTarball({ - packageName: "opencode-ai", - version: "latest", - executablePath: "bin/opencode", - installDependencies: true - }); - }, - run: async ({ payload, apiKey: _apiKey, apiKeys, mcpServers, cliPath, repo }) => { - const tempHome = process.env.PULLFROG_TEMP_DIR; - const configDir = join8(tempHome, ".config", "opencode"); - mkdirSync5(configDir, { recursive: true }); - configureOpenCode({ mcpServers, sandbox: payload.sandbox ?? false }); - const prompt = addInstructions({ payload, repo }); - log.group("Full prompt", () => log.info(prompt)); - const args3 = ["run", prompt, "--format", "json"]; - if (payload.sandbox) { - log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); - } - setupProcessAgentEnv({ HOME: tempHome }); - const env3 = { - ...Object.fromEntries( - Object.entries(process.env).filter( - ([key, value2]) => value2 !== void 0 && key !== "GITHUB_TOKEN" - ) - ), - HOME: tempHome, - XDG_CONFIG_HOME: join8(tempHome, ".config") - }; - for (const [key, value2] of Object.entries(apiKeys || {})) { - env3[key.toUpperCase()] = value2; - } - const repoDir = process.cwd(); - log.info(`\u{1F680} Starting OpenCode CLI: ${cliPath} ${args3.join(" ")}`); - log.info(`\u{1F4C1} Working directory: ${repoDir}`); - log.debug(`\u{1F3E0} HOME: ${env3.HOME}`); - log.debug(`\u{1F4CB} XDG_CONFIG_HOME: ${env3.XDG_CONFIG_HOME}`); - const startTime = Date.now(); - let lastActivityTime = startTime; - let eventCount = 0; - let output = ""; - let stdoutBuffer = ""; - const result = await spawn4({ - cmd: cliPath, - args: args3, - cwd: repoDir, - env: env3, - timeout: 6e5, - // 10 minutes timeout to prevent infinite hangs - stdio: ["ignore", "pipe", "pipe"], - onStdout: async (chunk) => { - const text = chunk.toString(); - output += text; - stdoutBuffer += text; - const lines = stdoutBuffer.split("\n"); - stdoutBuffer = lines.pop() || ""; - for (const line of lines) { - const trimmed = line.trim(); - if (!trimmed) { - continue; - } - try { - const event = JSON.parse(trimmed); - eventCount++; - log.debug(JSON.stringify(event, null, 2)); - const timeSinceLastActivity = Date.now() - lastActivityTime; - if (timeSinceLastActivity > 1e4) { - const activeToolCalls = toolCallTimings.size; - const toolCallInfo = activeToolCalls > 0 ? ` (waiting for ${activeToolCalls} tool call${activeToolCalls > 1 ? "s" : ""})` : " (OpenCode may be processing internally - LLM calls, planning, etc.)"; - log.warning( - `\u26A0\uFE0F No activity for ${(timeSinceLastActivity / 1e3).toFixed(1)}s${toolCallInfo} (${eventCount} events processed so far)` - ); - } - lastActivityTime = Date.now(); - const handler2 = messageHandlers4[event.type]; - if (handler2) { - await handler2(event); - } else { - log.info( - `\u{1F4CB} OpenCode event (unhandled): type=${event.type}, data=${JSON.stringify(event).substring(0, 500)}` - ); - } - } catch { - log.debug(`\xBB non-JSON stdout line: ${trimmed.substring(0, 200)}`); - } - } - }, - onStderr: (chunk) => { - try { - const parsed2 = JSON.parse(chunk); - log.debug(JSON.stringify(parsed2, null, 2)); - } catch { - } - const trimmed = chunk.trim(); - if (trimmed) { - log.warning(trimmed); - } - } - }); - const duration2 = Date.now() - startTime; - log.info(`\u2705 OpenCode CLI completed in ${duration2}ms with exit code ${result.exitCode}`); - if (!tokensLogged && (accumulatedTokens.input > 0 || accumulatedTokens.output > 0)) { - const totalTokens = accumulatedTokens.input + accumulatedTokens.output; - await log.summaryTable([ - [ - { data: "Input Tokens", header: true }, - { data: "Output Tokens", header: true }, - { data: "Total Tokens", header: true } - ], - [String(accumulatedTokens.input), String(accumulatedTokens.output), String(totalTokens)] - ]); - } - if (result.exitCode !== 0) { - const errorMessage = result.stderr || result.stdout || "Unknown error - no output from OpenCode CLI"; - log.error(`OpenCode CLI exited with code ${result.exitCode}: ${errorMessage}`); - log.debug(`OpenCode stdout: ${result.stdout?.substring(0, 500)}`); - log.debug(`OpenCode stderr: ${result.stderr?.substring(0, 500)}`); - return { - success: false, - output: finalOutput || output, - error: errorMessage - }; - } - return { - success: true, - output: finalOutput || output - }; - } -}); -function configureOpenCode({ mcpServers, sandbox }) { - const tempHome = process.env.PULLFROG_TEMP_DIR; - const configDir = join8(tempHome, ".config", "opencode"); - mkdirSync5(configDir, { recursive: true }); - const configPath = join8(configDir, "opencode.json"); - const opencodeMcpServers = {}; - for (const [serverName, serverConfig] of Object.entries(mcpServers)) { - if (serverConfig.type !== "http") { - log.error( - `unsupported MCP server type for OpenCode: ${serverConfig.type || "unknown"}` - ); - throw new Error( - `Unsupported MCP server type for OpenCode: ${serverConfig.type || "unknown"}` - ); - } - opencodeMcpServers[serverName] = { - type: "remote", - url: serverConfig.url - }; - } - const permission = sandbox ? { - edit: "deny", - bash: "deny", - webfetch: "deny", - doom_loop: "allow", - external_directory: "allow" - } : { - edit: "allow", - bash: "allow", - webfetch: "allow", - doom_loop: "allow", - external_directory: "allow" - }; - const config2 = { - mcp: opencodeMcpServers, - permission - }; - const configJson = JSON.stringify(config2, null, 2); - try { - writeFileSync4(configPath, configJson, "utf-8"); - } catch (error41) { - log.error( - `failed to write OpenCode config to ${configPath}: ${error41 instanceof Error ? error41.message : String(error41)}` - ); - throw error41; - } - log.info(`\xBB OpenCode config written to ${configPath} (sandbox: ${sandbox})`); - log.debug(`OpenCode config contents: -${configJson}`); -} -var finalOutput = ""; -var accumulatedTokens = { input: 0, output: 0 }; -var tokensLogged = false; -var toolCallTimings = /* @__PURE__ */ new Map(); -var currentStepId = null; -var currentStepType = null; -var stepHistory = []; -var messageHandlers4 = { - init: (event) => { - log.info( - `\u{1F535} OpenCode init: session_id=${event.session_id || "unknown"}, model=${event.model || "unknown"}` - ); - log.info(`\u{1F535} OpenCode init event (full): ${JSON.stringify(event)}`); - finalOutput = ""; - accumulatedTokens = { input: 0, output: 0 }; - tokensLogged = false; - }, - message: (event) => { - if (event.role === "assistant" && event.content?.trim()) { - const message = event.content.trim(); - if (message) { - if (event.delta) { - log.info( - `\u{1F4AD} OpenCode thinking: ${message.substring(0, 300)}${message.length > 300 ? "..." : ""}` - ); - } else { - log.info( - `\u{1F4AC} OpenCode message (${event.role}): ${message.substring(0, 100)}${message.length > 100 ? "..." : ""}` - ); - finalOutput = message; - } - } - } else if (event.role === "user") { - log.info( - `\u{1F4AC} OpenCode message (${event.role}): ${event.content?.substring(0, 100) || ""}${event.content && event.content.length > 100 ? "..." : ""}` - ); - } - }, - text: (event) => { - if (event.part?.text?.trim()) { - const message = event.part.text.trim(); - log.box(message, { title: "OpenCode" }); - finalOutput = message; - } - }, - step_start: (event) => { - const stepType = event.part?.type || "unknown"; - const stepId = event.part?.id || "unknown"; - currentStepId = stepId; - currentStepType = stepType; - stepHistory.push({ stepId, stepType, toolCalls: [] }); - }, - step_finish: async (event) => { - const stepId = event.part?.id || "unknown"; - const eventTokens = event.part?.tokens; - if (eventTokens) { - const inputTokens = eventTokens.input || 0; - const outputTokens = eventTokens.output || 0; - accumulatedTokens.input += inputTokens; - accumulatedTokens.output += outputTokens; - } - if (currentStepId === stepId) { - currentStepId = null; - currentStepType = null; - } - }, - tool_use: (event) => { - const toolName = event.part?.tool; - const toolId = event.part?.callID; - const parameters = event.part?.state?.input; - const status = event.part?.state?.status; - const output = event.part?.state?.output; - if (!toolName || !toolId) { - log.debug(`\xBB tool_use event missing toolName or toolId: ${JSON.stringify(event)}`); - } - if (toolName && toolId) { - if (stepHistory.length > 0) { - stepHistory[stepHistory.length - 1].toolCalls.push(toolName); - } - log.toolCall({ - toolName, - input: parameters || {} - }); - if (status === "completed" && output) { - log.debug(` output: ${output}`); - } - } - }, - tool_result: (event) => { - const toolId = event.part?.callID || event.tool_id; - const status = event.part?.state?.status || event.status || "unknown"; - const output = event.part?.state?.output || event.output; - if (toolId) { - const toolStartTime = toolCallTimings.get(toolId); - if (toolStartTime) { - const toolDuration = Date.now() - toolStartTime; - toolCallTimings.delete(toolId); - const stepContext = currentStepId ? ` (step=${currentStepType || "unknown"})` : ""; - log.info( - `\u{1F527} OpenCode tool_result${stepContext}: id=${toolId}, status=${status}, duration=${toolDuration}ms` - ); - if (output) { - log.debug(` output: ${typeof output === "string" ? output : JSON.stringify(output)}`); - } - if (toolDuration > 5e3) { - log.warning( - `\u26A0\uFE0F Tool call took ${(toolDuration / 1e3).toFixed(1)}s - this may indicate network latency or slow processing` - ); - } - } - } - if (status === "error") { - const errorMsg = typeof output === "string" ? output : JSON.stringify(output); - log.warning(`\u274C Tool call failed: ${errorMsg}`); - } - }, - result: async (event) => { - const status = event.status || "unknown"; - const duration2 = event.stats?.duration_ms || 0; - const toolCalls = event.stats?.tool_calls || 0; - log.info( - `\u{1F3C1} OpenCode result: status=${status}, duration=${duration2}ms, tool_calls=${toolCalls}` - ); - if (event.status === "error") { - log.error(`\u274C OpenCode CLI failed: ${JSON.stringify(event)}`); - } else { - const inputTokens = event.stats?.input_tokens || accumulatedTokens.input || 0; - const outputTokens = event.stats?.output_tokens || accumulatedTokens.output || 0; - const totalTokens = event.stats?.total_tokens || inputTokens + outputTokens; - log.info( - `\u{1F4CA} OpenCode final stats: input=${inputTokens}, output=${outputTokens}, total=${totalTokens}, tool_calls=${toolCalls}, duration=${duration2}ms` - ); - if ((inputTokens > 0 || outputTokens > 0) && !tokensLogged) { - await log.summaryTable([ - [ - { data: "Input Tokens", header: true }, - { data: "Output Tokens", header: true }, - { data: "Total Tokens", header: true } - ], - [String(inputTokens), String(outputTokens), String(totalTokens)] - ]); - tokensLogged = true; - } - } - } -}; - -// agents/index.ts -var agents = { - claude, - codex, - cursor, - gemini, - opencode -}; - -// main.ts -import { mkdtemp as mkdtemp2 } from "node:fs/promises"; -import { tmpdir as tmpdir2 } from "node:os"; -import { join as join12 } from "node:path"; +throttling.VERSION = VERSION; +throttling.triggersNotification = triggersNotification; // node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js function getUserAgent() { @@ -94883,8 +94486,8 @@ function Collection() { var before_after_hook_default = { Singular, Collection }; // node_modules/.pnpm/@octokit+endpoint@11.0.1/node_modules/@octokit/endpoint/dist-bundle/index.js -var VERSION = "0.0.0-development"; -var userAgent = `octokit-endpoint.js/${VERSION} ${getUserAgent()}`; +var VERSION2 = "0.0.0-development"; +var userAgent = `octokit-endpoint.js/${VERSION2} ${getUserAgent()}`; var DEFAULTS = { method: "GET", baseUrl: "https://api.github.com", @@ -95000,7 +94603,7 @@ function encodeUnreserved(str) { return "%" + c.charCodeAt(0).toString(16).toUpperCase(); }); } -function encodeValue2(operator, value2, key) { +function encodeValue(operator, value2, key) { value2 = operator === "+" || operator === "#" ? encodeReserved(value2) : encodeUnreserved(value2); if (key) { return encodeUnreserved(key) + "=" + value2; @@ -95023,20 +94626,20 @@ function getValues(context, operator, key, modifier) { value2 = value2.substring(0, parseInt(modifier, 10)); } result.push( - encodeValue2(operator, value2, isKeyOperator(operator) ? key : "") + encodeValue(operator, value2, isKeyOperator(operator) ? key : "") ); } else { if (modifier === "*") { if (Array.isArray(value2)) { value2.filter(isDefined).forEach(function(value22) { result.push( - encodeValue2(operator, value22, isKeyOperator(operator) ? key : "") + encodeValue(operator, value22, isKeyOperator(operator) ? key : "") ); }); } else { Object.keys(value2).forEach(function(k) { if (isDefined(value2[k])) { - result.push(encodeValue2(operator, value2[k], k)); + result.push(encodeValue(operator, value2[k], k)); } }); } @@ -95044,13 +94647,13 @@ function getValues(context, operator, key, modifier) { const tmp = []; if (Array.isArray(value2)) { value2.filter(isDefined).forEach(function(value22) { - tmp.push(encodeValue2(operator, value22)); + tmp.push(encodeValue(operator, value22)); }); } else { Object.keys(value2).forEach(function(k) { if (isDefined(value2[k])) { tmp.push(encodeUnreserved(k)); - tmp.push(encodeValue2(operator, value2[k].toString())); + tmp.push(encodeValue(operator, value2[k].toString())); } }); } @@ -95238,10 +94841,10 @@ var RequestError = class extends Error { }; // node_modules/.pnpm/@octokit+request@10.0.5/node_modules/@octokit/request/dist-bundle/index.js -var VERSION2 = "10.0.5"; +var VERSION3 = "10.0.5"; var defaults_default = { headers: { - "user-agent": `octokit-request.js/${VERSION2} ${getUserAgent()}` + "user-agent": `octokit-request.js/${VERSION3} ${getUserAgent()}` } }; function isPlainObject3(value2) { @@ -95412,7 +95015,7 @@ function withDefaults2(oldEndpoint, newDefaults) { var request = withDefaults2(endpoint, defaults_default); // node_modules/.pnpm/@octokit+graphql@9.0.2/node_modules/@octokit/graphql/dist-bundle/index.js -var VERSION3 = "0.0.0-development"; +var VERSION4 = "0.0.0-development"; function _buildMessageForResponseErrors(data) { return `Request failed due to following response errors: ` + data.errors.map((e) => ` - ${e.message}`).join("\n"); @@ -95506,7 +95109,7 @@ function withDefaults3(request2, newDefaults) { } var graphql2 = withDefaults3(request, { headers: { - "user-agent": `octokit-graphql.js/${VERSION3} ${getUserAgent()}` + "user-agent": `octokit-graphql.js/${VERSION4} ${getUserAgent()}` }, method: "POST", url: "/graphql" @@ -95564,19 +95167,19 @@ var createTokenAuth = function createTokenAuth2(token) { }; // node_modules/.pnpm/@octokit+core@7.0.5/node_modules/@octokit/core/dist-src/version.js -var VERSION4 = "7.0.5"; +var VERSION5 = "7.0.5"; // node_modules/.pnpm/@octokit+core@7.0.5/node_modules/@octokit/core/dist-src/index.js -var noop = () => { +var noop2 = () => { }; var consoleWarn = console.warn.bind(console); var consoleError = console.error.bind(console); function createLogger(logger = {}) { if (typeof logger.debug !== "function") { - logger.debug = noop; + logger.debug = noop2; } if (typeof logger.info !== "function") { - logger.info = noop; + logger.info = noop2; } if (typeof logger.warn !== "function") { logger.warn = consoleWarn; @@ -95586,9 +95189,9 @@ function createLogger(logger = {}) { } return logger; } -var userAgentTrail = `octokit-core.js/${VERSION4} ${getUserAgent()}`; +var userAgentTrail = `octokit-core.js/${VERSION5} ${getUserAgent()}`; var Octokit = class { - static VERSION = VERSION4; + static VERSION = VERSION5; static defaults(defaults) { const OctokitWithDefaults = class extends this { constructor(...args3) { @@ -95701,7 +95304,7 @@ var Octokit = class { }; // node_modules/.pnpm/@octokit+plugin-request-log@6.0.0_@octokit+core@7.0.5/node_modules/@octokit/plugin-request-log/dist-src/version.js -var VERSION5 = "6.0.0"; +var VERSION6 = "6.0.0"; // node_modules/.pnpm/@octokit+plugin-request-log@6.0.0_@octokit+core@7.0.5/node_modules/@octokit/plugin-request-log/dist-src/index.js function requestLog(octokit) { @@ -95725,10 +95328,10 @@ function requestLog(octokit) { }); }); } -requestLog.VERSION = VERSION5; +requestLog.VERSION = VERSION6; // node_modules/.pnpm/@octokit+plugin-paginate-rest@13.2.0_@octokit+core@7.0.5/node_modules/@octokit/plugin-paginate-rest/dist-bundle/index.js -var VERSION6 = "0.0.0-development"; +var VERSION7 = "0.0.0-development"; function normalizePaginatedListResponse(response) { if (!response.data) { return { @@ -95841,10 +95444,10 @@ function paginateRest(octokit) { }) }; } -paginateRest.VERSION = VERSION6; +paginateRest.VERSION = VERSION7; // node_modules/.pnpm/@octokit+plugin-rest-endpoint-methods@16.1.0_@octokit+core@7.0.5/node_modules/@octokit/plugin-rest-endpoint-methods/dist-src/version.js -var VERSION7 = "16.1.0"; +var VERSION8 = "16.1.0"; // node_modules/.pnpm/@octokit+plugin-rest-endpoint-methods@16.1.0_@octokit+core@7.0.5/node_modules/@octokit/plugin-rest-endpoint-methods/dist-src/generated/endpoints.js var Endpoints = { @@ -98168,7 +97771,7 @@ function restEndpointMethods(octokit) { rest: api }; } -restEndpointMethods.VERSION = VERSION7; +restEndpointMethods.VERSION = VERSION8; function legacyRestEndpointMethods(octokit) { const api = endpointsToMethods(octokit); return { @@ -98176,18 +97779,1942 @@ function legacyRestEndpointMethods(octokit) { rest: api }; } -legacyRestEndpointMethods.VERSION = VERSION7; +legacyRestEndpointMethods.VERSION = VERSION8; // node_modules/.pnpm/@octokit+rest@22.0.0/node_modules/@octokit/rest/dist-src/version.js -var VERSION8 = "22.0.0"; +var VERSION9 = "22.0.0"; // node_modules/.pnpm/@octokit+rest@22.0.0/node_modules/@octokit/rest/dist-src/index.js var Octokit2 = Octokit.plugin(requestLog, legacyRestEndpointMethods, paginateRest).defaults( { - userAgent: `octokit-rest.js/${VERSION8}` + userAgent: `octokit-rest.js/${VERSION9}` } ); +// utils/github.ts +import { createSign } from "node:crypto"; + +// utils/retry.ts +var defaultShouldRetry = (error41) => { + if (!(error41 instanceof Error)) return false; + return error41.name === "AbortError" || error41.message.includes("fetch failed") || error41.message.includes("ECONNRESET") || error41.message.includes("ETIMEDOUT"); +}; +async function retry(fn2, options = {}) { + const maxAttempts = options.maxAttempts ?? 3; + const delayMs = options.delayMs ?? 1e3; + const shouldRetry = options.shouldRetry ?? defaultShouldRetry; + const label = options.label ?? "operation"; + let lastError; + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + try { + return await fn2(); + } catch (error41) { + lastError = error41; + if (attempt === maxAttempts || !shouldRetry(error41)) { + throw error41; + } + const delay2 = delayMs * attempt; + log.warning( + `\xBB ${label} failed (attempt ${attempt}/${maxAttempts}), retrying in ${delay2}ms...` + ); + await new Promise((resolve) => setTimeout(resolve, delay2)); + } + } + throw lastError; +} + +// utils/github.ts +function isGitHubActionsEnvironment() { + return Boolean(process.env.GITHUB_ACTIONS); +} +async function acquireTokenViaOIDC() { + log.info("\xBB generating OIDC token..."); + const oidcToken = await core2.getIDToken("pullfrog-api"); + const apiUrl = process.env.API_URL || "https://pullfrog.com"; + log.info("\xBB exchanging OIDC token for installation token..."); + const timeoutMs = 3e4; + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + try { + const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, { + method: "POST", + headers: { + Authorization: `Bearer ${oidcToken}`, + "Content-Type": "application/json" + }, + signal: controller.signal + }); + clearTimeout(timeoutId); + if (!tokenResponse.ok) { + throw new Error(`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`); + } + const tokenData = await tokenResponse.json(); + log.info(`\xBB installation token obtained for ${tokenData.repository || "all repositories"}`); + return tokenData.token; + } catch (error41) { + clearTimeout(timeoutId); + if (error41 instanceof Error && error41.name === "AbortError") { + throw new Error(`Token exchange timed out after ${timeoutMs}ms`); + } + throw error41; + } +} +var base64UrlEncode = (str) => { + return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); +}; +var generateJWT = (appId, privateKey) => { + const now = Math.floor(Date.now() / 1e3); + const payload = { + iat: now - 60, + exp: now + 5 * 60, + iss: appId + }; + const header = { + alg: "RS256", + typ: "JWT" + }; + const encodedHeader = base64UrlEncode(JSON.stringify(header)); + const encodedPayload = base64UrlEncode(JSON.stringify(payload)); + const signaturePart = `${encodedHeader}.${encodedPayload}`; + const signature = createSign("RSA-SHA256").update(signaturePart).sign(privateKey, "base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + return `${signaturePart}.${signature}`; +}; +var githubRequest = async (path4, options = {}) => { + const { method = "GET", headers = {}, body } = options; + const url2 = `https://api.github.com${path4}`; + const requestHeaders = { + Accept: "application/vnd.github.v3+json", + "User-Agent": "Pullfrog-Installation-Token-Generator/1.0", + ...headers + }; + const response = await fetch(url2, { + method, + headers: requestHeaders, + ...body && { body } + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error( + `GitHub API request failed: ${response.status} ${response.statusText} +${errorText}` + ); + } + return response.json(); +}; +var checkRepositoryAccess = async (token, repoOwner, repoName) => { + try { + const response = await githubRequest("/installation/repositories", { + headers: { Authorization: `token ${token}` } + }); + return response.repositories.some( + (repo) => repo.owner.login === repoOwner && repo.name === repoName + ); + } catch { + return false; + } +}; +var createInstallationToken = async (jwt, installationId) => { + const response = await githubRequest( + `/app/installations/${installationId}/access_tokens`, + { + method: "POST", + headers: { Authorization: `Bearer ${jwt}` } + } + ); + return response.token; +}; +var findInstallationId = async (jwt, repoOwner, repoName) => { + const installations = await githubRequest("/app/installations", { + headers: { Authorization: `Bearer ${jwt}` } + }); + for (const installation of installations) { + try { + const tempToken = await createInstallationToken(jwt, installation.id); + const hasAccess = await checkRepositoryAccess(tempToken, repoOwner, repoName); + if (hasAccess) { + return installation.id; + } + } catch { + } + } + throw new Error( + `No installation found with access to ${repoOwner}/${repoName}. Ensure the GitHub App is installed on the target repository.` + ); +}; +async function acquireTokenViaGitHubApp() { + const repoContext = parseRepoContext(); + const config2 = { + appId: process.env.GITHUB_APP_ID, + privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n"), + repoOwner: repoContext.owner, + repoName: repoContext.name + }; + const jwt = generateJWT(config2.appId, config2.privateKey); + const installationId = await findInstallationId(jwt, config2.repoOwner, config2.repoName); + const token = await createInstallationToken(jwt, installationId); + return token; +} +async function acquireNewToken() { + if (isGitHubActionsEnvironment()) { + return await retry(() => acquireTokenViaOIDC(), { label: "token exchange" }); + } else { + return await acquireTokenViaGitHubApp(); + } +} +var githubInstallationToken; +async function setupGitHubInstallationToken() { + const acquiredToken = await acquireNewToken(); + core2.setSecret(acquiredToken); + githubInstallationToken = acquiredToken; + return acquiredToken; +} +function getGitHubInstallationToken() { + if (!githubInstallationToken) { + throw new Error("GitHub installation token not set. Call setupGitHubInstallationToken first."); + } + return githubInstallationToken; +} +async function revokeGitHubInstallationToken() { + if (!githubInstallationToken) { + return; + } + const token = githubInstallationToken; + githubInstallationToken = void 0; + const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com"; + try { + await fetch(`${apiUrl}/installation/token`, { + method: "DELETE", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${token}`, + "X-GitHub-Api-Version": "2022-11-28" + } + }); + log.debug("\xBB installation token revoked"); + } catch (error41) { + log.warning( + `Failed to revoke installation token: ${error41 instanceof Error ? error41.message : String(error41)}` + ); + } +} +function parseRepoContext() { + const githubRepo = process.env.GITHUB_REPOSITORY; + if (!githubRepo) { + throw new Error("GITHUB_REPOSITORY environment variable is required"); + } + const [owner, name] = githubRepo.split("/"); + if (!owner || !name) { + throw new Error(`Invalid GITHUB_REPOSITORY format: ${githubRepo}. Expected 'owner/repo'`); + } + return { owner, name }; +} +function createOctokit(token) { + const OctokitWithPlugins = Octokit2.plugin(throttling); + return new OctokitWithPlugins({ + auth: token, + throttle: { + onRateLimit: (retryAfter, options, octokit, retryCount) => { + return retryCount <= 2; + }, + onSecondaryRateLimit: (retryAfter, options, octokit, retryCount) => { + return retryCount <= 2; + } + } + }); +} + +// agents/shared.ts +function createAgentEnv(agentSpecificVars) { + const home = agentSpecificVars.HOME || process.env.HOME; + return { + PATH: process.env.PATH, + HOME: home, + // XDG_CONFIG_HOME must match HOME to ensure CLI tools find config files in the right place. + // GitHub Actions sets XDG_CONFIG_HOME to /home/runner/.config which would override $HOME/.config lookup. + XDG_CONFIG_HOME: home ? join4(home, ".config") : void 0, + LOG_LEVEL: process.env.LOG_LEVEL, + NODE_ENV: process.env.NODE_ENV, + GITHUB_TOKEN: getGitHubInstallationToken(), + ...agentSpecificVars + // values could be undefined but will be ignored + }; +} +function setupProcessAgentEnv(agentSpecificVars) { + Object.assign(process.env, createAgentEnv(agentSpecificVars)); +} +async function installFromNpmTarball({ + packageName, + version: version2, + executablePath, + installDependencies +}) { + let resolvedVersion = version2; + if (version2.startsWith("^") || version2.startsWith("~") || version2 === "latest") { + const npmRegistry2 = process.env.NPM_REGISTRY || "https://registry.npmjs.org"; + log.debug(`\xBB resolving version for ${version2}...`); + try { + const registryResponse = await fetch(`${npmRegistry2}/${packageName}`); + if (!registryResponse.ok) { + throw new Error(`Failed to query registry: ${registryResponse.status}`); + } + const registryData = await registryResponse.json(); + resolvedVersion = registryData["dist-tags"].latest; + log.debug(`\xBB resolved to version ${resolvedVersion}`); + } catch (error41) { + log.warning( + `Failed to resolve version from registry: ${error41 instanceof Error ? error41.message : String(error41)}` + ); + throw error41; + } + } + log.debug(`\xBB installing ${packageName}@${resolvedVersion}...`); + const tempDir = process.env.PULLFROG_TEMP_DIR; + const tarballPath = join4(tempDir, "package.tgz"); + const npmRegistry = process.env.NPM_REGISTRY || "https://registry.npmjs.org"; + let tarballUrl; + if (packageName.startsWith("@")) { + const [scope2, name] = packageName.slice(1).split("/"); + const scopedPackageName = `@${scope2}%2F${name}`; + tarballUrl = `${npmRegistry}/${scopedPackageName}/-/${name}-${resolvedVersion}.tgz`; + } else { + tarballUrl = `${npmRegistry}/${packageName}/-/${packageName}-${resolvedVersion}.tgz`; + } + log.debug(`\xBB downloading from ${tarballUrl}...`); + const response = await fetch(tarballUrl); + if (!response.ok) { + throw new Error(`Failed to download tarball: ${response.status} ${response.statusText}`); + } + if (!response.body) throw new Error("Response body is null"); + const fileStream = createWriteStream2(tarballPath); + await pipeline(response.body, fileStream); + log.debug(`\xBB downloaded tarball to ${tarballPath}`); + log.debug(`\xBB extracting tarball...`); + const extractResult = spawnSync("tar", ["-xzf", tarballPath, "-C", tempDir], { + stdio: "pipe", + encoding: "utf-8" + }); + if (extractResult.status !== 0) { + throw new Error( + `Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}` + ); + } + const extractedDir = join4(tempDir, "package"); + const cliPath = join4(extractedDir, executablePath); + if (!existsSync2(cliPath)) { + throw new Error(`Executable not found in extracted package at ${cliPath}`); + } + if (installDependencies) { + log.debug(`\xBB installing dependencies for ${packageName}...`); + const installResult = spawnSync("npm", ["install", "--production"], { + cwd: extractedDir, + stdio: "pipe", + encoding: "utf-8" + }); + if (installResult.status !== 0) { + throw new Error( + `Failed to install dependencies: ${installResult.stderr || installResult.stdout || "Unknown error"}` + ); + } + log.debug(`\xBB dependencies installed`); + } + chmodSync(cliPath, 493); + log.debug(`\xBB ${packageName} installed at ${cliPath}`); + return cliPath; +} +async function fetchWithRetry(url2, headers, errorMessage) { + const response = await fetch(url2, { headers }); + if (!response.ok) { + const retryAfter = response.headers.get("Retry-After") || response.headers.get("retry-after"); + if (retryAfter) { + const waitSeconds = parseInt(retryAfter, 10); + if (!Number.isNaN(waitSeconds) && waitSeconds > 0) { + log.info(`Rate limited, waiting ${waitSeconds} seconds before retry...`); + await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1e3)); + const retryResponse = await fetch(url2, { headers }); + if (!retryResponse.ok) { + throw new Error( + `${errorMessage}: ${retryResponse.status} ${retryResponse.statusText} (retry failed)` + ); + } + return retryResponse; + } + } + throw new Error(`${errorMessage}: ${response.status} ${response.statusText}`); + } + return response; +} +async function installFromGithub({ + owner, + repo, + assetName, + executablePath, + githubInstallationToken: githubInstallationToken2 +}) { + log.info(`\u{1F4E6} Installing ${owner}/${repo} from GitHub releases...`); + const releaseUrl = `https://api.github.com/repos/${owner}/${repo}/releases/latest`; + log.info(`Fetching release from ${releaseUrl}...`); + const headers = {}; + if (githubInstallationToken2) { + headers.Authorization = `Bearer ${githubInstallationToken2}`; + } + const releaseResponse = await fetchWithRetry(releaseUrl, headers, "Failed to fetch release"); + const releaseData = await releaseResponse.json(); + log.info(`Found release: ${releaseData.tag_name}`); + const asset = releaseData.assets.find((a) => a.name === assetName); + if (!asset) { + throw new Error(`Asset '${assetName}' not found in release ${releaseData.tag_name}`); + } + const assetUrl = asset.browser_download_url; + log.info(`Downloading asset from ${assetUrl}...`); + const tempDirPrefix = `${owner}-${repo}-github-`; + const tempDir = await mkdtemp(join4(tmpdir(), tempDirPrefix)); + const urlPath = new URL(assetUrl).pathname; + const fileName3 = urlPath.split("/").pop() || "asset"; + const downloadPath = join4(tempDir, fileName3); + const assetResponse = await fetchWithRetry(assetUrl, headers, "Failed to download asset"); + if (!assetResponse.body) throw new Error("Response body is null"); + const fileStream = createWriteStream2(downloadPath); + await pipeline(assetResponse.body, fileStream); + log.info(`Downloaded asset to ${downloadPath}`); + let cliPath; + if (executablePath) { + cliPath = join4(tempDir, executablePath); + } else { + cliPath = downloadPath; + } + if (!existsSync2(cliPath)) { + throw new Error(`Executable not found at ${cliPath}`); + } + chmodSync(cliPath, 493); + log.info(`\u2713 Installed from GitHub release at ${cliPath}`); + return cliPath; +} +async function installFromCurl({ + installUrl, + executableName +}) { + log.info(`\u{1F4E6} Installing ${executableName}...`); + const tempDir = process.env.PULLFROG_TEMP_DIR; + const installScriptPath = join4(tempDir, "install.sh"); + log.info(`Downloading install script from ${installUrl}...`); + const installScriptResponse = await fetch(installUrl); + if (!installScriptResponse.ok) { + throw new Error(`Failed to download install script: ${installScriptResponse.status}`); + } + if (!installScriptResponse.body) throw new Error("Response body is null"); + const fileStream = createWriteStream2(installScriptPath); + await pipeline(installScriptResponse.body, fileStream); + log.info(`Downloaded install script to ${installScriptPath}`); + chmodSync(installScriptPath, 493); + log.info(`Installing to temp directory at ${tempDir}...`); + const installResult = spawnSync("bash", [installScriptPath], { + cwd: tempDir, + env: { + // Run the install script with HOME set to temp directory + // ensuring a fresh install for each run + HOME: tempDir, + // XDG_CONFIG_HOME must match HOME so CLI tools find config in the right place + XDG_CONFIG_HOME: join4(tempDir, ".config"), + SHELL: process.env.SHELL, + USER: process.env.USER + }, + stdio: "pipe", + encoding: "utf-8" + }); + if (installResult.status !== 0) { + const errorOutput = installResult.stderr || installResult.stdout || "No output"; + throw new Error( + `Failed to install ${executableName}. Install script exited with code ${installResult.status}. Output: ${errorOutput}` + ); + } + const cliPath = join4(tempDir, ".local", "bin", executableName); + if (!existsSync2(cliPath)) { + throw new Error(`Executable not found at ${cliPath}`); + } + chmodSync(cliPath, 493); + log.info(`\u2713 ${executableName} installed at ${cliPath}`); + return cliPath; +} +var agent = (input) => { + return { ...input, ...agentsManifest[input.name] }; +}; + +// agents/claude.ts +var claude = agent({ + name: "claude", + install: async () => { + const versionRange = package_default.dependencies["@anthropic-ai/claude-agent-sdk"] || "latest"; + return await installFromNpmTarball({ + packageName: "@anthropic-ai/claude-agent-sdk", + version: versionRange, + executablePath: "cli.js" + }); + }, + run: async ({ payload, mcpServers, apiKey, cliPath, repo }) => { + delete process.env.ANTHROPIC_API_KEY; + const prompt = addInstructions({ payload, repo }); + log.group("Full prompt", () => log.info(prompt)); + const sandboxOptions = payload.sandbox ? { + permissionMode: "default", + disallowedTools: ["Bash", "WebSearch", "WebFetch", "Write"], + async canUseTool(toolName, input, _options) { + if (toolName.startsWith("mcp__gh_pullfrog__")) + return { + behavior: "allow", + updatedInput: input, + updatedPermissions: [] + }; + console.error("can i use this tool?", toolName); + return { + behavior: "deny", + message: "You are not allowed to use this tool." + }; + } + } : { + permissionMode: "bypassPermissions" + }; + if (payload.sandbox) { + log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); + } + const queryInstance = query({ + prompt, + options: { + ...sandboxOptions, + mcpServers, + // model: "claude-opus-4-5", + pathToClaudeCodeExecutable: cliPath, + env: createAgentEnv({ ANTHROPIC_API_KEY: apiKey }) + } + }); + for await (const message of queryInstance) { + log.debug(JSON.stringify(message, null, 2)); + const handler2 = messageHandlers[message.type]; + await handler2(message); + } + return { + success: true, + output: "" + }; + } +}); +var bashToolIds = /* @__PURE__ */ new Set(); +var messageHandlers = { + assistant: (data) => { + if (data.message?.content) { + for (const content of data.message.content) { + if (content.type === "text" && content.text?.trim()) { + log.box(content.text.trim(), { title: "Claude" }); + } else if (content.type === "tool_use") { + if (content.name === "bash" && content.id) { + bashToolIds.add(content.id); + } + log.toolCall({ + toolName: content.name, + input: content.input + }); + } + } + } + }, + user: (data) => { + if (data.message?.content) { + for (const content of data.message.content) { + if (content.type === "tool_result") { + const toolUseId = content.tool_use_id; + const isBashTool = toolUseId && bashToolIds.has(toolUseId); + if (isBashTool) { + const outputContent = typeof content.content === "string" ? content.content : Array.isArray(content.content) ? content.content.map((c) => typeof c === "string" ? c : c.text || JSON.stringify(c)).join("\n") : String(content.content); + log.startGroup(`bash output`); + if (content.is_error) { + log.warning(outputContent); + } else { + log.info(outputContent); + } + log.endGroup(); + bashToolIds.delete(toolUseId); + } else if (content.is_error) { + const errorContent = typeof content.content === "string" ? content.content : String(content.content); + log.warning(`Tool error: ${errorContent}`); + } + } + } + } + }, + result: async (data) => { + if (data.subtype === "success") { + const usage = data.usage; + const inputTokens = usage?.input_tokens || 0; + const cacheRead = usage?.cache_read_input_tokens || 0; + const cacheWrite = usage?.cache_creation_input_tokens || 0; + const outputTokens = usage?.output_tokens || 0; + const totalInput = inputTokens + cacheRead + cacheWrite; + await log.summaryTable([ + [ + { data: "Cost", header: true }, + { data: "Input", header: true }, + { data: "Cache Read", header: true }, + { data: "Cache Write", header: true }, + { data: "Output", header: true } + ], + [ + `$${data.total_cost_usd?.toFixed(4) || "0.0000"}`, + String(totalInput), + String(cacheRead), + String(cacheWrite), + String(outputTokens) + ] + ]); + } else if (data.subtype === "error_max_turns") { + log.error(`Max turns reached: ${JSON.stringify(data)}`); + } else if (data.subtype === "error_during_execution") { + log.error(`Execution error: ${JSON.stringify(data)}`); + } else { + log.error(`Failed: ${JSON.stringify(data)}`); + } + }, + system: () => { + }, + stream_event: () => { + }, + tool_progress: () => { + }, + auth_status: () => { + } +}; + +// agents/codex.ts +import { spawnSync as spawnSync2 } from "node:child_process"; +import { mkdirSync as mkdirSync2 } from "node:fs"; +import { join as join5 } from "node:path"; + +// node_modules/.pnpm/@openai+codex-sdk@0.58.0/node_modules/@openai/codex-sdk/dist/index.js +import { promises as fs2 } from "fs"; +import os from "os"; +import path from "path"; +import { spawn as spawn2 } from "child_process"; +import path2 from "path"; +import readline from "readline"; +import { fileURLToPath as fileURLToPath2 } from "url"; +async function createOutputSchemaFile(schema2) { + if (schema2 === void 0) { + return { cleanup: async () => { + } }; + } + if (!isJsonObject2(schema2)) { + throw new Error("outputSchema must be a plain JSON object"); + } + const schemaDir = await fs2.mkdtemp(path.join(os.tmpdir(), "codex-output-schema-")); + const schemaPath = path.join(schemaDir, "schema.json"); + const cleanup = async () => { + try { + await fs2.rm(schemaDir, { recursive: true, force: true }); + } catch { + } + }; + try { + await fs2.writeFile(schemaPath, JSON.stringify(schema2), "utf8"); + return { schemaPath, cleanup }; + } catch (error41) { + await cleanup(); + throw error41; + } +} +function isJsonObject2(value2) { + return typeof value2 === "object" && value2 !== null && !Array.isArray(value2); +} +var Thread = class { + _exec; + _options; + _id; + _threadOptions; + /** Returns the ID of the thread. Populated after the first turn starts. */ + get id() { + return this._id; + } + /* @internal */ + constructor(exec, options, threadOptions, id = null) { + this._exec = exec; + this._options = options; + this._id = id; + this._threadOptions = threadOptions; + } + /** Provides the input to the agent and streams events as they are produced during the turn. */ + async runStreamed(input, turnOptions = {}) { + return { events: this.runStreamedInternal(input, turnOptions) }; + } + async *runStreamedInternal(input, turnOptions = {}) { + const { schemaPath, cleanup } = await createOutputSchemaFile(turnOptions.outputSchema); + const options = this._threadOptions; + const { prompt, images } = normalizeInput(input); + const generator = this._exec.run({ + input: prompt, + baseUrl: this._options.baseUrl, + apiKey: this._options.apiKey, + threadId: this._id, + images, + model: options?.model, + sandboxMode: options?.sandboxMode, + workingDirectory: options?.workingDirectory, + skipGitRepoCheck: options?.skipGitRepoCheck, + outputSchemaFile: schemaPath, + modelReasoningEffort: options?.modelReasoningEffort, + networkAccessEnabled: options?.networkAccessEnabled, + webSearchEnabled: options?.webSearchEnabled, + approvalPolicy: options?.approvalPolicy + }); + try { + for await (const item of generator) { + let parsed2; + try { + parsed2 = JSON.parse(item); + } catch (error41) { + throw new Error(`Failed to parse item: ${item}`, { cause: error41 }); + } + if (parsed2.type === "thread.started") { + this._id = parsed2.thread_id; + } + yield parsed2; + } + } finally { + await cleanup(); + } + } + /** Provides the input to the agent and returns the completed turn. */ + async run(input, turnOptions = {}) { + const generator = this.runStreamedInternal(input, turnOptions); + const items = []; + let finalResponse = ""; + let usage = null; + let turnFailure = null; + for await (const event of generator) { + if (event.type === "item.completed") { + if (event.item.type === "agent_message") { + finalResponse = event.item.text; + } + items.push(event.item); + } else if (event.type === "turn.completed") { + usage = event.usage; + } else if (event.type === "turn.failed") { + turnFailure = event.error; + break; + } + } + if (turnFailure) { + throw new Error(turnFailure.message); + } + return { items, finalResponse, usage }; + } +}; +function normalizeInput(input) { + if (typeof input === "string") { + return { prompt: input, images: [] }; + } + const promptParts = []; + const images = []; + for (const item of input) { + if (item.type === "text") { + promptParts.push(item.text); + } else if (item.type === "local_image") { + images.push(item.path); + } + } + return { prompt: promptParts.join("\n\n"), images }; +} +var INTERNAL_ORIGINATOR_ENV = "CODEX_INTERNAL_ORIGINATOR_OVERRIDE"; +var TYPESCRIPT_SDK_ORIGINATOR = "codex_sdk_ts"; +var CodexExec = class { + executablePath; + constructor(executablePath = null) { + this.executablePath = executablePath || findCodexPath(); + } + async *run(args3) { + const commandArgs = ["exec", "--experimental-json"]; + if (args3.model) { + commandArgs.push("--model", args3.model); + } + if (args3.sandboxMode) { + commandArgs.push("--sandbox", args3.sandboxMode); + } + if (args3.workingDirectory) { + commandArgs.push("--cd", args3.workingDirectory); + } + if (args3.skipGitRepoCheck) { + commandArgs.push("--skip-git-repo-check"); + } + if (args3.outputSchemaFile) { + commandArgs.push("--output-schema", args3.outputSchemaFile); + } + if (args3.modelReasoningEffort) { + commandArgs.push("--config", `model_reasoning_effort="${args3.modelReasoningEffort}"`); + } + if (args3.networkAccessEnabled !== void 0) { + commandArgs.push("--config", `sandbox_workspace_write.network_access=${args3.networkAccessEnabled}`); + } + if (args3.webSearchEnabled !== void 0) { + commandArgs.push("--config", `features.web_search_request=${args3.webSearchEnabled}`); + } + if (args3.approvalPolicy) { + commandArgs.push("--config", `approval_policy="${args3.approvalPolicy}"`); + } + if (args3.images?.length) { + for (const image of args3.images) { + commandArgs.push("--image", image); + } + } + if (args3.threadId) { + commandArgs.push("resume", args3.threadId); + } + const env3 = { + ...process.env + }; + if (!env3[INTERNAL_ORIGINATOR_ENV]) { + env3[INTERNAL_ORIGINATOR_ENV] = TYPESCRIPT_SDK_ORIGINATOR; + } + if (args3.baseUrl) { + env3.OPENAI_BASE_URL = args3.baseUrl; + } + if (args3.apiKey) { + env3.CODEX_API_KEY = args3.apiKey; + } + const child = spawn2(this.executablePath, commandArgs, { + env: env3 + }); + let spawnError = null; + child.once("error", (err) => spawnError = err); + if (!child.stdin) { + child.kill(); + throw new Error("Child process has no stdin"); + } + child.stdin.write(args3.input); + child.stdin.end(); + if (!child.stdout) { + child.kill(); + throw new Error("Child process has no stdout"); + } + const stderrChunks = []; + if (child.stderr) { + child.stderr.on("data", (data) => { + stderrChunks.push(data); + }); + } + const rl = readline.createInterface({ + input: child.stdout, + crlfDelay: Infinity + }); + try { + for await (const line of rl) { + yield line; + } + const exitCode = new Promise((resolve, reject) => { + child.once("exit", (code) => { + if (code === 0) { + resolve(code); + } else { + const stderrBuffer = Buffer.concat(stderrChunks); + reject( + new Error(`Codex Exec exited with code ${code}: ${stderrBuffer.toString("utf8")}`) + ); + } + }); + }); + if (spawnError) throw spawnError; + await exitCode; + } finally { + rl.close(); + child.removeAllListeners(); + try { + if (!child.killed) child.kill(); + } catch { + } + } + } +}; +var scriptFileName = fileURLToPath2(import.meta.url); +var scriptDirName = path2.dirname(scriptFileName); +function findCodexPath() { + const { platform, arch } = process; + let targetTriple = null; + switch (platform) { + case "linux": + case "android": + switch (arch) { + case "x64": + targetTriple = "x86_64-unknown-linux-musl"; + break; + case "arm64": + targetTriple = "aarch64-unknown-linux-musl"; + break; + default: + break; + } + break; + case "darwin": + switch (arch) { + case "x64": + targetTriple = "x86_64-apple-darwin"; + break; + case "arm64": + targetTriple = "aarch64-apple-darwin"; + break; + default: + break; + } + break; + case "win32": + switch (arch) { + case "x64": + targetTriple = "x86_64-pc-windows-msvc"; + break; + case "arm64": + targetTriple = "aarch64-pc-windows-msvc"; + break; + default: + break; + } + break; + default: + break; + } + if (!targetTriple) { + throw new Error(`Unsupported platform: ${platform} (${arch})`); + } + const vendorRoot = path2.join(scriptDirName, "..", "vendor"); + const archRoot = path2.join(vendorRoot, targetTriple); + const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex"; + const binaryPath = path2.join(archRoot, "codex", codexBinaryName); + return binaryPath; +} +var Codex = class { + exec; + options; + constructor(options = {}) { + this.exec = new CodexExec(options.codexPathOverride); + this.options = options; + } + /** + * Starts a new conversation with an agent. + * @returns A new thread instance. + */ + startThread(options = {}) { + return new Thread(this.exec, this.options, options); + } + /** + * Resumes a conversation with an agent based on the thread id. + * Threads are persisted in ~/.codex/sessions. + * + * @param id The id of the thread to resume. + * @returns A new thread instance. + */ + resumeThread(id, options = {}) { + return new Thread(this.exec, this.options, options, id); + } +}; + +// agents/codex.ts +var codex = agent({ + name: "codex", + install: async () => { + return await installFromNpmTarball({ + packageName: "@openai/codex", + version: "latest", + executablePath: "bin/codex.js" + }); + }, + run: async ({ payload, mcpServers, apiKey, cliPath, repo }) => { + const tempHome = process.env.PULLFROG_TEMP_DIR; + const configDir = join5(tempHome, ".config", "codex"); + mkdirSync2(configDir, { recursive: true }); + setupProcessAgentEnv({ + OPENAI_API_KEY: apiKey, + HOME: tempHome + }); + configureCodexMcpServers({ mcpServers, cliPath }); + const codexOptions = { + apiKey, + codexPathOverride: cliPath + }; + if (payload.sandbox) { + log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); + } + const codex2 = new Codex(codexOptions); + const thread = codex2.startThread( + payload.sandbox ? { + approvalPolicy: "never", + sandboxMode: "read-only", + networkAccessEnabled: false + } : { + approvalPolicy: "never", + // use danger-full-access to allow git operations (workspace-write blocks .git directory writes) + sandboxMode: "danger-full-access", + networkAccessEnabled: true + } + ); + try { + const streamedTurn = await thread.runStreamed(addInstructions({ payload, repo })); + let finalOutput2 = ""; + for await (const event of streamedTurn.events) { + const handler2 = messageHandlers2[event.type]; + log.debug(JSON.stringify(event, null, 2)); + if (handler2) { + handler2(event); + } + if (event.type === "item.completed" && event.item.type === "agent_message") { + finalOutput2 = event.item.text; + } + } + return { + success: true, + output: finalOutput2 + }; + } catch (error41) { + const errorMessage = error41 instanceof Error ? error41.message : String(error41); + log.error(`Codex execution failed: ${errorMessage}`); + return { + success: false, + error: errorMessage, + output: "" + }; + } + } +}); +var commandExecutionIds = /* @__PURE__ */ new Set(); +var messageHandlers2 = { + "thread.started": () => { + }, + "turn.started": () => { + }, + "turn.completed": async (event) => { + await log.summaryTable([ + [ + { data: "Input Tokens", header: true }, + { data: "Cached Input Tokens", header: true }, + { data: "Output Tokens", header: true } + ], + [ + String(event.usage.input_tokens || 0), + String(event.usage.cached_input_tokens || 0), + String(event.usage.output_tokens || 0) + ] + ]); + }, + "turn.failed": (event) => { + log.error(`Turn failed: ${event.error.message}`); + }, + "item.started": (event) => { + const item = event.item; + if (item.type === "command_execution") { + commandExecutionIds.add(item.id); + log.toolCall({ + toolName: item.command, + input: item.args || {} + }); + } else if (item.type === "agent_message") { + } else if (item.type === "mcp_tool_call") { + log.toolCall({ + toolName: item.tool, + input: { + server: item.server, + ...item.arguments || {} + } + }); + } + }, + "item.updated": (event) => { + const item = event.item; + if (item.type === "command_execution") { + if (item.status === "in_progress" && item.aggregated_output) { + } + } + }, + "item.completed": (event) => { + const item = event.item; + if (item.type === "agent_message") { + log.box(item.text.trim(), { title: "Codex" }); + } else if (item.type === "command_execution") { + const isTracked = commandExecutionIds.has(item.id); + if (isTracked) { + log.startGroup(`bash output`); + if (item.status === "failed" || item.exit_code !== void 0 && item.exit_code !== 0) { + log.warning(item.aggregated_output || "Command failed"); + } else { + log.info(item.aggregated_output || ""); + } + log.endGroup(); + commandExecutionIds.delete(item.id); + } + } else if (item.type === "mcp_tool_call") { + if (item.status === "failed" && item.error) { + log.warning(`MCP tool call failed: ${item.error.message}`); + } + } else if (item.type === "reasoning") { + const reasoningText = item.text.trim(); + const cleanText = reasoningText.replace(/\*\*/g, ""); + log.box(cleanText, { title: "Codex" }); + } + }, + error: (event) => { + log.error(`Error: ${event.message}`); + } +}; +function configureCodexMcpServers({ mcpServers, cliPath }) { + for (const [serverName, serverConfig] of Object.entries(mcpServers)) { + if (serverConfig.type === "http") { + const addArgs = ["mcp", "add", serverName, "--url", serverConfig.url]; + log.info(`Adding MCP server '${serverName}' at ${serverConfig.url}...`); + const addResult = spawnSync2("node", [cliPath, ...addArgs], { + stdio: "pipe", + encoding: "utf-8" + }); + if (addResult.status !== 0) { + throw new Error( + `codex mcp add failed: ${addResult.stderr || addResult.stdout || "Unknown error"}` + ); + } + log.info(`\u2713 MCP server '${serverName}' configured`); + } else { + throw new Error( + `Unsupported MCP server type for Codex: ${serverConfig.type || "unknown"}` + ); + } + } +} + +// agents/cursor.ts +import { spawn as spawn3 } from "node:child_process"; +import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "node:fs"; +import { homedir as homedir2 } from "node:os"; +import { join as join6 } from "node:path"; +var cursor = agent({ + name: "cursor", + install: async () => { + return await installFromCurl({ + installUrl: "https://cursor.com/install", + executableName: "cursor-agent" + }); + }, + run: async ({ payload, apiKey, cliPath, mcpServers, repo }) => { + configureCursorMcpServers({ mcpServers, cliPath }); + configureCursorSandbox({ sandbox: payload.sandbox ?? false }); + const loggedModelCallIds = /* @__PURE__ */ new Set(); + const messageHandlers5 = { + system: (_event) => { + }, + user: (_event) => { + }, + thinking: (_event) => { + }, + assistant: (event) => { + const text = event.message?.content?.[0]?.text?.trim(); + if (!text) return; + if (event.model_call_id) { + if (!loggedModelCallIds.has(event.model_call_id)) { + loggedModelCallIds.add(event.model_call_id); + log.box(text, { title: "Cursor" }); + } + } else { + log.box(text, { title: "Cursor" }); + } + }, + tool_call: (event) => { + if (event.subtype === "started") { + const mcpToolCall = event.tool_call?.mcpToolCall; + const builtinToolCall = event.tool_call?.builtinToolCall; + if (mcpToolCall?.args?.toolName && mcpToolCall?.args?.args) { + log.toolCall({ + toolName: mcpToolCall.args.toolName, + input: mcpToolCall.args.args + }); + } else if (builtinToolCall?.args?.name && builtinToolCall?.args?.args) { + log.toolCall({ + toolName: builtinToolCall.args.name, + input: builtinToolCall.args.args + }); + } + } else if (event.subtype === "completed") { + const isError = event.tool_call?.mcpToolCall?.result?.success?.isError; + if (isError) { + log.warning("Tool call failed"); + } + } + }, + result: async (event) => { + if (event.subtype === "success" && event.duration_ms) { + const durationSec = (event.duration_ms / 1e3).toFixed(1); + log.debug(`Cursor completed in ${durationSec}s`); + } + } + }; + try { + const fullPrompt = addInstructions({ payload, repo }); + log.group("Full prompt", () => log.info(fullPrompt)); + const cursorArgs = payload.sandbox ? [ + "--print", + fullPrompt, + "--output-format", + "stream-json", + "--approve-mcps" + // --force removed in sandbox mode to enforce safety checks + ] : ["--print", fullPrompt, "--output-format", "stream-json", "--approve-mcps", "--force"]; + if (payload.sandbox) { + log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); + } + log.info("Running Cursor CLI..."); + const startTime = Date.now(); + return new Promise((resolve) => { + const child = spawn3(cliPath, cursorArgs, { + cwd: process.cwd(), + env: createAgentEnv({ + CURSOR_API_KEY: apiKey + }), + stdio: ["ignore", "pipe", "pipe"] + // Ignore stdin, pipe stdout/stderr + }); + let stdout = ""; + let stderr = ""; + child.on("spawn", () => { + log.debug("Cursor CLI process spawned"); + }); + child.stdout?.on("data", async (data) => { + const text = data.toString(); + stdout += text; + try { + const event = JSON.parse(text); + log.debug(JSON.stringify(event, null, 2)); + if (event.type === "thinking" && event.subtype === "delta" && !event.text) { + return; + } + const handler2 = messageHandlers5[event.type]; + if (handler2) { + await handler2(event); + } + } catch { + } + }); + child.stderr?.on("data", (data) => { + const text = data.toString(); + stderr += text; + process.stderr.write(text); + log.warning(text); + }); + child.on("close", async (code, signal) => { + if (signal) { + log.warning(`Cursor CLI terminated by signal: ${signal}`); + } + const duration2 = ((Date.now() - startTime) / 1e3).toFixed(1); + if (code === 0) { + log.success(`Cursor CLI completed successfully in ${duration2}s`); + resolve({ + success: true, + output: stdout.trim() + }); + } else { + const errorMessage = stderr || `Cursor CLI exited with code ${code}`; + log.error(`Cursor CLI failed after ${duration2}s: ${errorMessage}`); + resolve({ + success: false, + error: errorMessage, + output: stdout.trim() + }); + } + }); + child.on("error", (error41) => { + const duration2 = ((Date.now() - startTime) / 1e3).toFixed(1); + const errorMessage = error41.message || String(error41); + log.error(`Cursor CLI execution failed after ${duration2}s: ${errorMessage}`); + resolve({ + success: false, + error: errorMessage, + output: stdout.trim() + }); + }); + }); + } catch (error41) { + const errorMessage = error41 instanceof Error ? error41.message : String(error41); + log.error(`Cursor execution failed: ${errorMessage}`); + return { + success: false, + error: errorMessage, + output: "" + }; + } + } +}); +function configureCursorMcpServers({ mcpServers }) { + const realHome = homedir2(); + const cursorConfigDir = join6(realHome, ".cursor"); + const mcpConfigPath = join6(cursorConfigDir, "mcp.json"); + mkdirSync3(cursorConfigDir, { recursive: true }); + const cursorMcpServers = {}; + for (const [serverName, serverConfig] of Object.entries(mcpServers)) { + if (serverConfig.type !== "http") { + throw new Error( + `Unsupported MCP server type for Cursor: ${serverConfig.type || "unknown"}` + ); + } + cursorMcpServers[serverName] = { + type: "http", + url: serverConfig.url + }; + } + writeFileSync2(mcpConfigPath, JSON.stringify({ mcpServers: cursorMcpServers }, null, 2), "utf-8"); + log.info(`\xBB MCP config written to ${mcpConfigPath}`); +} +function configureCursorSandbox({ sandbox }) { + const realHome = homedir2(); + const cursorConfigDir = join6(realHome, ".cursor"); + const cliConfigPath = join6(cursorConfigDir, "cli-config.json"); + mkdirSync3(cursorConfigDir, { recursive: true }); + const config2 = sandbox ? { + // sandbox mode: deny all writes and shell commands + permissions: { + allow: [ + "Read(**)" + // allow reading all files + ], + deny: [ + "Write(**)", + // deny all file writes + "Shell(**)" + // deny all shell commands + ] + } + } : { + // normal mode: allow everything + permissions: { + allow: ["Read(**)", "Write(**)", "Shell(**)"], + deny: [] + } + }; + writeFileSync2(cliConfigPath, JSON.stringify(config2, null, 2), "utf-8"); + log.info(`\xBB CLI config written to ${cliConfigPath} (sandbox: ${sandbox})`); +} + +// agents/gemini.ts +import { mkdirSync as mkdirSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs"; +import { homedir as homedir3 } from "node:os"; +import { join as join7 } from "node:path"; + +// utils/subprocess.ts +import { spawn as nodeSpawn } from "node:child_process"; +async function spawn4(options) { + const { cmd, args: args3, env: env3, input, timeout, cwd: cwd2, stdio, onStdout, onStderr } = options; + const startTime = Date.now(); + let stdoutBuffer = ""; + let stderrBuffer = ""; + return new Promise((resolve, reject) => { + const child = nodeSpawn(cmd, args3, { + env: env3 || { + PATH: process.env.PATH || "", + HOME: process.env.HOME || "" + }, + stdio: stdio || ["pipe", "pipe", "pipe"], + cwd: cwd2 || process.cwd() + }); + let timeoutId; + let isTimedOut = false; + if (timeout) { + timeoutId = setTimeout(() => { + isTimedOut = true; + child.kill("SIGTERM"); + setTimeout(() => { + if (!child.killed) { + child.kill("SIGKILL"); + } + }, 5e3); + }, timeout); + } + if (child.stdout) { + child.stdout.on("data", (data) => { + const chunk = data.toString(); + stdoutBuffer += chunk; + onStdout?.(chunk); + }); + } + if (child.stderr) { + child.stderr.on("data", (data) => { + const chunk = data.toString(); + stderrBuffer += chunk; + onStderr?.(chunk); + }); + } + child.on("close", (exitCode) => { + const durationMs = Date.now() - startTime; + if (timeoutId) { + clearTimeout(timeoutId); + } + if (isTimedOut) { + reject(new Error(`Process timed out after ${timeout}ms`)); + return; + } + resolve({ + stdout: stdoutBuffer, + stderr: stderrBuffer, + exitCode: exitCode || 0, + durationMs + }); + }); + child.on("error", (error41) => { + const durationMs = Date.now() - startTime; + if (timeoutId) { + clearTimeout(timeoutId); + } + console.error(`[spawn] Process spawn error: ${error41.message}`); + resolve({ + stdout: stdoutBuffer, + stderr: stderrBuffer, + exitCode: 1, + durationMs + }); + }); + if (input && child.stdin && stdio?.[0] !== "ignore") { + child.stdin.write(input); + child.stdin.end(); + } + }); +} + +// agents/gemini.ts +var assistantMessageBuffer = ""; +var messageHandlers3 = { + init: (_event) => { + log.debug(JSON.stringify(_event, null, 2)); + assistantMessageBuffer = ""; + }, + message: (event) => { + log.debug(JSON.stringify(event, null, 2)); + if (event.role === "assistant" && event.content?.trim()) { + if (event.delta) { + assistantMessageBuffer += event.content; + } else { + const message = event.content.trim(); + if (message) { + log.box(message, { title: "Gemini" }); + } + assistantMessageBuffer = ""; + } + } else if (event.role === "assistant" && !event.delta && assistantMessageBuffer.trim()) { + log.box(assistantMessageBuffer.trim(), { title: "Gemini" }); + assistantMessageBuffer = ""; + } + }, + tool_use: (event) => { + log.debug(JSON.stringify(event, null, 2)); + if (event.tool_name) { + log.toolCall({ + toolName: event.tool_name, + input: event.parameters || {} + }); + } + }, + tool_result: (event) => { + log.debug(JSON.stringify(event, null, 2)); + if (event.status === "error") { + const errorMsg = typeof event.output === "string" ? event.output : JSON.stringify(event.output); + log.warning(`Tool call failed: ${errorMsg}`); + } + }, + result: async (event) => { + log.debug(JSON.stringify(event, null, 2)); + if (assistantMessageBuffer.trim()) { + log.box(assistantMessageBuffer.trim(), { title: "Gemini" }); + assistantMessageBuffer = ""; + } + if (event.status === "success" && event.stats) { + const stats = event.stats; + const rows = [ + [ + { data: "Input Tokens", header: true }, + { data: "Output Tokens", header: true }, + { data: "Total Tokens", header: true }, + { data: "Tool Calls", header: true }, + { data: "Duration (ms)", header: true } + ], + [ + String(stats.input_tokens || 0), + String(stats.output_tokens || 0), + String(stats.total_tokens || 0), + String(stats.tool_calls || 0), + String(stats.duration_ms || 0) + ] + ]; + await log.summaryTable(rows); + } else if (event.status === "error") { + log.error(`Gemini CLI failed: ${JSON.stringify(event)}`); + } + } +}; +var gemini = agent({ + name: "gemini", + install: async (githubInstallationToken2) => { + return await installFromGithub({ + owner: "google-gemini", + repo: "gemini-cli", + assetName: "gemini.js", + ...githubInstallationToken2 && { githubInstallationToken: githubInstallationToken2 } + }); + }, + run: async ({ payload, apiKey, mcpServers, cliPath, repo }) => { + configureGeminiMcpServers({ mcpServers, cliPath }); + if (!apiKey) { + throw new Error("google_api_key or gemini_api_key is required for gemini agent"); + } + const sessionPrompt = addInstructions({ payload, repo }); + log.group("Full prompt", () => log.info(sessionPrompt)); + const args3 = payload.sandbox ? [ + "--allowed-tools", + "read_file,list_directory,search_file_content,glob,save_memory,write_todos", + "--allowed-mcp-server-names", + "gh_pullfrog", + "--output-format=stream-json", + "-p", + sessionPrompt + ] : ["--yolo", "--output-format=stream-json", "-p", sessionPrompt]; + if (payload.sandbox) { + log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); + } + let finalOutput2 = ""; + let stdoutBuffer = ""; + try { + const result = await spawn4({ + cmd: "node", + args: [cliPath, ...args3], + env: createAgentEnv({ + GEMINI_API_KEY: apiKey + }), + onStdout: async (chunk) => { + const text = chunk.toString(); + finalOutput2 += text; + stdoutBuffer += text; + const lines = stdoutBuffer.split("\n"); + stdoutBuffer = lines.pop() || ""; + for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed) continue; + log.debug(`[gemini stdout] ${trimmed}`); + try { + const event = JSON.parse(trimmed); + const handler2 = messageHandlers3[event.type]; + if (handler2) { + await handler2(event); + } + } catch { + log.debug(`[gemini] non-JSON stdout line: ${trimmed.substring(0, 200)}`); + } + } + }, + onStderr: (chunk) => { + const trimmed = chunk.trim(); + if (trimmed) { + log.debug(`[gemini stderr] ${trimmed}`); + log.warning(trimmed); + finalOutput2 += trimmed + "\n"; + } + } + }); + if (result.exitCode !== 0) { + const errorMessage = result.stderr || finalOutput2 || result.stdout || "Unknown error - no output from Gemini CLI"; + log.error(`Gemini CLI exited with code ${result.exitCode}: ${errorMessage}`); + return { + success: false, + error: errorMessage, + output: finalOutput2 || result.stdout || "" + }; + } + finalOutput2 = finalOutput2 || result.stdout || "Gemini CLI completed successfully."; + log.info("\u2713 Gemini CLI completed successfully"); + return { + success: true, + output: finalOutput2 + }; + } catch (error41) { + const errorMessage = error41 instanceof Error ? error41.message : String(error41); + log.error(`Failed to run Gemini CLI: ${errorMessage}`); + return { + success: false, + error: errorMessage, + output: finalOutput2 || "" + }; + } + } +}); +function configureGeminiMcpServers({ mcpServers }) { + const realHome = homedir3(); + const geminiConfigDir = join7(realHome, ".gemini"); + const settingsPath = join7(geminiConfigDir, "settings.json"); + mkdirSync4(geminiConfigDir, { recursive: true }); + let existingSettings = {}; + try { + const content = readFileSync2(settingsPath, "utf-8"); + existingSettings = JSON.parse(content); + } catch { + } + const geminiMcpServers = {}; + for (const [serverName, serverConfig] of Object.entries(mcpServers)) { + if (serverConfig.type !== "http") { + throw new Error( + `Unsupported MCP server type for Gemini: ${serverConfig.type || "unknown"}` + ); + } + geminiMcpServers[serverName] = { + httpUrl: serverConfig.url, + trust: true + // trust our own MCP server to avoid confirmation prompts + }; + log.info(`Adding MCP server '${serverName}' at ${serverConfig.url}...`); + } + const newSettings = { + ...existingSettings, + mcpServers: geminiMcpServers + }; + writeFileSync3(settingsPath, JSON.stringify(newSettings, null, 2), "utf-8"); + log.info(`\xBB MCP config written to ${settingsPath}`); +} + +// agents/opencode.ts +import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs"; +import { join as join8 } from "node:path"; +var opencode = agent({ + name: "opencode", + install: async () => { + return await installFromNpmTarball({ + packageName: "opencode-ai", + version: "latest", + executablePath: "bin/opencode", + installDependencies: true + }); + }, + run: async ({ payload, apiKey: _apiKey, apiKeys, mcpServers, cliPath, repo }) => { + const tempHome = process.env.PULLFROG_TEMP_DIR; + const configDir = join8(tempHome, ".config", "opencode"); + mkdirSync5(configDir, { recursive: true }); + configureOpenCode({ mcpServers, sandbox: payload.sandbox ?? false }); + const prompt = addInstructions({ payload, repo }); + log.group("Full prompt", () => log.info(prompt)); + const args3 = ["run", prompt, "--format", "json"]; + if (payload.sandbox) { + log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations"); + } + setupProcessAgentEnv({ HOME: tempHome }); + const env3 = { + ...Object.fromEntries( + Object.entries(process.env).filter( + ([key, value2]) => value2 !== void 0 && key !== "GITHUB_TOKEN" + ) + ), + HOME: tempHome, + XDG_CONFIG_HOME: join8(tempHome, ".config") + }; + for (const [key, value2] of Object.entries(apiKeys || {})) { + env3[key.toUpperCase()] = value2; + } + const repoDir = process.cwd(); + log.info(`\u{1F680} Starting OpenCode CLI: ${cliPath} ${args3.join(" ")}`); + log.info(`\u{1F4C1} Working directory: ${repoDir}`); + log.debug(`\u{1F3E0} HOME: ${env3.HOME}`); + log.debug(`\u{1F4CB} XDG_CONFIG_HOME: ${env3.XDG_CONFIG_HOME}`); + const startTime = Date.now(); + let lastActivityTime = startTime; + let eventCount = 0; + let output = ""; + let stdoutBuffer = ""; + const result = await spawn4({ + cmd: cliPath, + args: args3, + cwd: repoDir, + env: env3, + timeout: 6e5, + // 10 minutes timeout to prevent infinite hangs + stdio: ["ignore", "pipe", "pipe"], + onStdout: async (chunk) => { + const text = chunk.toString(); + output += text; + stdoutBuffer += text; + const lines = stdoutBuffer.split("\n"); + stdoutBuffer = lines.pop() || ""; + for (const line of lines) { + const trimmed = line.trim(); + if (!trimmed) { + continue; + } + try { + const event = JSON.parse(trimmed); + eventCount++; + log.debug(JSON.stringify(event, null, 2)); + const timeSinceLastActivity = Date.now() - lastActivityTime; + if (timeSinceLastActivity > 1e4) { + const activeToolCalls = toolCallTimings.size; + const toolCallInfo = activeToolCalls > 0 ? ` (waiting for ${activeToolCalls} tool call${activeToolCalls > 1 ? "s" : ""})` : " (OpenCode may be processing internally - LLM calls, planning, etc.)"; + log.warning( + `\u26A0\uFE0F No activity for ${(timeSinceLastActivity / 1e3).toFixed(1)}s${toolCallInfo} (${eventCount} events processed so far)` + ); + } + lastActivityTime = Date.now(); + const handler2 = messageHandlers4[event.type]; + if (handler2) { + await handler2(event); + } else { + log.info( + `\u{1F4CB} OpenCode event (unhandled): type=${event.type}, data=${JSON.stringify(event).substring(0, 500)}` + ); + } + } catch { + log.debug(`\xBB non-JSON stdout line: ${trimmed.substring(0, 200)}`); + } + } + }, + onStderr: (chunk) => { + try { + const parsed2 = JSON.parse(chunk); + log.debug(JSON.stringify(parsed2, null, 2)); + } catch { + } + const trimmed = chunk.trim(); + if (trimmed) { + log.warning(trimmed); + } + } + }); + const duration2 = Date.now() - startTime; + log.info(`\u2705 OpenCode CLI completed in ${duration2}ms with exit code ${result.exitCode}`); + if (!tokensLogged && (accumulatedTokens.input > 0 || accumulatedTokens.output > 0)) { + const totalTokens = accumulatedTokens.input + accumulatedTokens.output; + await log.summaryTable([ + [ + { data: "Input Tokens", header: true }, + { data: "Output Tokens", header: true }, + { data: "Total Tokens", header: true } + ], + [String(accumulatedTokens.input), String(accumulatedTokens.output), String(totalTokens)] + ]); + } + if (result.exitCode !== 0) { + const errorMessage = result.stderr || result.stdout || "Unknown error - no output from OpenCode CLI"; + log.error(`OpenCode CLI exited with code ${result.exitCode}: ${errorMessage}`); + log.debug(`OpenCode stdout: ${result.stdout?.substring(0, 500)}`); + log.debug(`OpenCode stderr: ${result.stderr?.substring(0, 500)}`); + return { + success: false, + output: finalOutput || output, + error: errorMessage + }; + } + return { + success: true, + output: finalOutput || output + }; + } +}); +function configureOpenCode({ mcpServers, sandbox }) { + const tempHome = process.env.PULLFROG_TEMP_DIR; + const configDir = join8(tempHome, ".config", "opencode"); + mkdirSync5(configDir, { recursive: true }); + const configPath = join8(configDir, "opencode.json"); + const opencodeMcpServers = {}; + for (const [serverName, serverConfig] of Object.entries(mcpServers)) { + if (serverConfig.type !== "http") { + log.error( + `unsupported MCP server type for OpenCode: ${serverConfig.type || "unknown"}` + ); + throw new Error( + `Unsupported MCP server type for OpenCode: ${serverConfig.type || "unknown"}` + ); + } + opencodeMcpServers[serverName] = { + type: "remote", + url: serverConfig.url + }; + } + const permission = sandbox ? { + edit: "deny", + bash: "deny", + webfetch: "deny", + doom_loop: "allow", + external_directory: "allow" + } : { + edit: "allow", + bash: "allow", + webfetch: "allow", + doom_loop: "allow", + external_directory: "allow" + }; + const config2 = { + mcp: opencodeMcpServers, + permission + }; + const configJson = JSON.stringify(config2, null, 2); + try { + writeFileSync4(configPath, configJson, "utf-8"); + } catch (error41) { + log.error( + `failed to write OpenCode config to ${configPath}: ${error41 instanceof Error ? error41.message : String(error41)}` + ); + throw error41; + } + log.info(`\xBB OpenCode config written to ${configPath} (sandbox: ${sandbox})`); + log.debug(`OpenCode config contents: +${configJson}`); +} +var finalOutput = ""; +var accumulatedTokens = { input: 0, output: 0 }; +var tokensLogged = false; +var toolCallTimings = /* @__PURE__ */ new Map(); +var currentStepId = null; +var currentStepType = null; +var stepHistory = []; +var messageHandlers4 = { + init: (event) => { + log.info( + `\u{1F535} OpenCode init: session_id=${event.session_id || "unknown"}, model=${event.model || "unknown"}` + ); + log.info(`\u{1F535} OpenCode init event (full): ${JSON.stringify(event)}`); + finalOutput = ""; + accumulatedTokens = { input: 0, output: 0 }; + tokensLogged = false; + }, + message: (event) => { + if (event.role === "assistant" && event.content?.trim()) { + const message = event.content.trim(); + if (message) { + if (event.delta) { + log.info( + `\u{1F4AD} OpenCode thinking: ${message.substring(0, 300)}${message.length > 300 ? "..." : ""}` + ); + } else { + log.info( + `\u{1F4AC} OpenCode message (${event.role}): ${message.substring(0, 100)}${message.length > 100 ? "..." : ""}` + ); + finalOutput = message; + } + } + } else if (event.role === "user") { + log.info( + `\u{1F4AC} OpenCode message (${event.role}): ${event.content?.substring(0, 100) || ""}${event.content && event.content.length > 100 ? "..." : ""}` + ); + } + }, + text: (event) => { + if (event.part?.text?.trim()) { + const message = event.part.text.trim(); + log.box(message, { title: "OpenCode" }); + finalOutput = message; + } + }, + step_start: (event) => { + const stepType = event.part?.type || "unknown"; + const stepId = event.part?.id || "unknown"; + currentStepId = stepId; + currentStepType = stepType; + stepHistory.push({ stepId, stepType, toolCalls: [] }); + }, + step_finish: async (event) => { + const stepId = event.part?.id || "unknown"; + const eventTokens = event.part?.tokens; + if (eventTokens) { + const inputTokens = eventTokens.input || 0; + const outputTokens = eventTokens.output || 0; + accumulatedTokens.input += inputTokens; + accumulatedTokens.output += outputTokens; + } + if (currentStepId === stepId) { + currentStepId = null; + currentStepType = null; + } + }, + tool_use: (event) => { + const toolName = event.part?.tool; + const toolId = event.part?.callID; + const parameters = event.part?.state?.input; + const status = event.part?.state?.status; + const output = event.part?.state?.output; + if (!toolName || !toolId) { + log.debug(`\xBB tool_use event missing toolName or toolId: ${JSON.stringify(event)}`); + } + if (toolName && toolId) { + if (stepHistory.length > 0) { + stepHistory[stepHistory.length - 1].toolCalls.push(toolName); + } + log.toolCall({ + toolName, + input: parameters || {} + }); + if (status === "completed" && output) { + log.debug(` output: ${output}`); + } + } + }, + tool_result: (event) => { + const toolId = event.part?.callID || event.tool_id; + const status = event.part?.state?.status || event.status || "unknown"; + const output = event.part?.state?.output || event.output; + if (toolId) { + const toolStartTime = toolCallTimings.get(toolId); + if (toolStartTime) { + const toolDuration = Date.now() - toolStartTime; + toolCallTimings.delete(toolId); + const stepContext = currentStepId ? ` (step=${currentStepType || "unknown"})` : ""; + log.info( + `\u{1F527} OpenCode tool_result${stepContext}: id=${toolId}, status=${status}, duration=${toolDuration}ms` + ); + if (output) { + log.debug(` output: ${typeof output === "string" ? output : JSON.stringify(output)}`); + } + if (toolDuration > 5e3) { + log.warning( + `\u26A0\uFE0F Tool call took ${(toolDuration / 1e3).toFixed(1)}s - this may indicate network latency or slow processing` + ); + } + } + } + if (status === "error") { + const errorMsg = typeof output === "string" ? output : JSON.stringify(output); + log.warning(`\u274C Tool call failed: ${errorMsg}`); + } + }, + result: async (event) => { + const status = event.status || "unknown"; + const duration2 = event.stats?.duration_ms || 0; + const toolCalls = event.stats?.tool_calls || 0; + log.info( + `\u{1F3C1} OpenCode result: status=${status}, duration=${duration2}ms, tool_calls=${toolCalls}` + ); + if (event.status === "error") { + log.error(`\u274C OpenCode CLI failed: ${JSON.stringify(event)}`); + } else { + const inputTokens = event.stats?.input_tokens || accumulatedTokens.input || 0; + const outputTokens = event.stats?.output_tokens || accumulatedTokens.output || 0; + const totalTokens = event.stats?.total_tokens || inputTokens + outputTokens; + log.info( + `\u{1F4CA} OpenCode final stats: input=${inputTokens}, output=${outputTokens}, total=${totalTokens}, tool_calls=${toolCalls}, duration=${duration2}ms` + ); + if ((inputTokens > 0 || outputTokens > 0) && !tokensLogged) { + await log.summaryTable([ + [ + { data: "Input Tokens", header: true }, + { data: "Output Tokens", header: true }, + { data: "Total Tokens", header: true } + ], + [String(inputTokens), String(outputTokens), String(totalTokens)] + ]); + tokensLogged = true; + } + } + } +}; + +// agents/index.ts +var agents = { + claude, + codex, + cursor, + gemini, + opencode +}; + +// main.ts +import { mkdtemp as mkdtemp2 } from "node:fs/promises"; +import { tmpdir as tmpdir2 } from "node:os"; +import { join as join12 } from "node:path"; + // utils/api.ts var DEFAULT_REPO_SETTINGS = { defaultAgent: null, @@ -98677,8 +100204,7 @@ async function ensureProgressCommentUpdated(payload) { return; } const repoContext = parseRepoContext(); - const token = getGitHubInstallationToken(); - const octokit = new Octokit2({ auth: token }); + const octokit = createOctokit(getGitHubInstallationToken()); try { const existingComment = await octokit.rest.issues.getComment({ owner: repoContext.owner, @@ -118352,7 +119878,7 @@ var require_formats3 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/ajv@6.1 hostname: HOSTNAME, ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex3, + regex: regex4, uuid: UUID, "json-pointer": JSON_POINTER, "json-pointer-uri-fragment": JSON_POINTER_URI_FRAGMENT, @@ -118370,7 +119896,7 @@ var require_formats3 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/ajv@6.1 hostname: HOSTNAME, ipv4: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/, ipv6: /^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i, - regex: regex3, + regex: regex4, uuid: UUID, "json-pointer": JSON_POINTER, "json-pointer-uri-fragment": JSON_POINTER_URI_FRAGMENT, @@ -118406,7 +119932,7 @@ var require_formats3 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/ajv@6.1 return NOT_URI_FRAGMENT.test(str) && URI.test(str); } var Z_ANCHOR = /[^\\]\\Z/; - function regex3(str) { + function regex4(str) { if (Z_ANCHOR.test(str)) return false; try { new RegExp(str); @@ -121145,9 +122671,9 @@ var require_ajv3 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/ajv@6.12.6/ function setLogger(self2) { var logger = self2._opts.logger; if (logger === false) self2.logger = { - log: noop3, - warn: noop3, - error: noop3 + log: noop4, + warn: noop4, + error: noop4 }; else { if (logger === void 0) logger = console; @@ -121155,7 +122681,7 @@ var require_ajv3 = /* @__PURE__ */ __commonJS3({ "node_modules/.pnpm/ajv@6.12.6/ self2.logger = logger; } } - function noop3() { + function noop4() { } }) }); var import_ajv$1 = /* @__PURE__ */ __toESM3(require_ajv3(), 1); @@ -121167,11 +122693,11 @@ var ParseError2 = class extends Error { super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line; } }; -function noop2(_arg) { +function noop3(_arg) { } function createParser(callbacks) { if (typeof callbacks == "function") throw new TypeError("`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"); - const { onEvent = noop2, onError = noop2, onRetry = noop2, onComment } = callbacks; + const { onEvent = noop3, onError = noop3, onRetry = noop3, onComment } = callbacks; let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = ""; function feed(newChunk) { const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`); @@ -124889,8 +126415,7 @@ ${error41}` : `\u274C ${error41}`; return; } const repoContext = parseRepoContext(); - const token = getGitHubInstallationToken(); - const octokit = new Octokit2({ auth: token }); + const octokit = createOctokit(getGitHubInstallationToken()); await octokit.rest.issues.updateComment({ owner: repoContext.owner, repo: repoContext.name, @@ -125169,7 +126694,7 @@ async function initializeGitHub() { log.info(`\u{1F438} Running pullfrog/action@${package_default.version}...`); const token = await setupGitHubInstallationToken(); const { owner, name } = parseRepoContext(); - const octokit = new Octokit2({ auth: token }); + const octokit = createOctokit(token); const [repoResponse, repoSettings] = await Promise.all([ octokit.repos.get({ owner, repo: name }), fetchRepoSettings({ token, repoContext: { owner, name } }) diff --git a/main.ts b/main.ts index 0178b32..e4ceb97 100644 --- a/main.ts +++ b/main.ts @@ -19,6 +19,7 @@ import { fetchRepoSettings, fetchWorkflowRunInfo, type RepoSettings } from "./ut import { log } from "./utils/cli.ts"; import { reportErrorToComment } from "./utils/errorReport.ts"; import { + createOctokit, parseRepoContext, revokeGitHubInstallationToken, setupGitHubInstallationToken, @@ -354,7 +355,7 @@ async function initializeGitHub(): Promise { const token = await setupGitHubInstallationToken(); const { owner, name } = parseRepoContext(); - const octokit = new Octokit({ auth: token }); + const octokit = createOctokit(token); // fetch repo data and settings in parallel const [repoResponse, repoSettings] = await Promise.all([ diff --git a/mcp/comment.ts b/mcp/comment.ts index e16a947..2ffa2b4 100644 --- a/mcp/comment.ts +++ b/mcp/comment.ts @@ -1,11 +1,10 @@ -import { Octokit } from "@octokit/rest"; import { type } from "arktype"; import type { Payload } from "../external.ts"; import { agentsManifest } from "../external.ts"; import type { ToolContext } from "../main.ts"; import { fetchWorkflowRunInfo } from "../utils/api.ts"; import { buildPullfrogFooter, stripExistingFooter } from "../utils/buildPullfrogFooter.ts"; -import { getGitHubInstallationToken, parseRepoContext } from "../utils/github.ts"; +import { createOctokit, getGitHubInstallationToken, parseRepoContext, type OctokitWithPlugins } from "../utils/github.ts"; import { execute, tool } from "./shared.ts"; /** @@ -17,7 +16,7 @@ export const LEAPING_INTO_ACTION_PREFIX = "Leaping into action"; interface BuildCommentFooterParams { payload: Payload; - octokit?: Octokit | undefined; + octokit?: OctokitWithPlugins | undefined; customParts?: string[] | undefined; } @@ -80,7 +79,7 @@ function buildImplementPlanLink( return `[Implement plan ➔](${apiUrl}/trigger/${owner}/${repo}/${issueNumber}?action=implement&comment_id=${commentId})`; } -async function addFooter(body: string, payload: Payload, octokit?: Octokit): Promise { +async function addFooter(body: string, payload: Payload, octokit?: OctokitWithPlugins): Promise { const bodyWithoutFooter = stripExistingFooter(body); const footer = await buildCommentFooter({ payload, octokit }); return `${bodyWithoutFooter}${footer}`; @@ -408,8 +407,7 @@ export async function ensureProgressCommentUpdated(payload?: Payload): Promise= 20'} @@ -407,6 +416,12 @@ packages: peerDependencies: '@octokit/core': '>=6' + '@octokit/plugin-throttling@11.0.3': + resolution: {integrity: sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': ^7.0.0 + '@octokit/request-error@5.1.1': resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} engines: {node: '>= 18'} @@ -436,6 +451,9 @@ packages: '@octokit/types@15.0.0': resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==} + '@octokit/types@16.0.0': + resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} + '@octokit/webhooks-types@7.6.1': resolution: {integrity: sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw==} @@ -463,6 +481,9 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@toon-format/toon@1.4.0': + resolution: {integrity: sha512-bjdhhIPjnX2oVk+pKy/nD3bwuESDLX/5fwW0TxwpV7Q4PVNkiRSv1S0sPeuy9TI4PfAlulow1HShdmMTnYvoLg==} + '@types/node@24.7.2': resolution: {integrity: sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==} @@ -515,6 +536,9 @@ packages: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} + bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -1347,6 +1371,8 @@ snapshots: '@octokit/openapi-types@26.0.0': {} + '@octokit/openapi-types@27.0.0': {} + '@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)': dependencies: '@octokit/core': 7.0.5 @@ -1371,6 +1397,12 @@ snapshots: '@octokit/core': 7.0.5 '@octokit/types': 15.0.0 + '@octokit/plugin-throttling@11.0.3(@octokit/core@7.0.5)': + dependencies: + '@octokit/core': 7.0.5 + '@octokit/types': 16.0.0 + bottleneck: 2.19.5 + '@octokit/request-error@5.1.1': dependencies: '@octokit/types': 13.10.0 @@ -1415,6 +1447,10 @@ snapshots: dependencies: '@octokit/openapi-types': 26.0.0 + '@octokit/types@16.0.0': + dependencies: + '@octokit/openapi-types': 27.0.0 + '@octokit/webhooks-types@7.6.1': {} '@openai/codex-sdk@0.58.0': {} @@ -1437,6 +1473,8 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@toon-format/toon@1.4.0': {} + '@types/node@24.7.2': dependencies: undici-types: 7.14.0 @@ -1502,6 +1540,8 @@ snapshots: transitivePeerDependencies: - supports-color + bottleneck@2.19.5: {} + bytes@3.1.2: {} call-bind-apply-helpers@1.0.2: diff --git a/utils/errorReport.ts b/utils/errorReport.ts index b0a23f3..873d8cf 100644 --- a/utils/errorReport.ts +++ b/utils/errorReport.ts @@ -1,6 +1,5 @@ -import { Octokit } from "@octokit/rest"; import { fetchWorkflowRunInfo } from "./api.ts"; -import { getGitHubInstallationToken, parseRepoContext } from "./github.ts"; +import { createOctokit, getGitHubInstallationToken, parseRepoContext } from "./github.ts"; /** * Get progress comment ID from environment variable or database. @@ -55,8 +54,7 @@ export async function reportErrorToComment({ // update comment directly using GitHub API const repoContext = parseRepoContext(); - const token = getGitHubInstallationToken(); - const octokit = new Octokit({ auth: token }); + const octokit = createOctokit(getGitHubInstallationToken()); await octokit.rest.issues.updateComment({ owner: repoContext.owner, diff --git a/utils/github.ts b/utils/github.ts index 614d1ec..e09deba 100644 --- a/utils/github.ts +++ b/utils/github.ts @@ -1,5 +1,7 @@ -import { createSign } from "node:crypto"; import * as core from "@actions/core"; +import { throttling } from "@octokit/plugin-throttling"; +import { Octokit } from "@octokit/rest"; +import { createSign } from "node:crypto"; import { log } from "./cli.ts"; import { retry } from "./retry.ts"; @@ -311,3 +313,22 @@ export function parseRepoContext(): RepoContext { return { owner, name }; } + +export type OctokitWithPlugins = InstanceType>> + +export function createOctokit(token: string): OctokitWithPlugins { + // `OctokitWithPlugins` initialization based on https://github.com/actions/toolkit/blob/2506e78e82fbd2f9e94d63e75f5309118c8de1b1/packages/github/src/github.ts#L15-L22 + // we can't use it directly because it's stuck on `@octokit/core@v5` and we use the hottest `@octokit/core@v7` + const OctokitWithPlugins = Octokit.plugin(throttling); + return new OctokitWithPlugins({ + auth: token, + throttle: { + onRateLimit: (retryAfter, options, octokit, retryCount) => { + return retryCount <= 2; + }, + onSecondaryRateLimit: (retryAfter, options, octokit, retryCount) => { + return retryCount <= 2; + }, + } + }); +} diff --git a/utils/setup.ts b/utils/setup.ts index f254b5a..66a8458 100644 --- a/utils/setup.ts +++ b/utils/setup.ts @@ -1,10 +1,10 @@ import { execSync } from "node:child_process"; import { existsSync, rmSync } from "node:fs"; -import type { Octokit } from "@octokit/rest"; import type { Payload } from "../external.ts"; import type { ToolState } from "../main.ts"; import { checkoutPrBranch } from "../mcp/checkout.ts"; import { log } from "./cli.ts"; +import type { OctokitWithPlugins } from "./github.ts"; import { $ } from "./shell.ts"; export interface SetupOptions { @@ -66,7 +66,7 @@ interface SetupGitAuthParams { owner: string; name: string; payload: Payload; - octokit: Octokit; + octokit: OctokitWithPlugins; toolState: ToolState; }