pullfrog 0.1.95 → 0.1.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/agents/opencodePlugin.d.ts +4 -2
- package/dist/cli.mjs +1415 -1279
- package/dist/external.d.ts +1 -1
- package/dist/index.js +1358 -1231
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal.js +107 -42
- package/dist/mcp/checkout.d.ts +2 -0
- package/dist/mcp/comment.d.ts +3 -0
- package/dist/models.d.ts +5 -5
- package/dist/toolState.d.ts +6 -4
- package/dist/utils/apiKeys.d.ts +26 -0
- package/dist/utils/changeImpact.d.ts +1 -0
- package/dist/utils/codexHome.d.ts +4 -6
- package/dist/utils/gitAuth.d.ts +1 -0
- package/dist/utils/github.d.ts +1 -1
- package/dist/utils/oauthWriteback.d.ts +5 -0
- package/dist/utils/openCodeModels.d.ts +19 -2
- package/dist/utils/patchWorkflowRunFields.d.ts +8 -1
- package/dist/utils/providerErrors.d.ts +4 -1
- package/dist/utils/runContext.d.ts +8 -0
- package/dist/utils/runContextData.d.ts +2 -0
- package/dist/utils/runErrorRenderer.d.ts +25 -9
- package/dist/utils/runStatusCheck.d.ts +11 -0
- package/dist/utils/statusChecks.d.ts +2 -1
- package/dist/utils/subprocess.d.ts +2 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1415,9 +1415,9 @@ var require_timers = __commonJS({
|
|
|
1415
1415
|
}
|
|
1416
1416
|
}
|
|
1417
1417
|
var Timeout = class {
|
|
1418
|
-
constructor(callback,
|
|
1418
|
+
constructor(callback, delay3, opaque) {
|
|
1419
1419
|
this.callback = callback;
|
|
1420
|
-
this.delay =
|
|
1420
|
+
this.delay = delay3;
|
|
1421
1421
|
this.opaque = opaque;
|
|
1422
1422
|
this.state = -2;
|
|
1423
1423
|
this.refresh();
|
|
@@ -1436,8 +1436,8 @@ var require_timers = __commonJS({
|
|
|
1436
1436
|
}
|
|
1437
1437
|
};
|
|
1438
1438
|
module.exports = {
|
|
1439
|
-
setTimeout(callback,
|
|
1440
|
-
return
|
|
1439
|
+
setTimeout(callback, delay3, opaque) {
|
|
1440
|
+
return delay3 < 1e3 ? setTimeout(callback, delay3, opaque) : new Timeout(callback, delay3, opaque);
|
|
1441
1441
|
},
|
|
1442
1442
|
clearTimeout(timeout) {
|
|
1443
1443
|
if (timeout instanceof Timeout) {
|
|
@@ -5717,7 +5717,7 @@ var require_request = __commonJS({
|
|
|
5717
5717
|
method,
|
|
5718
5718
|
body,
|
|
5719
5719
|
headers,
|
|
5720
|
-
query,
|
|
5720
|
+
query: query2,
|
|
5721
5721
|
idempotent,
|
|
5722
5722
|
blocking,
|
|
5723
5723
|
upgrade,
|
|
@@ -5794,7 +5794,7 @@ var require_request = __commonJS({
|
|
|
5794
5794
|
this.completed = false;
|
|
5795
5795
|
this.aborted = false;
|
|
5796
5796
|
this.upgrade = upgrade || null;
|
|
5797
|
-
this.path =
|
|
5797
|
+
this.path = query2 ? util2.buildURL(path4, query2) : path4;
|
|
5798
5798
|
this.origin = origin;
|
|
5799
5799
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
5800
5800
|
this.blocking = blocking == null ? false : blocking;
|
|
@@ -10508,13 +10508,13 @@ var require_mock_utils = __commonJS({
|
|
|
10508
10508
|
}
|
|
10509
10509
|
}
|
|
10510
10510
|
function buildKey(opts) {
|
|
10511
|
-
const { path: path4, method, body, headers, query } = opts;
|
|
10511
|
+
const { path: path4, method, body, headers, query: query2 } = opts;
|
|
10512
10512
|
return {
|
|
10513
10513
|
path: path4,
|
|
10514
10514
|
method,
|
|
10515
10515
|
body,
|
|
10516
10516
|
headers,
|
|
10517
|
-
query
|
|
10517
|
+
query: query2
|
|
10518
10518
|
};
|
|
10519
10519
|
}
|
|
10520
10520
|
function generateKeyValues(data) {
|
|
@@ -10541,7 +10541,7 @@ var require_mock_utils = __commonJS({
|
|
|
10541
10541
|
if (mockDispatch2.data.callback) {
|
|
10542
10542
|
mockDispatch2.data = { ...mockDispatch2.data, ...mockDispatch2.data.callback(opts) };
|
|
10543
10543
|
}
|
|
10544
|
-
const { data: { statusCode, data, headers, trailers, error: error49 }, delay:
|
|
10544
|
+
const { data: { statusCode, data, headers, trailers, error: error49 }, delay: delay3, persist } = mockDispatch2;
|
|
10545
10545
|
const { timesInvoked, times } = mockDispatch2;
|
|
10546
10546
|
mockDispatch2.consumed = !persist && timesInvoked >= times;
|
|
10547
10547
|
mockDispatch2.pending = timesInvoked < times;
|
|
@@ -10550,10 +10550,10 @@ var require_mock_utils = __commonJS({
|
|
|
10550
10550
|
handler2.onError(error49);
|
|
10551
10551
|
return true;
|
|
10552
10552
|
}
|
|
10553
|
-
if (typeof
|
|
10553
|
+
if (typeof delay3 === "number" && delay3 > 0) {
|
|
10554
10554
|
setTimeout(() => {
|
|
10555
10555
|
handleReply(this[kDispatches]);
|
|
10556
|
-
},
|
|
10556
|
+
}, delay3);
|
|
10557
10557
|
} else {
|
|
10558
10558
|
handleReply(this[kDispatches]);
|
|
10559
10559
|
}
|
|
@@ -26388,8 +26388,8 @@ var require_coerce = __commonJS({
|
|
|
26388
26388
|
const minor = match3[3] || "0";
|
|
26389
26389
|
const patch = match3[4] || "0";
|
|
26390
26390
|
const prerelease = options.includePrerelease && match3[5] ? `-${match3[5]}` : "";
|
|
26391
|
-
const
|
|
26392
|
-
return parse6(`${major}.${minor}.${patch}${prerelease}${
|
|
26391
|
+
const build4 = options.includePrerelease && match3[6] ? `+${match3[6]}` : "";
|
|
26392
|
+
return parse6(`${major}.${minor}.${patch}${prerelease}${build4}`, options);
|
|
26393
26393
|
};
|
|
26394
26394
|
module.exports = coerce;
|
|
26395
26395
|
}
|
|
@@ -40308,9 +40308,9 @@ var require_timers2 = __commonJS({
|
|
|
40308
40308
|
* before the specified function or code is executed.
|
|
40309
40309
|
* @param {*} arg
|
|
40310
40310
|
*/
|
|
40311
|
-
constructor(callback,
|
|
40311
|
+
constructor(callback, delay3, arg) {
|
|
40312
40312
|
this._onTimeout = callback;
|
|
40313
|
-
this._idleTimeout =
|
|
40313
|
+
this._idleTimeout = delay3;
|
|
40314
40314
|
this._timerArg = arg;
|
|
40315
40315
|
this.refresh();
|
|
40316
40316
|
}
|
|
@@ -40355,8 +40355,8 @@ var require_timers2 = __commonJS({
|
|
|
40355
40355
|
* when the timer expires.
|
|
40356
40356
|
* @returns {NodeJS.Timeout|FastTimer}
|
|
40357
40357
|
*/
|
|
40358
|
-
setTimeout(callback,
|
|
40359
|
-
return
|
|
40358
|
+
setTimeout(callback, delay3, arg) {
|
|
40359
|
+
return delay3 <= RESOLUTION_MS ? setTimeout(callback, delay3, arg) : new FastTimer(callback, delay3, arg);
|
|
40360
40360
|
},
|
|
40361
40361
|
/**
|
|
40362
40362
|
* The clearTimeout method cancels an instantiated Timer previously created
|
|
@@ -40382,8 +40382,8 @@ var require_timers2 = __commonJS({
|
|
|
40382
40382
|
* when the timer expires.
|
|
40383
40383
|
* @returns {FastTimer}
|
|
40384
40384
|
*/
|
|
40385
|
-
setFastTimeout(callback,
|
|
40386
|
-
return new FastTimer(callback,
|
|
40385
|
+
setFastTimeout(callback, delay3, arg) {
|
|
40386
|
+
return new FastTimer(callback, delay3, arg);
|
|
40387
40387
|
},
|
|
40388
40388
|
/**
|
|
40389
40389
|
* The clearTimeout method cancels an instantiated FastTimer previously
|
|
@@ -40409,8 +40409,8 @@ var require_timers2 = __commonJS({
|
|
|
40409
40409
|
* @deprecated
|
|
40410
40410
|
* @param {number} [delay=0] The delay in milliseconds to add to the now value.
|
|
40411
40411
|
*/
|
|
40412
|
-
tick(
|
|
40413
|
-
fastNow +=
|
|
40412
|
+
tick(delay3 = 0) {
|
|
40413
|
+
fastNow += delay3 - RESOLUTION_MS + 1;
|
|
40414
40414
|
onTick();
|
|
40415
40415
|
onTick();
|
|
40416
40416
|
},
|
|
@@ -42234,7 +42234,7 @@ var require_request3 = __commonJS({
|
|
|
42234
42234
|
method,
|
|
42235
42235
|
body,
|
|
42236
42236
|
headers,
|
|
42237
|
-
query,
|
|
42237
|
+
query: query2,
|
|
42238
42238
|
idempotent,
|
|
42239
42239
|
blocking,
|
|
42240
42240
|
upgrade,
|
|
@@ -42326,7 +42326,7 @@ var require_request3 = __commonJS({
|
|
|
42326
42326
|
this.completed = false;
|
|
42327
42327
|
this.aborted = false;
|
|
42328
42328
|
this.upgrade = upgrade || null;
|
|
42329
|
-
this.path =
|
|
42329
|
+
this.path = query2 ? serializePathWithQuery(path4, query2) : path4;
|
|
42330
42330
|
this.origin = origin;
|
|
42331
42331
|
this.protocol = getProtocolFromUrlString(origin);
|
|
42332
42332
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -46893,21 +46893,21 @@ var require_client_h1 = __commonJS({
|
|
|
46893
46893
|
this.connection = "";
|
|
46894
46894
|
this.maxResponseSize = client2[kMaxResponseSize];
|
|
46895
46895
|
}
|
|
46896
|
-
setTimeout(
|
|
46897
|
-
if (
|
|
46896
|
+
setTimeout(delay3, type2) {
|
|
46897
|
+
if (delay3 !== this.timeoutValue || type2 & USE_FAST_TIMER ^ this.timeoutType & USE_FAST_TIMER) {
|
|
46898
46898
|
if (this.timeout) {
|
|
46899
46899
|
timers.clearTimeout(this.timeout);
|
|
46900
46900
|
this.timeout = null;
|
|
46901
46901
|
}
|
|
46902
|
-
if (
|
|
46902
|
+
if (delay3) {
|
|
46903
46903
|
if (type2 & USE_FAST_TIMER) {
|
|
46904
|
-
this.timeout = timers.setFastTimeout(onParserTimeout,
|
|
46904
|
+
this.timeout = timers.setFastTimeout(onParserTimeout, delay3, this.timeoutWeakRef);
|
|
46905
46905
|
} else {
|
|
46906
|
-
this.timeout = setTimeout(onParserTimeout,
|
|
46906
|
+
this.timeout = setTimeout(onParserTimeout, delay3, this.timeoutWeakRef);
|
|
46907
46907
|
this.timeout?.unref();
|
|
46908
46908
|
}
|
|
46909
46909
|
}
|
|
46910
|
-
this.timeoutValue =
|
|
46910
|
+
this.timeoutValue = delay3;
|
|
46911
46911
|
} else if (this.timeout) {
|
|
46912
46912
|
if (this.timeout.refresh) {
|
|
46913
46913
|
this.timeout.refresh();
|
|
@@ -52901,11 +52901,11 @@ var require_mock_utils2 = __commonJS({
|
|
|
52901
52901
|
}
|
|
52902
52902
|
return true;
|
|
52903
52903
|
}
|
|
52904
|
-
function normalizeSearchParams(
|
|
52905
|
-
if (typeof
|
|
52906
|
-
return
|
|
52904
|
+
function normalizeSearchParams(query2) {
|
|
52905
|
+
if (typeof query2 !== "string") {
|
|
52906
|
+
return query2;
|
|
52907
52907
|
}
|
|
52908
|
-
const originalQp = new URLSearchParams(
|
|
52908
|
+
const originalQp = new URLSearchParams(query2);
|
|
52909
52909
|
const normalizedQp = new URLSearchParams();
|
|
52910
52910
|
for (let [key, value2] of originalQp.entries()) {
|
|
52911
52911
|
key = key.replace("[]", "");
|
|
@@ -53013,13 +53013,13 @@ var require_mock_utils2 = __commonJS({
|
|
|
53013
53013
|
return path4;
|
|
53014
53014
|
}
|
|
53015
53015
|
function buildKey(opts) {
|
|
53016
|
-
const { path: path4, method, body, headers, query } = opts;
|
|
53016
|
+
const { path: path4, method, body, headers, query: query2 } = opts;
|
|
53017
53017
|
return {
|
|
53018
53018
|
path: path4,
|
|
53019
53019
|
method,
|
|
53020
53020
|
body,
|
|
53021
53021
|
headers,
|
|
53022
|
-
query
|
|
53022
|
+
query: query2
|
|
53023
53023
|
};
|
|
53024
53024
|
}
|
|
53025
53025
|
function generateKeyValues(data) {
|
|
@@ -53056,7 +53056,7 @@ var require_mock_utils2 = __commonJS({
|
|
|
53056
53056
|
if (mockDispatch2.data.callback) {
|
|
53057
53057
|
mockDispatch2.data = { ...mockDispatch2.data, ...mockDispatch2.data.callback(opts) };
|
|
53058
53058
|
}
|
|
53059
|
-
const { data: { statusCode, data, headers, trailers, error: error49 }, delay:
|
|
53059
|
+
const { data: { statusCode, data, headers, trailers, error: error49 }, delay: delay3, persist } = mockDispatch2;
|
|
53060
53060
|
const { timesInvoked, times } = mockDispatch2;
|
|
53061
53061
|
mockDispatch2.consumed = !persist && timesInvoked >= times;
|
|
53062
53062
|
mockDispatch2.pending = timesInvoked < times;
|
|
@@ -53079,11 +53079,11 @@ var require_mock_utils2 = __commonJS({
|
|
|
53079
53079
|
handler2.onError(err);
|
|
53080
53080
|
}
|
|
53081
53081
|
handler2.onConnect?.(abort, null);
|
|
53082
|
-
if (typeof
|
|
53082
|
+
if (typeof delay3 === "number" && delay3 > 0) {
|
|
53083
53083
|
timer = setTimeout(() => {
|
|
53084
53084
|
timer = null;
|
|
53085
53085
|
handleReply(this[kDispatches]);
|
|
53086
|
-
},
|
|
53086
|
+
}, delay3);
|
|
53087
53087
|
} else {
|
|
53088
53088
|
handleReply(this[kDispatches]);
|
|
53089
53089
|
}
|
|
@@ -53453,13 +53453,13 @@ var require_mock_call_history = __commonJS({
|
|
|
53453
53453
|
function makeFilterCalls(parameterName) {
|
|
53454
53454
|
return (parameterValue, logs) => {
|
|
53455
53455
|
if (typeof parameterValue === "string" || parameterValue == null) {
|
|
53456
|
-
return logs.filter((
|
|
53457
|
-
return
|
|
53456
|
+
return logs.filter((log2) => {
|
|
53457
|
+
return log2[parameterName] === parameterValue;
|
|
53458
53458
|
});
|
|
53459
53459
|
}
|
|
53460
53460
|
if (parameterValue instanceof RegExp) {
|
|
53461
|
-
return logs.filter((
|
|
53462
|
-
return parameterValue.test(
|
|
53461
|
+
return logs.filter((log2) => {
|
|
53462
|
+
return parameterValue.test(log2[parameterName]);
|
|
53463
53463
|
});
|
|
53464
53464
|
}
|
|
53465
53465
|
throw new InvalidArgumentError(`${parameterName} parameter should be one of string, regexp, undefined or null`);
|
|
@@ -53554,8 +53554,8 @@ var require_mock_call_history = __commonJS({
|
|
|
53554
53554
|
return this.logs.filter(criteria);
|
|
53555
53555
|
}
|
|
53556
53556
|
if (criteria instanceof RegExp) {
|
|
53557
|
-
return this.logs.filter((
|
|
53558
|
-
return criteria.test(
|
|
53557
|
+
return this.logs.filter((log2) => {
|
|
53558
|
+
return criteria.test(log2.toString());
|
|
53559
53559
|
});
|
|
53560
53560
|
}
|
|
53561
53561
|
if (typeof criteria === "object" && criteria !== null) {
|
|
@@ -53605,13 +53605,13 @@ var require_mock_call_history = __commonJS({
|
|
|
53605
53605
|
this.logs = [];
|
|
53606
53606
|
}
|
|
53607
53607
|
[kMockCallHistoryAddLog](requestInit) {
|
|
53608
|
-
const
|
|
53609
|
-
this.logs.push(
|
|
53610
|
-
return
|
|
53608
|
+
const log2 = new MockCallHistoryLog(requestInit);
|
|
53609
|
+
this.logs.push(log2);
|
|
53610
|
+
return log2;
|
|
53611
53611
|
}
|
|
53612
53612
|
*[Symbol.iterator]() {
|
|
53613
|
-
for (const
|
|
53614
|
-
yield
|
|
53613
|
+
for (const log2 of this.calls()) {
|
|
53614
|
+
yield log2;
|
|
53615
53615
|
}
|
|
53616
53616
|
}
|
|
53617
53617
|
};
|
|
@@ -56023,18 +56023,18 @@ var require_cache2 = __commonJS({
|
|
|
56023
56023
|
}
|
|
56024
56024
|
}
|
|
56025
56025
|
}
|
|
56026
|
-
function makeDeduplicationKey(
|
|
56026
|
+
function makeDeduplicationKey(cacheKey3, excludeHeaders) {
|
|
56027
56027
|
const headers = {};
|
|
56028
|
-
if (
|
|
56029
|
-
const sortedHeaders = Object.keys(
|
|
56028
|
+
if (cacheKey3.headers) {
|
|
56029
|
+
const sortedHeaders = Object.keys(cacheKey3.headers).sort();
|
|
56030
56030
|
for (const header of sortedHeaders) {
|
|
56031
56031
|
if (excludeHeaders?.has(header.toLowerCase())) {
|
|
56032
56032
|
continue;
|
|
56033
56033
|
}
|
|
56034
|
-
headers[header] =
|
|
56034
|
+
headers[header] = cacheKey3.headers[header];
|
|
56035
56035
|
}
|
|
56036
56036
|
}
|
|
56037
|
-
return JSON.stringify([
|
|
56037
|
+
return JSON.stringify([cacheKey3.origin, cacheKey3.method, cacheKey3.path, headers]);
|
|
56038
56038
|
}
|
|
56039
56039
|
module.exports = {
|
|
56040
56040
|
makeCacheKey,
|
|
@@ -56608,7 +56608,7 @@ var require_cache_handler = __commonJS({
|
|
|
56608
56608
|
}
|
|
56609
56609
|
}
|
|
56610
56610
|
}
|
|
56611
|
-
function getSameOriginPath(
|
|
56611
|
+
function getSameOriginPath(cacheKey3, location) {
|
|
56612
56612
|
if (typeof location !== "string") {
|
|
56613
56613
|
return void 0;
|
|
56614
56614
|
}
|
|
@@ -56616,8 +56616,8 @@ var require_cache_handler = __commonJS({
|
|
|
56616
56616
|
let requestUrl;
|
|
56617
56617
|
let locationUrl;
|
|
56618
56618
|
try {
|
|
56619
|
-
originUrl = new URL(
|
|
56620
|
-
requestUrl = new URL(
|
|
56619
|
+
originUrl = new URL(cacheKey3.origin);
|
|
56620
|
+
requestUrl = new URL(cacheKey3.path, originUrl);
|
|
56621
56621
|
locationUrl = new URL(location, requestUrl);
|
|
56622
56622
|
} catch {
|
|
56623
56623
|
return void 0;
|
|
@@ -56627,38 +56627,38 @@ var require_cache_handler = __commonJS({
|
|
|
56627
56627
|
}
|
|
56628
56628
|
return locationUrl.pathname + locationUrl.search;
|
|
56629
56629
|
}
|
|
56630
|
-
function deleteCachedUri(store,
|
|
56630
|
+
function deleteCachedUri(store, cacheKey3, path4) {
|
|
56631
56631
|
deleteCachedValue(store, {
|
|
56632
|
-
...
|
|
56632
|
+
...cacheKey3,
|
|
56633
56633
|
path: path4
|
|
56634
56634
|
});
|
|
56635
56635
|
for (let i = 0; i < util2.safeHTTPMethods.length; i++) {
|
|
56636
56636
|
const method = util2.safeHTTPMethods[i];
|
|
56637
|
-
if (method !==
|
|
56637
|
+
if (method !== cacheKey3.method) {
|
|
56638
56638
|
deleteCachedValue(store, {
|
|
56639
|
-
...
|
|
56639
|
+
...cacheKey3,
|
|
56640
56640
|
method,
|
|
56641
56641
|
path: path4
|
|
56642
56642
|
});
|
|
56643
56643
|
}
|
|
56644
56644
|
}
|
|
56645
56645
|
}
|
|
56646
|
-
function deleteLocationTargets(store,
|
|
56646
|
+
function deleteLocationTargets(store, cacheKey3, headerValue) {
|
|
56647
56647
|
if (headerValue === void 0) {
|
|
56648
56648
|
return;
|
|
56649
56649
|
}
|
|
56650
56650
|
const values = Array.isArray(headerValue) ? headerValue : [headerValue];
|
|
56651
56651
|
for (let i = 0; i < values.length; i++) {
|
|
56652
|
-
const path4 = getSameOriginPath(
|
|
56652
|
+
const path4 = getSameOriginPath(cacheKey3, values[i]);
|
|
56653
56653
|
if (path4 !== void 0) {
|
|
56654
|
-
deleteCachedUri(store,
|
|
56654
|
+
deleteCachedUri(store, cacheKey3, path4);
|
|
56655
56655
|
}
|
|
56656
56656
|
}
|
|
56657
56657
|
}
|
|
56658
|
-
function invalidateUnsafeRequest(store,
|
|
56659
|
-
deleteCachedUri(store,
|
|
56660
|
-
deleteLocationTargets(store,
|
|
56661
|
-
deleteLocationTargets(store,
|
|
56658
|
+
function invalidateUnsafeRequest(store, cacheKey3, resHeaders) {
|
|
56659
|
+
deleteCachedUri(store, cacheKey3, cacheKey3.path);
|
|
56660
|
+
deleteLocationTargets(store, cacheKey3, resHeaders.location);
|
|
56661
|
+
deleteLocationTargets(store, cacheKey3, resHeaders["content-location"]);
|
|
56662
56662
|
}
|
|
56663
56663
|
var CacheHandler = class {
|
|
56664
56664
|
/**
|
|
@@ -56690,11 +56690,11 @@ var require_cache_handler = __commonJS({
|
|
|
56690
56690
|
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} cacheKey
|
|
56691
56691
|
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandler} handler
|
|
56692
56692
|
*/
|
|
56693
|
-
constructor({ store, type: type2, cacheByDefault },
|
|
56693
|
+
constructor({ store, type: type2, cacheByDefault }, cacheKey3, handler2) {
|
|
56694
56694
|
this.#store = store;
|
|
56695
56695
|
this.#cacheType = type2;
|
|
56696
56696
|
this.#cacheByDefault = cacheByDefault;
|
|
56697
|
-
this.#cacheKey =
|
|
56697
|
+
this.#cacheKey = cacheKey3;
|
|
56698
56698
|
this.#handler = handler2;
|
|
56699
56699
|
}
|
|
56700
56700
|
onRequestStart(controller, context) {
|
|
@@ -56887,15 +56887,15 @@ var require_cache_handler = __commonJS({
|
|
|
56887
56887
|
this.#handler.onResponseError?.(controller, err);
|
|
56888
56888
|
}
|
|
56889
56889
|
};
|
|
56890
|
-
function deleteCachedValue(store,
|
|
56890
|
+
function deleteCachedValue(store, cacheKey3) {
|
|
56891
56891
|
try {
|
|
56892
|
-
store.delete(
|
|
56892
|
+
store.delete(cacheKey3)?.catch?.(noop4);
|
|
56893
56893
|
} catch {
|
|
56894
56894
|
}
|
|
56895
56895
|
}
|
|
56896
|
-
function deleteCachedValueIfNotModified(statusCode, store,
|
|
56896
|
+
function deleteCachedValueIfNotModified(statusCode, store, cacheKey3) {
|
|
56897
56897
|
if (statusCode === 304) {
|
|
56898
|
-
deleteCachedValue(store,
|
|
56898
|
+
deleteCachedValue(store, cacheKey3);
|
|
56899
56899
|
}
|
|
56900
56900
|
}
|
|
56901
56901
|
function revalidationResponseDisallowsCachedReuse(cacheType, resHeaders, cacheControlDirectives) {
|
|
@@ -57461,9 +57461,9 @@ var require_cache3 = __commonJS({
|
|
|
57461
57461
|
function revalidationResponseUpdatesCacheControl(headers) {
|
|
57462
57462
|
return headers["cache-control"] !== void 0;
|
|
57463
57463
|
}
|
|
57464
|
-
function deleteCachedValue(store,
|
|
57464
|
+
function deleteCachedValue(store, cacheKey3) {
|
|
57465
57465
|
try {
|
|
57466
|
-
store.delete(
|
|
57466
|
+
store.delete(cacheKey3)?.catch?.(nop);
|
|
57467
57467
|
} catch {
|
|
57468
57468
|
}
|
|
57469
57469
|
}
|
|
@@ -57515,7 +57515,7 @@ var require_cache3 = __commonJS({
|
|
|
57515
57515
|
const staleWhileRevalidateExpiry = result.staleAt + staleWhileRevalidate * 1e3;
|
|
57516
57516
|
return now <= staleWhileRevalidateExpiry;
|
|
57517
57517
|
}
|
|
57518
|
-
function handleUncachedResponse(dispatch, globalOpts,
|
|
57518
|
+
function handleUncachedResponse(dispatch, globalOpts, cacheKey3, handler2, opts, reqCacheControl) {
|
|
57519
57519
|
if (reqCacheControl?.["only-if-cached"]) {
|
|
57520
57520
|
let aborted3 = false;
|
|
57521
57521
|
try {
|
|
@@ -57543,7 +57543,7 @@ var require_cache3 = __commonJS({
|
|
|
57543
57543
|
}
|
|
57544
57544
|
return true;
|
|
57545
57545
|
}
|
|
57546
|
-
return dispatch(opts, new CacheHandler(globalOpts,
|
|
57546
|
+
return dispatch(opts, new CacheHandler(globalOpts, cacheKey3, handler2));
|
|
57547
57547
|
}
|
|
57548
57548
|
function sendCachedValue(handler2, opts, result, age, context, isStale2) {
|
|
57549
57549
|
const stream = util2.isStream(result.body) ? result.body : Readable2.from(result.body ?? []);
|
|
@@ -57599,20 +57599,20 @@ var require_cache3 = __commonJS({
|
|
|
57599
57599
|
});
|
|
57600
57600
|
}
|
|
57601
57601
|
}
|
|
57602
|
-
function handleResult2(dispatch, globalOpts,
|
|
57602
|
+
function handleResult2(dispatch, globalOpts, cacheKey3, handler2, opts, reqCacheControl, result) {
|
|
57603
57603
|
if (!result) {
|
|
57604
|
-
return handleUncachedResponse(dispatch, globalOpts,
|
|
57604
|
+
return handleUncachedResponse(dispatch, globalOpts, cacheKey3, handler2, opts, reqCacheControl);
|
|
57605
57605
|
}
|
|
57606
57606
|
if (globalOpts.type === "shared" && Object.hasOwn(result.headers, "set-cookie")) {
|
|
57607
57607
|
if (util2.isStream(result.body)) {
|
|
57608
57608
|
result.body.on("error", nop).destroy();
|
|
57609
57609
|
}
|
|
57610
|
-
deleteCachedValue(globalOpts.store,
|
|
57611
|
-
return handleUncachedResponse(dispatch, globalOpts,
|
|
57610
|
+
deleteCachedValue(globalOpts.store, cacheKey3);
|
|
57611
|
+
return handleUncachedResponse(dispatch, globalOpts, cacheKey3, handler2, opts, reqCacheControl);
|
|
57612
57612
|
}
|
|
57613
57613
|
const now = Date.now();
|
|
57614
57614
|
if (now > result.deleteAt) {
|
|
57615
|
-
return dispatch(opts, new CacheHandler(globalOpts,
|
|
57615
|
+
return dispatch(opts, new CacheHandler(globalOpts, cacheKey3, handler2));
|
|
57616
57616
|
}
|
|
57617
57617
|
const age = Math.round((now - result.cachedAt) / 1e3);
|
|
57618
57618
|
const requestMaxAgeExpired = reqCacheControl?.["max-age"] !== void 0 && age >= reqCacheControl["max-age"];
|
|
@@ -57620,7 +57620,7 @@ var require_cache3 = __commonJS({
|
|
|
57620
57620
|
const revalidate = requestMaxAgeExpired || needsRevalidation(result, reqCacheControl, opts);
|
|
57621
57621
|
if (stale || revalidate) {
|
|
57622
57622
|
if (util2.isStream(opts.body) && util2.bodyLength(opts.body) !== 0) {
|
|
57623
|
-
return dispatch(opts, new CacheHandler(globalOpts,
|
|
57623
|
+
return dispatch(opts, new CacheHandler(globalOpts, cacheKey3, handler2));
|
|
57624
57624
|
}
|
|
57625
57625
|
if (!revalidate && withinStaleWhileRevalidateWindow(result, globalOpts.type)) {
|
|
57626
57626
|
sendCachedValue(handler2, opts, result, age, null, true);
|
|
@@ -57631,7 +57631,7 @@ var require_cache3 = __commonJS({
|
|
|
57631
57631
|
...opts,
|
|
57632
57632
|
headers: headers2
|
|
57633
57633
|
},
|
|
57634
|
-
new CacheHandler(globalOpts,
|
|
57634
|
+
new CacheHandler(globalOpts, cacheKey3, {
|
|
57635
57635
|
// Silent handler that just updates the cache
|
|
57636
57636
|
onRequestStart() {
|
|
57637
57637
|
},
|
|
@@ -57671,11 +57671,11 @@ var require_cache3 = __commonJS({
|
|
|
57671
57671
|
if (util2.isStream(result.body)) {
|
|
57672
57672
|
result.body.on("error", nop).destroy();
|
|
57673
57673
|
}
|
|
57674
|
-
deleteCachedValue(globalOpts.store,
|
|
57675
|
-
return dispatch(opts, new CacheHandler(globalOpts,
|
|
57674
|
+
deleteCachedValue(globalOpts.store, cacheKey3);
|
|
57675
|
+
return dispatch(opts, new CacheHandler(globalOpts, cacheKey3, handler2));
|
|
57676
57676
|
}
|
|
57677
57677
|
if (revalidationResponseUpdatesCacheControl(headers2)) {
|
|
57678
|
-
deleteCachedValue(globalOpts.store,
|
|
57678
|
+
deleteCachedValue(globalOpts.store, cacheKey3);
|
|
57679
57679
|
}
|
|
57680
57680
|
}
|
|
57681
57681
|
sendCachedValue(handler2, opts, result, age, context, stale);
|
|
@@ -57683,7 +57683,7 @@ var require_cache3 = __commonJS({
|
|
|
57683
57683
|
result.body.on("error", nop).destroy();
|
|
57684
57684
|
}
|
|
57685
57685
|
},
|
|
57686
|
-
new CacheHandler(globalOpts,
|
|
57686
|
+
new CacheHandler(globalOpts, cacheKey3, handler2),
|
|
57687
57687
|
withinStaleIfErrorThreshold
|
|
57688
57688
|
)
|
|
57689
57689
|
);
|
|
@@ -57758,16 +57758,16 @@ var require_cache3 = __commonJS({
|
|
|
57758
57758
|
if (reqCacheControl?.["no-store"]) {
|
|
57759
57759
|
return dispatch(opts2, handler2);
|
|
57760
57760
|
}
|
|
57761
|
-
const
|
|
57761
|
+
const cacheKey3 = makeCacheKey(opts2);
|
|
57762
57762
|
if (!arrayIncludes(util2.safeHTTPMethods, opts2.method)) {
|
|
57763
|
-
return dispatch(opts2, new CacheHandler(globalOpts,
|
|
57763
|
+
return dispatch(opts2, new CacheHandler(globalOpts, cacheKey3, handler2));
|
|
57764
57764
|
}
|
|
57765
|
-
const result = store.get(
|
|
57765
|
+
const result = store.get(cacheKey3);
|
|
57766
57766
|
if (result && typeof result.then === "function") {
|
|
57767
57767
|
return result.then((result2) => handleResult2(
|
|
57768
57768
|
dispatch,
|
|
57769
57769
|
globalOpts,
|
|
57770
|
-
|
|
57770
|
+
cacheKey3,
|
|
57771
57771
|
handler2,
|
|
57772
57772
|
opts2,
|
|
57773
57773
|
reqCacheControl,
|
|
@@ -57777,7 +57777,7 @@ var require_cache3 = __commonJS({
|
|
|
57777
57777
|
return handleResult2(
|
|
57778
57778
|
dispatch,
|
|
57779
57779
|
globalOpts,
|
|
57780
|
-
|
|
57780
|
+
cacheKey3,
|
|
57781
57781
|
handler2,
|
|
57782
57782
|
opts2,
|
|
57783
57783
|
reqCacheControl,
|
|
@@ -58670,8 +58670,8 @@ var require_deduplicate = __commonJS({
|
|
|
58670
58670
|
}
|
|
58671
58671
|
}
|
|
58672
58672
|
}
|
|
58673
|
-
const
|
|
58674
|
-
const dedupeKey = makeDeduplicationKey(
|
|
58673
|
+
const cacheKey3 = makeCacheKey(opts2);
|
|
58674
|
+
const dedupeKey = makeDeduplicationKey(cacheKey3, excludeHeaderNamesSet);
|
|
58675
58675
|
const pendingHandler = pendingRequests.get(dedupeKey);
|
|
58676
58676
|
if (pendingHandler) {
|
|
58677
58677
|
if (pendingHandler.addWaitingHandler(handler2)) {
|
|
@@ -76276,8 +76276,8 @@ var require_core2 = __commonJS({
|
|
|
76276
76276
|
return this;
|
|
76277
76277
|
}
|
|
76278
76278
|
case "object": {
|
|
76279
|
-
const
|
|
76280
|
-
this._cache.delete(
|
|
76279
|
+
const cacheKey3 = schemaKeyRef;
|
|
76280
|
+
this._cache.delete(cacheKey3);
|
|
76281
76281
|
let id = schemaKeyRef[this.opts.schemaId];
|
|
76282
76282
|
if (id) {
|
|
76283
76283
|
id = (0, resolve_1.normalizeId)(id);
|
|
@@ -76442,11 +76442,11 @@ var require_core2 = __commonJS({
|
|
|
76442
76442
|
Ajv5.ValidationError = validation_error_1.default;
|
|
76443
76443
|
Ajv5.MissingRefError = ref_error_1.default;
|
|
76444
76444
|
exports.default = Ajv5;
|
|
76445
|
-
function checkOptions(checkOpts, options, msg,
|
|
76445
|
+
function checkOptions(checkOpts, options, msg, log2 = "error") {
|
|
76446
76446
|
for (const key in checkOpts) {
|
|
76447
76447
|
const opt = key;
|
|
76448
76448
|
if (opt in options)
|
|
76449
|
-
this.logger[
|
|
76449
|
+
this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
|
|
76450
76450
|
}
|
|
76451
76451
|
}
|
|
76452
76452
|
function getSchEnv(keyRef) {
|
|
@@ -98088,14 +98088,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
98088
98088
|
} else if (node2.nodeType === 1) {
|
|
98089
98089
|
replacement = replacementForNode.call(self2, node2);
|
|
98090
98090
|
}
|
|
98091
|
-
return
|
|
98091
|
+
return join29(output, replacement);
|
|
98092
98092
|
}, "");
|
|
98093
98093
|
}
|
|
98094
98094
|
function postProcess(output) {
|
|
98095
98095
|
var self2 = this;
|
|
98096
98096
|
this.rules.forEach(function(rule) {
|
|
98097
98097
|
if (typeof rule.append === "function") {
|
|
98098
|
-
output =
|
|
98098
|
+
output = join29(output, rule.append(self2.options));
|
|
98099
98099
|
}
|
|
98100
98100
|
});
|
|
98101
98101
|
return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -98107,7 +98107,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
98107
98107
|
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
|
98108
98108
|
return whitespace.leading + rule.replacement(content, node2, this.options) + whitespace.trailing;
|
|
98109
98109
|
}
|
|
98110
|
-
function
|
|
98110
|
+
function join29(output, replacement) {
|
|
98111
98111
|
var s1 = trimTrailingNewlines(output);
|
|
98112
98112
|
var s2 = trimLeadingNewlines(replacement);
|
|
98113
98113
|
var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
|
|
@@ -99714,7 +99714,7 @@ var require_node = __commonJS({
|
|
|
99714
99714
|
var tty = __require("tty");
|
|
99715
99715
|
var util2 = __require("util");
|
|
99716
99716
|
exports.init = init;
|
|
99717
|
-
exports.log =
|
|
99717
|
+
exports.log = log2;
|
|
99718
99718
|
exports.formatArgs = formatArgs2;
|
|
99719
99719
|
exports.save = save;
|
|
99720
99720
|
exports.load = load;
|
|
@@ -99849,7 +99849,7 @@ var require_node = __commonJS({
|
|
|
99849
99849
|
}
|
|
99850
99850
|
return (/* @__PURE__ */ new Date()).toISOString() + " ";
|
|
99851
99851
|
}
|
|
99852
|
-
function
|
|
99852
|
+
function log2(...args2) {
|
|
99853
99853
|
return process.stderr.write(util2.formatWithOptions(exports.inspectOpts, ...args2) + "\n");
|
|
99854
99854
|
}
|
|
99855
99855
|
function save(namespaces) {
|
|
@@ -102898,9 +102898,9 @@ var init_file_type = __esm({
|
|
|
102898
102898
|
});
|
|
102899
102899
|
|
|
102900
102900
|
// main.ts
|
|
102901
|
-
import { existsSync as
|
|
102901
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2 } from "node:fs";
|
|
102902
102902
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
102903
|
-
import { join as
|
|
102903
|
+
import { join as join28 } from "node:path";
|
|
102904
102904
|
|
|
102905
102905
|
// node_modules/.pnpm/package-manager-detector@1.8.0/node_modules/package-manager-detector/dist/commands.mjs
|
|
102906
102906
|
function splitRunArgs(args2, valueFlags = []) {
|
|
@@ -103909,6 +103909,15 @@ var providers = {
|
|
|
103909
103909
|
openRouterEffort: [],
|
|
103910
103910
|
openRouterResolve: "openrouter/qwen/qwen3.8-flash"
|
|
103911
103911
|
},
|
|
103912
|
+
// Zen lists Mistral Large 4 at half its list price for launch, level with
|
|
103913
|
+
// the routers. hidden until a published `pullfrog` resolves it, as there.
|
|
103914
|
+
"mistral-large": {
|
|
103915
|
+
displayName: "Mistral Large",
|
|
103916
|
+
resolve: "opencode/mistral-large-4",
|
|
103917
|
+
effort: ["none", "high"],
|
|
103918
|
+
openRouterResolve: "openrouter/mistralai/mistral-large-4-0",
|
|
103919
|
+
hidden: true
|
|
103920
|
+
},
|
|
103912
103921
|
"gpt-5-nano": {
|
|
103913
103922
|
displayName: "GPT Nano",
|
|
103914
103923
|
resolve: "opencode/gpt-5.4-nano",
|
|
@@ -103957,12 +103966,12 @@ var providers = {
|
|
|
103957
103966
|
fallback: "opencode/big-pickle"
|
|
103958
103967
|
},
|
|
103959
103968
|
// Zen's FREE stealth preview (listed 2026-09-23), the third after
|
|
103960
|
-
// big-pickle and union-alpha.
|
|
103961
|
-
//
|
|
103962
|
-
//
|
|
103969
|
+
// big-pickle and union-alpha. Zen's docs: zero retention, no training.
|
|
103970
|
+
// unlike the first two it publishes an effort ladder, so the gate
|
|
103971
|
+
// mirrors one here.
|
|
103963
103972
|
"space-bunny": {
|
|
103964
103973
|
displayName: "Space Bunny",
|
|
103965
|
-
description: "Stealth preview
|
|
103974
|
+
description: "Stealth preview, free for a limited time",
|
|
103966
103975
|
resolve: "opencode/space-bunny-free",
|
|
103967
103976
|
effort: ["low", "medium", "high", "xhigh", "max"],
|
|
103968
103977
|
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
@@ -103980,17 +103989,30 @@ var providers = {
|
|
|
103980
103989
|
// see the big-pickle note above (#1077).
|
|
103981
103990
|
isFree: true
|
|
103982
103991
|
},
|
|
103983
|
-
// Zen's FREE stealth preview (listed 2026-10-01), the fifth promo. Zen
|
|
103984
|
-
//
|
|
103992
|
+
// Zen's FREE stealth preview (listed 2026-10-01), the fifth promo. Zen's
|
|
103993
|
+
// docs: data may be used to improve the model during the free period.
|
|
103985
103994
|
"fledge-alpha": {
|
|
103986
103995
|
displayName: "Fledge Alpha",
|
|
103987
|
-
description: "Stealth preview
|
|
103996
|
+
description: "Stealth preview; data may be used to improve it",
|
|
103988
103997
|
resolve: "opencode/fledge-alpha-free",
|
|
103989
103998
|
effort: ["low", "high", "max"],
|
|
103990
103999
|
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
103991
104000
|
// see the big-pickle note above (#1077).
|
|
103992
104001
|
isFree: true
|
|
103993
104002
|
},
|
|
104003
|
+
// Zen's FREE preview (listed 2026-10-06), the sixth promo, on Fledge
|
|
104004
|
+
// Alpha's terms. hidden until a published `pullfrog` resolves it.
|
|
104005
|
+
exo: {
|
|
104006
|
+
displayName: "Exo",
|
|
104007
|
+
description: "Preview; data may be used to improve it",
|
|
104008
|
+
resolve: "opencode/exo-free",
|
|
104009
|
+
// Zen publishes a single rung.
|
|
104010
|
+
effort: ["high"],
|
|
104011
|
+
// free to run, still gated on the provider's own OPENCODE_API_KEY —
|
|
104012
|
+
// see the big-pickle note above (#1077).
|
|
104013
|
+
isFree: true,
|
|
104014
|
+
hidden: true
|
|
104015
|
+
},
|
|
103994
104016
|
// Zen's live free MiMo, and the second free row in a menu that big-pickle
|
|
103995
104017
|
// was alone in since `mimo-v2-pro-free` lost its model.
|
|
103996
104018
|
mimo: {
|
|
@@ -104053,7 +104075,11 @@ var providers = {
|
|
|
104053
104075
|
"glm-flash": {
|
|
104054
104076
|
displayName: "GLM Flash",
|
|
104055
104077
|
resolve: "opencode-go/glm-5.3-flash",
|
|
104056
|
-
|
|
104078
|
+
// the Go endpoint intermittently rejects reasoning_effort ("native reasoning
|
|
104079
|
+
// control reasoning_effort is not allowed") mid-run, despite models.dev
|
|
104080
|
+
// advertising a ladder — so this route sends none.
|
|
104081
|
+
effort: [],
|
|
104082
|
+
openRouterEffort: ["low", "high", "max"],
|
|
104057
104083
|
openRouterResolve: "openrouter/z-ai/glm-5.3-flash"
|
|
104058
104084
|
},
|
|
104059
104085
|
// legacy alias — the slug pinned a version instead of a brand tier and
|
|
@@ -104442,6 +104468,17 @@ var providers = {
|
|
|
104442
104468
|
resolve: "openrouter/meta/muse-spark-1.3-contributor",
|
|
104443
104469
|
effort: ["minimal", "low", "medium", "high", "xhigh", "max"],
|
|
104444
104470
|
openRouterResolve: "openrouter/meta/muse-spark-1.3-contributor"
|
|
104471
|
+
},
|
|
104472
|
+
// Mistral's flagship (public preview, 2026-10-06), on the routers only:
|
|
104473
|
+
// the catalog carries no direct Mistral provider. out of the pickers
|
|
104474
|
+
// until a published `pullfrog` resolves the slug; see "A new alias
|
|
104475
|
+
// reaches the picker at merge".
|
|
104476
|
+
"mistral-large": {
|
|
104477
|
+
displayName: "Mistral Large",
|
|
104478
|
+
resolve: "openrouter/mistralai/mistral-large-4-0",
|
|
104479
|
+
effort: ["none", "high"],
|
|
104480
|
+
openRouterResolve: "openrouter/mistralai/mistral-large-4-0",
|
|
104481
|
+
hidden: true
|
|
104445
104482
|
}
|
|
104446
104483
|
}
|
|
104447
104484
|
}),
|
|
@@ -104509,7 +104546,7 @@ var providers = {
|
|
|
104509
104546
|
"deepseek-pro": {
|
|
104510
104547
|
displayName: "DeepSeek Pro",
|
|
104511
104548
|
resolve: "vercel/deepseek/deepseek-v4-pro-0813",
|
|
104512
|
-
effort: ["none", "high", "max"]
|
|
104549
|
+
effort: ["none", "low", "high", "max"]
|
|
104513
104550
|
},
|
|
104514
104551
|
// the gateway's bare `deepseek-v4-flash` is the April preview — the same
|
|
104515
104552
|
// fork trap as OpenRouter, with `deepseek-v4-flash-0731` beside it — so
|
|
@@ -104517,7 +104554,7 @@ var providers = {
|
|
|
104517
104554
|
"deepseek-flash": {
|
|
104518
104555
|
displayName: "DeepSeek Flash",
|
|
104519
104556
|
resolve: "vercel/deepseek/deepseek-v4.1-flash",
|
|
104520
|
-
effort: ["none", "high", "max"]
|
|
104557
|
+
effort: ["none", "low", "high", "max"]
|
|
104521
104558
|
},
|
|
104522
104559
|
glm: {
|
|
104523
104560
|
displayName: "GLM",
|
|
@@ -104533,6 +104570,13 @@ var providers = {
|
|
|
104533
104570
|
displayName: "Muse Spark",
|
|
104534
104571
|
resolve: "vercel/meta/muse-spark-1.3",
|
|
104535
104572
|
effort: ["minimal", "low", "medium", "high", "xhigh"]
|
|
104573
|
+
},
|
|
104574
|
+
// hidden until a published `pullfrog` resolves it, as on OpenRouter.
|
|
104575
|
+
"mistral-large": {
|
|
104576
|
+
displayName: "Mistral Large",
|
|
104577
|
+
resolve: "vercel/mistral/mistral-large-4",
|
|
104578
|
+
effort: ["none", "low", "medium", "high"],
|
|
104579
|
+
hidden: true
|
|
104536
104580
|
}
|
|
104537
104581
|
}
|
|
104538
104582
|
})
|
|
@@ -104723,13 +104767,13 @@ for (const [name, ladder] of Object.entries({ ...PROVIDER_LADDERS, router: ROUTE
|
|
|
104723
104767
|
if (terminal.size < 2) throw new Error(`${name} ladder runs every tier on ${[...terminal][0]}`);
|
|
104724
104768
|
}
|
|
104725
104769
|
var OSS_MODEL_ALLOWLIST = [
|
|
104726
|
-
"deepseek/deepseek-flash",
|
|
104727
|
-
"openai/gpt-luna",
|
|
104728
|
-
"openrouter/minimax-m2.5",
|
|
104729
104770
|
// opt-in: 0.86x the old default on the measured mix, and Meta trains on the
|
|
104730
104771
|
// traffic — fine for public code on headless runs, the human decided
|
|
104731
104772
|
// 2026-09-11. unmeasured on a real run; not the default until it is.
|
|
104732
|
-
"meta/muse-spark-contributor"
|
|
104773
|
+
"meta/muse-spark-contributor",
|
|
104774
|
+
"deepseek/deepseek-flash",
|
|
104775
|
+
"openai/gpt-luna",
|
|
104776
|
+
"openrouter/minimax-m2.5"
|
|
104733
104777
|
];
|
|
104734
104778
|
var OSS_RECOMMENDED_MODEL = AUTO_TIER_TARGET[AUTO_EFFICIENT];
|
|
104735
104779
|
function ossFundedModelNames() {
|
|
@@ -105413,7 +105457,13 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
105413
105457
|
// …/settings/credits`) matched neither this nor `requires more credits`, so
|
|
105414
105458
|
// the one run in that episode that was a genuinely empty wallet rendered with
|
|
105415
105459
|
// no CTA at all while runs 1-6 rendered correctly.
|
|
105416
|
-
|
|
105460
|
+
// `account funds` is Zen's (#1474).
|
|
105461
|
+
{
|
|
105462
|
+
regex: /Insufficient (?:balance|credits|account funds)/i,
|
|
105463
|
+
label: PROVIDER_BILLING_EXHAUSTED_LABEL
|
|
105464
|
+
},
|
|
105465
|
+
// OpenAI's `You have no credits remaining` (#1474).
|
|
105466
|
+
{ regex: /no credits remaining/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
105417
105467
|
{ regex: /credit balance is too low/i, label: PROVIDER_BILLING_EXHAUSTED_LABEL },
|
|
105418
105468
|
// "spending cap" (Gemini) and "spending limit" (xAI, #1076) are the same
|
|
105419
105469
|
// condition in two house styles — a configured ceiling was reached.
|
|
@@ -105534,6 +105584,9 @@ function isRouterKeylimitExhaustedError(text) {
|
|
|
105534
105584
|
function isProviderBillingExhausted(text) {
|
|
105535
105585
|
return findProviderErrorMatch(text)?.label === PROVIDER_BILLING_EXHAUSTED_LABEL;
|
|
105536
105586
|
}
|
|
105587
|
+
function isProviderUsageLimit(text) {
|
|
105588
|
+
return findProviderErrorMatch(text)?.label === PROVIDER_USAGE_LIMIT_LABEL;
|
|
105589
|
+
}
|
|
105537
105590
|
function isProviderNoRoutableEndpoints(text) {
|
|
105538
105591
|
return findProviderErrorMatch(text)?.label === PROVIDER_NO_ENDPOINTS_LABEL;
|
|
105539
105592
|
}
|
|
@@ -105605,7 +105658,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
105605
105658
|
// package.json
|
|
105606
105659
|
var package_default = {
|
|
105607
105660
|
name: "pullfrog",
|
|
105608
|
-
version: "0.1.
|
|
105661
|
+
version: "0.1.97",
|
|
105609
105662
|
cliContractVersion: "1",
|
|
105610
105663
|
type: "module",
|
|
105611
105664
|
bin: {
|
|
@@ -105671,7 +105724,7 @@ var package_default = {
|
|
|
105671
105724
|
undici: "^7.22.0",
|
|
105672
105725
|
vitest: "^4.0.17",
|
|
105673
105726
|
yaml: "^2.8.2",
|
|
105674
|
-
yes: "0.
|
|
105727
|
+
yes: "0.2.3",
|
|
105675
105728
|
zod: "4.3.6"
|
|
105676
105729
|
},
|
|
105677
105730
|
repository: {
|
|
@@ -105839,6 +105892,9 @@ function trackChild(options) {
|
|
|
105839
105892
|
function untrackChild(child) {
|
|
105840
105893
|
activeChildren.delete(child);
|
|
105841
105894
|
}
|
|
105895
|
+
function isTrackedChild(child) {
|
|
105896
|
+
return activeChildren.has(child);
|
|
105897
|
+
}
|
|
105842
105898
|
function killTrackedChildren() {
|
|
105843
105899
|
for (const entry of activeChildren) {
|
|
105844
105900
|
const child = entry[0];
|
|
@@ -105852,6 +105908,7 @@ function killTrackedChildren() {
|
|
|
105852
105908
|
}
|
|
105853
105909
|
child.kill("SIGKILL");
|
|
105854
105910
|
}
|
|
105911
|
+
activeChildren.clear();
|
|
105855
105912
|
}
|
|
105856
105913
|
var handlersInstalled = false;
|
|
105857
105914
|
function installSignalHandler() {
|
|
@@ -105898,6 +105955,7 @@ ${this.buffer}`;
|
|
|
105898
105955
|
};
|
|
105899
105956
|
async function spawn(options) {
|
|
105900
105957
|
const activityTimeoutMs = options.activityTimeout ?? DEFAULT_ACTIVITY_TIMEOUT_MS;
|
|
105958
|
+
options.signal?.throwIfAborted();
|
|
105901
105959
|
installSignalHandler();
|
|
105902
105960
|
const startTime = performance3.now();
|
|
105903
105961
|
const retain = options.retain ?? "tail";
|
|
@@ -105933,17 +105991,18 @@ async function spawn(options) {
|
|
|
105933
105991
|
let isActivityTimedOut = false;
|
|
105934
105992
|
let lastActivityTime = performance3.now();
|
|
105935
105993
|
let killedAtIdleMs;
|
|
105994
|
+
const terminate = () => {
|
|
105995
|
+
if (sigkillEscalatorId) return;
|
|
105996
|
+
killSelf("SIGTERM");
|
|
105997
|
+
sigkillEscalatorId = setTimeout(() => killSelf("SIGKILL"), 5e3);
|
|
105998
|
+
};
|
|
105936
105999
|
if (options.timeout) {
|
|
105937
106000
|
timeoutId = setTimeout(() => {
|
|
105938
106001
|
isTimedOut = true;
|
|
105939
|
-
|
|
105940
|
-
sigkillEscalatorId = setTimeout(() => {
|
|
105941
|
-
if (!child.killed) {
|
|
105942
|
-
killSelf("SIGKILL");
|
|
105943
|
-
}
|
|
105944
|
-
}, 5e3);
|
|
106002
|
+
terminate();
|
|
105945
106003
|
}, options.timeout);
|
|
105946
106004
|
}
|
|
106005
|
+
options.signal?.addEventListener("abort", terminate, { once: true });
|
|
105947
106006
|
if (activityTimeoutMs > 0) {
|
|
105948
106007
|
log.debug(
|
|
105949
106008
|
`spawn activity timer: pid=${child.pid} cmd=${options.cmd} timeout=${activityTimeoutMs}ms`
|
|
@@ -106008,6 +106067,11 @@ async function spawn(options) {
|
|
|
106008
106067
|
if (timeoutId) clearTimeout(timeoutId);
|
|
106009
106068
|
if (sigkillEscalatorId) clearTimeout(sigkillEscalatorId);
|
|
106010
106069
|
if (activityCheckIntervalId) clearInterval(activityCheckIntervalId);
|
|
106070
|
+
options.signal?.removeEventListener("abort", terminate);
|
|
106071
|
+
if (options.signal?.aborted) {
|
|
106072
|
+
reject(options.signal.reason);
|
|
106073
|
+
return;
|
|
106074
|
+
}
|
|
106011
106075
|
if (isTimedOut) {
|
|
106012
106076
|
reject(
|
|
106013
106077
|
new SpawnTimeoutError(`process timed out after ${options.timeout}ms`, SPAWN_TIMEOUT_CODE)
|
|
@@ -106046,6 +106110,7 @@ ${killMsg}` : killMsg;
|
|
|
106046
106110
|
if (timeoutId) clearTimeout(timeoutId);
|
|
106047
106111
|
if (sigkillEscalatorId) clearTimeout(sigkillEscalatorId);
|
|
106048
106112
|
if (activityCheckIntervalId) clearInterval(activityCheckIntervalId);
|
|
106113
|
+
options.signal?.removeEventListener("abort", terminate);
|
|
106049
106114
|
const errMsg = `[spawn] ${options.cmd}: ${error49.message}`;
|
|
106050
106115
|
console.error(errMsg);
|
|
106051
106116
|
const existingStderr = stderrBuffer?.toString() ?? "";
|
|
@@ -106287,17 +106352,16 @@ Report findings clearly with file:line references and quoted evidence where poss
|
|
|
106287
106352
|
// modes.ts
|
|
106288
106353
|
var PR_SUMMARY_FORMAT = `### Default format
|
|
106289
106354
|
|
|
106290
|
-
The body has at most
|
|
106355
|
+
The body has at most two parts, in this order:
|
|
106291
106356
|
|
|
106292
106357
|
1. **Reviewed changes preamble** \u2014 a bolded \`**Reviewed changes**\` lead-in with one sentence on what was reviewed in this run (for \`IncrementalReview\`: what changed since the prior pullfrog review), then a bullet list of the substantive changes \u2014 short bolded title, one sentence each. A reviewer should understand the full reviewed scope from this list alone. Close the preamble with the metadata comment below.
|
|
106293
106358
|
2. **Cross-cutting issue sections** (zero or more) \u2014 one \`### {emoji} {what's wrong, not what to do}\` heading per concern.
|
|
106294
|
-
3. **\`### \u2139\uFE0F Nitpicks\`** at the very bottom, if any \u2014 a flat bullet list, no technical-details block. Only for what has no runtime effect: a stale or wrong comment or doc, a misleading name, a typo, dead code, a missing test. Never formatting or whitespace.
|
|
106295
106359
|
|
|
106296
106360
|
**Inline vs. body.** Concerns that anchor to a specific line go inline (the \`comments\` parameter), even when their implications are broad. Body \`### \` sections are reserved for concerns that have **no line to anchor to** \u2014 *absence* (something the diff should have done but didn't), *sequencing* (rollout / deletion / migration order), *design decisions only the human can make*, or *scope questions the diff raises but doesn't address*. With no non-anchorable concerns, the body is just the preamble + metadata.
|
|
106297
106361
|
|
|
106298
106362
|
**Severity emoji** on every \`### \` heading, and nowhere else: \u{1F6A8} critical (blocks merge \u2014 data loss, security, broken core flow) \xB7 \u26A0\uFE0F important (must address before merging) \xB7 \u2139\uFE0F informational (mergeable as-is).
|
|
106299
106363
|
|
|
106300
|
-
**Behavior decides placement, not fix size.** A finding that changes what the code does \u2014 a wrong value or message, a crash, a race, a leak, a missed cleanup, a slow path \u2014 gets its own inline comment (or a \`### \` section if no line anchors it) at its real severity, however small the fix.
|
|
106364
|
+
**Behavior decides placement, not fix size.** A finding that changes what the code does \u2014 a wrong value or message, a crash, a race, a leak, a missed cleanup, a slow path \u2014 gets its own inline comment (or a \`### \` section if no line anchors it) at its real severity, however small the fix.
|
|
106301
106365
|
|
|
106302
106366
|
**Blank line between every block-level element.** GitHub's markdown parser requires one before and after HTML tags (\`<details>\`, \`<summary>\`, \`<sub>\`, \`<br/>\`) \u2014 without it GitHub treats what follows as a continuation of the HTML block and renders your markdown as literal text. This is a parser quirk, not a style preference, and it permanently breaks the posted review.
|
|
106303
106367
|
|
|
@@ -106446,8 +106510,6 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
106446
106510
|
|
|
106447
106511
|
3. **triage**: orient yourself on the PR \u2014 identify *what kind of thing this is* (domain it touches, seams it crosses, external contracts it depends on, user-facing surfaces it changes). pull as much context as you need to render a confident, well-grounded review: read related files, grep for callers of changed symbols, check tests that exercise the touched paths, fetch related GitHub state. **you are the synthesizer** \u2014 never delegate understanding to subagents.
|
|
106448
106512
|
|
|
106449
|
-
when the diff adds or changes a test, check that it can actually fail: a test that would still pass with the bug present is theatre, not coverage. the usual tell is a loose assertion standing where an exact one belongs \u2014 \`>=\` or a truthiness check over an expected value, or a snapshot that absorbs whatever it is handed. read the assertion against the behavior it claims to pin, not against whether it currently passes.
|
|
106450
|
-
|
|
106451
106513
|
skip the deeper pass and submit a \`No new issues found.\` review per step 7 only when the diff has **no behavioral surface at all** \u2014 doc typos, whitespace/formatting, lockfile or generated-code regeneration, a mechanical rename whose only effect is import-path updates. line count is not the signal: a one-line change to auth, money, SQL, a comparison operator, a redirect, or a config default is not trivial.
|
|
106452
106514
|
|
|
106453
106515
|
4. **specialist decision**: after reading the complete diff, name the questions you still cannot answer confidently yourself, and dispatch one \`${REVIEWER_AGENT_NAME}\` specialist per question. a question qualifies only when a specialist could return evidence that **changes your disposition** on the PR \u2014 generic requests for another look, extra confidence, or polish do not. most reviews need zero or one; some need several.
|
|
@@ -106471,8 +106533,6 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
106471
106533
|
|
|
106472
106534
|
6. **aggregate & draft**: when specialist results land, merge findings; de-dup overlaps (two specialists catching the same issue = higher-confidence signal); trace each finding yourself before accepting it. drop praise, style preferences, speculative/unverified claims, findings about pre-existing code unrelated to the PR (heuristic: if the finding's root cause lives in lines this PR added or modified, it's in scope; otherwise drop unless the PR plausibly introduced or amplified the regression), and anything not actionable. also drop **bloat-shaped findings** \u2014 proposed fixes that would add defensive checks for cases that can't happen, abstractions used once, comments restating obvious code, tests asserting tautologies, or "just-in-case" guards. subagents are fallible and bias toward recommending changes; the bar for an actionable inline comment is sound + correct + elegant. recommending a change that improves only one of the three (or worse, degrades elegance to nominally improve correctness) makes the codebase worse, not better.
|
|
106473
106535
|
|
|
106474
|
-
**Hunt for non-anchored concerns before drafting.** After collecting your anchored findings, deliberately scan for concerns that have no specific line to point at \u2014 typically: deletion / cleanup plans for code the diff replaces or shadows; rollout sequencing (what happens to in-flight state during deploy / revert?); scope questions that only the human can answer (e.g. is the legacy path going away or is this a long-term dual track?); architectural risks the diff opens up that aren't a single-line bug.
|
|
106475
|
-
|
|
106476
106536
|
for surviving findings, draft inline comments with NEW line numbers from the diff \u2014 attach a \`<details>Technical details</details>\` block to any inline comment whose fix is non-trivial or has cross-file implications (see Inline technical details in the format below). every comment must be actionable, 2-3 sentences max in the visible part, one per root cause \u2014 name its other sites in that comment rather than repeating it. use GitHub permalink format for code references. for impact-analysis findings (stale references after rename/remove), report them in the review body ordered by severity (runtime breakage > incorrect docs > stale comments) rather than as inline comments unless they're anchored to a specific line.
|
|
106477
106537
|
|
|
106478
106538
|
7. **submit**: ALWAYS submit exactly one review via \`${t("create_pull_request_review")}\`. Do NOT call \`report_progress\` \u2014 the review is the final record and the progress comment will be cleaned up automatically.
|
|
@@ -106494,7 +106554,7 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
106494
106554
|
\`approved: false\`. Body opens with \`> [!CAUTION]\\n> This PR introduces ...\`, followed by the PR summary. Include all inline comments via \`comments\`.
|
|
106495
106555
|
- **must-address non-critical findings** (real consequences if shipped \u2014 incorrect behavior in non-critical paths, missing validation on user input, regressions the author should fix before merge):
|
|
106496
106556
|
\`approved: false\`. Body opens with \`> [!IMPORTANT]\\n> ...\`, followed by the PR summary. Reserve this tier for findings with concrete fallout \u2014 do NOT use \`[!IMPORTANT]\` for nits, style preferences, or "consider also" suggestions. Include all inline comments via \`comments\`.
|
|
106497
|
-
- **minor suggestions only** (low-stakes findings
|
|
106557
|
+
- **minor suggestions only** (low-stakes findings):
|
|
106498
106558
|
\`approved: false\`. Body opens with \`> \u2139\uFE0F No critical issues \u2014 minor suggestions inline.\\n\\n\` followed by the PR summary. Include all inline comments via \`comments\`. Vary the wording after the emoji to fit the review (e.g. "Minor suggestions only.", "Two rough edges worth a look."), but always keep the \u2139\uFE0F prefix and keep it short.
|
|
106499
106559
|
- **informational observations** (mergeable as-is, nothing actionable \u2014 e.g. prior feedback addressed cleanly, calling out something noteworthy without recommending a change):
|
|
106500
106560
|
\`approved: true\`. Body opens with \`> \u2705 No new issues found.\\n\\n\` followed by the PR summary. Do NOT include inline \`comments\` \u2014 the \u2705 signals "no action needed", which contradicts an actionable anchor; if a point is concrete enough to anchor to a line, downgrade the whole review to "minor suggestions only" (\`approved: false\`) instead.
|
|
@@ -106537,8 +106597,6 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
106537
106597
|
|
|
106538
106598
|
5. **triage**: orient on the *incremental* changes \u2014 domain, seams, external contracts, user-facing surfaces. pull as much context as you need to render a confident review: read related files, grep for callers of changed symbols, check tests that exercise the touched paths. **you are the synthesizer.**
|
|
106539
106599
|
|
|
106540
|
-
a test added or changed in this delta must be able to fail \u2014 one that would still pass with the bug present is theatre, not coverage. the tell is a loose assertion where an exact one belongs (\`>=\` or a truthiness check over an expected value, a snapshot that absorbs whatever it is handed).
|
|
106541
|
-
|
|
106542
106600
|
skip the deeper pass and jump to step 10's non-substantive path (do NOT submit a review) only when the incremental changes have **no behavioral surface at all** \u2014 formatting, comment tweaks, import reordering, lockfile regen, a mechanical rename of import paths. line count is not the signal: a one-line change to auth, money, SQL, a comparison operator, a redirect, or a config default is not trivial.
|
|
106543
106601
|
|
|
106544
106602
|
6. **specialist decision**: after covering the incremental and full diffs, name the questions about the new changes that you still cannot answer confidently yourself, and dispatch one \`${REVIEWER_AGENT_NAME}\` specialist per question. a question qualifies only when a specialist could return evidence that **changes your disposition** on the PR \u2014 generic requests for another look, extra confidence, or polish do not. most incremental reviews need zero or one, especially thread-reply re-reviews; some need several.
|
|
@@ -106562,11 +106620,9 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
106562
106620
|
|
|
106563
106621
|
8. **aggregate, draft, self-critique**: merge findings (yours + output from every specialist you dispatched); de-dup overlaps; trace each finding yourself. drop praise, style preferences, speculative/unverified claims, findings about pre-existing code unrelated to the new commits, anything not actionable, and anything that re-states prior review feedback (heuristic: if the finding's root cause lives in lines the *new commits* added or modified, it's in scope; otherwise drop). also drop **bloat-shaped findings** \u2014 proposed fixes that would add defensive checks for cases that can't happen, abstractions used once, comments restating obvious code, tests asserting tautologies, or "just-in-case" guards. subagents are fallible and bias toward recommending changes; the bar for an actionable inline comment is sound + correct + elegant. recommending a change that improves only one of the three (or degrades elegance to nominally improve correctness) makes the codebase worse, not better. To compute "lines the new commits added or modified": if \`incrementalDiffPath\` from step 2 is present, use it directly. Otherwise, take the prior Pullfrog review's \`commit_id\` (returned alongside each entry from \`${t("list_pull_request_reviews")}\` in step 4) and run \`git diff <prior-review-sha>..HEAD\` to isolate the lines added since that review.
|
|
106564
106622
|
|
|
106565
|
-
**Hunt for non-anchored concerns before drafting.** After collecting your anchored findings, deliberately scan for concerns that have no specific line to point at \u2014 typically: deletion / cleanup plans for code the new commits replace or shadow; rollout sequencing (what happens to in-flight state during deploy / revert?); scope questions that only the human can answer (e.g. is the legacy path going away or is this a long-term dual track?); architectural risks the new commits open up that aren't a single-line bug.
|
|
106566
|
-
|
|
106567
106623
|
draft inline comments with NEW line numbers from the full PR diff \u2014 attach a \`<details>Technical details</details>\` block to any inline comment whose fix is non-trivial or has cross-file implications (see Inline technical details in the format below). every comment must be actionable, 2-3 sentences max in the visible part, one per root cause \u2014 name its other sites in that comment rather than repeating it.
|
|
106568
106624
|
|
|
106569
|
-
9. **build the review body**: use the same default format as Review mode (preamble + optional cross-cutting \`### \` sections
|
|
106625
|
+
9. **build the review body**: use the same default format as Review mode (preamble + optional cross-cutting \`### \` sections) \u2014 scoped to the **incremental delta**, not the full PR. The "Reviewed changes" bullets describe what changed since the prior pullfrog review (each bullet starts with a past-tense verb, e.g. \`- Extracted shared CLI runtime into a single module\`). Do NOT include a separate "Prior review feedback" checklist \u2014 that's tracked in the rolling PR summary snapshot for the next agent run, and surfacing it in the user-facing body is noise (changes that addressed prior feedback are already covered by the Reviewed-changes bullets). In some cases you may receive a complete diff for the whole PR instead of an incremental one; when this happens, determine what changed since Pullfrog's most recent review yourself before drafting bullets.
|
|
106570
106626
|
|
|
106571
106627
|
10. Submit \u2014 every run must end with EXACTLY ONE of \`${t("create_pull_request_review")}\` (substantive review) or \`${t("report_progress")}\` (no-review acknowledgement). do NOT call \`create_issue_comment\` for review output.
|
|
106572
106628
|
|
|
@@ -106574,10 +106630,10 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
106574
106630
|
|
|
106575
106631
|
Follow these rules:
|
|
106576
106632
|
- note: the first create_pull_request_review submission may error with a one-time diff-coverage nudge listing unread TOC regions. retry the same call to proceed \u2014 optionally after reading the listed ranges. the pre-flight will not block again this session.
|
|
106577
|
-
- IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Instead call \`${t("report_progress")}\` with a 1-2 sentence note explaining no review was warranted (e.g. "No new issues. Changes since last review are formatting-only."). this leaves a visible signal that the run completed.
|
|
106633
|
+
- IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Instead call \`${t("report_progress")}\` with \`no_review_needed: true\` and a 1-2 sentence note explaining no review was warranted (e.g. "No new issues. Changes since last review are formatting-only."). this leaves a visible signal that the run completed.
|
|
106578
106634
|
- ELSE IF NEW CRITICAL ISSUES (blocks merge \u2014 bugs, security, data loss, broken core flows): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!CAUTION]\\n> This PR introduces ...\`, followed by the PR summary using the default format below.
|
|
106579
106635
|
- ELSE IF NEW MUST-ADDRESS NON-CRITICAL FINDINGS (real consequences if shipped \u2014 incorrect behavior, missing validation, regressions the author should fix before merge): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!IMPORTANT]\\n> ...\`, followed by the PR summary using the default format below. Do NOT use this tier for nits, style preferences, or "consider also" suggestions.
|
|
106580
|
-
- ELSE IF NEW MINOR SUGGESTIONS ONLY (low-stakes findings
|
|
106636
|
+
- ELSE IF NEW MINOR SUGGESTIONS ONLY (low-stakes findings): call \`${t("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> \u2139\uFE0F No critical issues \u2014 minor suggestions inline.\\n\\n\` (vary the wording after \u2139\uFE0F to fit the review), followed by the PR summary using the default format below.
|
|
106581
106637
|
- ELSE IF INFORMATIONAL OBSERVATIONS (mergeable as-is, but worth surfacing \u2014 e.g. prior feedback addressed cleanly, or a noteworthy positive observation): call \`${t("create_pull_request_review")}\` with \`approved: true\`, NO inline comments, and the review body. body opens with \`> \u2705 No new issues found.\\n\\n\` (or similar friendly green opener), followed by the PR summary using the default format below. If a point is concrete enough to anchor to a line, downgrade the whole review to "minor suggestions only" (\`approved: false\`) instead \u2014 the \u2705 signals "no action needed", which contradicts an actionable anchor.
|
|
106582
106638
|
- ELSE IF NO NEW ISSUES, SUBSTANTIVE CHANGES (new functionality, behavior changes, or fixes to prior review feedback): call \`${t("create_pull_request_review")}\` to create a PR review. If all previous reviews have been properly addressed and no new issues were discovered, set \`approved: true\`. body opens with \`> \u2705 No new issues found.\\n\\n\`, followed by the PR summary using the default format below.
|
|
106583
106639
|
|
|
@@ -106735,7 +106791,7 @@ function buildUnsubmittedReviewPrompt(mode) {
|
|
|
106735
106791
|
"",
|
|
106736
106792
|
"do exactly one of:",
|
|
106737
106793
|
"- if you have findings: call `create_pull_request_review` now with your aggregated review (body + inline comments). the first call may error once with a diff-coverage nudge \u2014 retry the same call to proceed.",
|
|
106738
|
-
"- if there are genuinely no actionable findings since the last review (e.g. only formatting / comment / lockfile changes): call `report_progress` with a 1-2 sentence summary explaining that no review was warranted.",
|
|
106794
|
+
"- if there are genuinely no actionable findings since the last review (e.g. only formatting / comment / lockfile changes): call `report_progress` with `no_review_needed: true` and a 1-2 sentence summary explaining that no review was warranted.",
|
|
106739
106795
|
"",
|
|
106740
106796
|
"do NOT stop again until one of those tools has been called successfully."
|
|
106741
106797
|
].join("\n");
|
|
@@ -107716,6 +107772,8 @@ var claude = agent({
|
|
|
107716
107772
|
PWD: repoDir
|
|
107717
107773
|
};
|
|
107718
107774
|
env2.CLAUDE_CODE_AUTO_COMPACT_WINDOW ||= "500000";
|
|
107775
|
+
env2.CLAUDE_CODE_ENABLE_TODO_TOOLS = "1";
|
|
107776
|
+
env2.CLAUDE_CODE_ENABLE_TASKS = "0";
|
|
107719
107777
|
if (isBedrockRoute) {
|
|
107720
107778
|
env2.CLAUDE_CODE_USE_BEDROCK = "1";
|
|
107721
107779
|
}
|
|
@@ -107792,7 +107850,7 @@ import { performance as performance6 } from "node:perf_hooks";
|
|
|
107792
107850
|
|
|
107793
107851
|
// utils/codexHome.ts
|
|
107794
107852
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
107795
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
107853
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync5, mkdtempSync, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
107796
107854
|
import { homedir as homedir2, userInfo } from "node:os";
|
|
107797
107855
|
import { join as join5 } from "node:path";
|
|
107798
107856
|
|
|
@@ -107843,205 +107901,6 @@ function stringifyCodexAuthBody(body) {
|
|
|
107843
107901
|
`;
|
|
107844
107902
|
}
|
|
107845
107903
|
|
|
107846
|
-
// utils/xaiOAuth.ts
|
|
107847
|
-
function parseXaiAuthBody(raw2) {
|
|
107848
|
-
let parsed2;
|
|
107849
|
-
try {
|
|
107850
|
-
parsed2 = JSON.parse(raw2);
|
|
107851
|
-
} catch {
|
|
107852
|
-
return null;
|
|
107853
|
-
}
|
|
107854
|
-
if (!parsed2 || typeof parsed2 !== "object") return null;
|
|
107855
|
-
const v = parsed2;
|
|
107856
|
-
if (v.auth_mode !== "grok") return null;
|
|
107857
|
-
const tokens = v.tokens;
|
|
107858
|
-
if (!tokens || typeof tokens !== "object") return null;
|
|
107859
|
-
const t = tokens;
|
|
107860
|
-
if (typeof t.access_token !== "string" || t.access_token.length === 0) return null;
|
|
107861
|
-
if (typeof t.refresh_token !== "string" || t.refresh_token.length === 0) return null;
|
|
107862
|
-
return {
|
|
107863
|
-
auth_mode: "grok",
|
|
107864
|
-
...typeof v.refresh_rejected_at === "string" ? { refresh_rejected_at: v.refresh_rejected_at } : {},
|
|
107865
|
-
tokens: { access_token: t.access_token, refresh_token: t.refresh_token },
|
|
107866
|
-
...typeof v.last_refresh === "string" ? { last_refresh: v.last_refresh } : {}
|
|
107867
|
-
};
|
|
107868
|
-
}
|
|
107869
|
-
|
|
107870
|
-
// utils/codexHome.ts
|
|
107871
|
-
var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
|
|
107872
|
-
var XAI_AUTH_ENV = "GROK_AUTH_JSON";
|
|
107873
|
-
var installedSubscriptionPaths = /* @__PURE__ */ new Map();
|
|
107874
|
-
function clearInstalledSubscription(name) {
|
|
107875
|
-
const path4 = installedSubscriptionPaths.get(name);
|
|
107876
|
-
if (!path4 || !existsSync4(path4)) return;
|
|
107877
|
-
const value2 = JSON.parse(readFileSync2(path4, "utf8"));
|
|
107878
|
-
if (!value2 || typeof value2 !== "object") return;
|
|
107879
|
-
if (name === "CODEX_AUTH_JSON" && "openai" in value2) delete value2.openai;
|
|
107880
|
-
if (name === "GROK_AUTH_JSON" && "xai" in value2) delete value2.xai;
|
|
107881
|
-
writeFileSync4(path4, `${JSON.stringify(value2)}
|
|
107882
|
-
`, { mode: 384 });
|
|
107883
|
-
installedSubscriptionPaths.delete(name);
|
|
107884
|
-
}
|
|
107885
|
-
var PULLFROG_DATA_DIR = "/var/lib/pullfrog";
|
|
107886
|
-
function isRejectedChain(body) {
|
|
107887
|
-
if (!body.refresh_rejected_at) return false;
|
|
107888
|
-
log.warning(
|
|
107889
|
-
`\xBB ${CODEX_AUTH_ENV} was rejected by OpenAI at ${body.refresh_rejected_at} and cannot be refreshed \u2014 re-run \`npx pullfrog auth codex\`. skipping it for this run.`
|
|
107890
|
-
);
|
|
107891
|
-
return true;
|
|
107892
|
-
}
|
|
107893
|
-
function installCodexAuth() {
|
|
107894
|
-
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
107895
|
-
if (!raw2) return null;
|
|
107896
|
-
const body = parseCodexAuthBody(raw2);
|
|
107897
|
-
if (!body) {
|
|
107898
|
-
log.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
107899
|
-
return null;
|
|
107900
|
-
}
|
|
107901
|
-
if (isRejectedChain(body)) return null;
|
|
107902
|
-
const expiresMs = decodeJwtExpMs(body.tokens.access_token) ?? 0;
|
|
107903
|
-
const xdgDataHome = resolveDataHome();
|
|
107904
|
-
if (!xdgDataHome) return null;
|
|
107905
|
-
const opencodeDir = join5(xdgDataHome, "opencode");
|
|
107906
|
-
const authPath = join5(opencodeDir, "auth.json");
|
|
107907
|
-
writeOpenCodeAuthEntry({
|
|
107908
|
-
opencodeDir,
|
|
107909
|
-
authPath,
|
|
107910
|
-
provider: "openai",
|
|
107911
|
-
entry: {
|
|
107912
|
-
type: "oauth",
|
|
107913
|
-
refresh: body.tokens.refresh_token,
|
|
107914
|
-
access: body.tokens.access_token,
|
|
107915
|
-
expires: expiresMs,
|
|
107916
|
-
...body.tokens.account_id ? { accountId: body.tokens.account_id } : {}
|
|
107917
|
-
}
|
|
107918
|
-
});
|
|
107919
|
-
process.env.XDG_DATA_HOME = xdgDataHome;
|
|
107920
|
-
log.info(`\xBB installed Codex auth at ${authPath}`);
|
|
107921
|
-
installedSubscriptionPaths.set(CODEX_AUTH_ENV, authPath);
|
|
107922
|
-
return {
|
|
107923
|
-
authPath,
|
|
107924
|
-
xdgDataHome,
|
|
107925
|
-
originalRefresh: body.tokens.refresh_token,
|
|
107926
|
-
originalIdToken: body.tokens.id_token
|
|
107927
|
-
};
|
|
107928
|
-
}
|
|
107929
|
-
function writeOpenCodeAuthEntry(params) {
|
|
107930
|
-
let existing = {};
|
|
107931
|
-
if (existsSync4(params.authPath)) {
|
|
107932
|
-
try {
|
|
107933
|
-
const parsed2 = JSON.parse(readFileSync2(params.authPath, "utf8"));
|
|
107934
|
-
if (parsed2 && typeof parsed2 === "object") existing = parsed2;
|
|
107935
|
-
} catch {
|
|
107936
|
-
log.warning(`\xBB ${params.authPath} was unreadable; rewriting it`);
|
|
107937
|
-
}
|
|
107938
|
-
}
|
|
107939
|
-
const merged = { ...existing, [params.provider]: params.entry };
|
|
107940
|
-
mkdirSync5(params.opencodeDir, { recursive: true });
|
|
107941
|
-
writeFileSync4(params.authPath, `${JSON.stringify(merged, null, 2)}
|
|
107942
|
-
`, { mode: 384 });
|
|
107943
|
-
}
|
|
107944
|
-
function installXaiAuth() {
|
|
107945
|
-
const raw2 = process.env[XAI_AUTH_ENV];
|
|
107946
|
-
if (!raw2) return null;
|
|
107947
|
-
const body = parseXaiAuthBody(raw2);
|
|
107948
|
-
if (!body) {
|
|
107949
|
-
log.warning(`\xBB ${XAI_AUTH_ENV} present but malformed; ignoring`);
|
|
107950
|
-
return null;
|
|
107951
|
-
}
|
|
107952
|
-
if (isXaiRejectedChain(body)) return null;
|
|
107953
|
-
const xdgDataHome = resolveDataHome();
|
|
107954
|
-
if (!xdgDataHome) return null;
|
|
107955
|
-
const opencodeDir = join5(xdgDataHome, "opencode");
|
|
107956
|
-
const authPath = join5(opencodeDir, "auth.json");
|
|
107957
|
-
writeOpenCodeAuthEntry({
|
|
107958
|
-
opencodeDir,
|
|
107959
|
-
authPath,
|
|
107960
|
-
provider: "xai",
|
|
107961
|
-
// opencode refreshes when `expires` is inside its skew window, and falls
|
|
107962
|
-
// back to the JWT's own exp when the stored value is absent. Decoding it
|
|
107963
|
-
// here means the first request uses the token we already hold instead of
|
|
107964
|
-
// burning a rotation on startup.
|
|
107965
|
-
entry: {
|
|
107966
|
-
type: "oauth",
|
|
107967
|
-
refresh: body.tokens.refresh_token,
|
|
107968
|
-
access: body.tokens.access_token,
|
|
107969
|
-
expires: decodeJwtExpMs(body.tokens.access_token) ?? 0
|
|
107970
|
-
}
|
|
107971
|
-
});
|
|
107972
|
-
process.env.XDG_DATA_HOME = xdgDataHome;
|
|
107973
|
-
log.info(`\xBB installed Grok auth at ${authPath}`);
|
|
107974
|
-
installedSubscriptionPaths.set(XAI_AUTH_ENV, authPath);
|
|
107975
|
-
return { authPath, xdgDataHome, originalRefresh: body.tokens.refresh_token };
|
|
107976
|
-
}
|
|
107977
|
-
function isXaiRejectedChain(body) {
|
|
107978
|
-
if (!body.refresh_rejected_at) return false;
|
|
107979
|
-
log.warning(
|
|
107980
|
-
`\xBB ${XAI_AUTH_ENV} was rejected by xAI at ${body.refresh_rejected_at} and cannot be refreshed \u2014 re-run \`npx pullfrog auth grok\`. skipping it for this run.`
|
|
107981
|
-
);
|
|
107982
|
-
return true;
|
|
107983
|
-
}
|
|
107984
|
-
function installCodexHome() {
|
|
107985
|
-
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
107986
|
-
if (!raw2) return null;
|
|
107987
|
-
const body = parseCodexAuthBody(raw2);
|
|
107988
|
-
if (!body) {
|
|
107989
|
-
log.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
107990
|
-
return null;
|
|
107991
|
-
}
|
|
107992
|
-
if (isRejectedChain(body)) return null;
|
|
107993
|
-
if (!body.tokens.id_token) {
|
|
107994
|
-
log.warning(
|
|
107995
|
-
`\xBB ${CODEX_AUTH_ENV} carries no id_token \u2014 the codex CLI cannot load it. re-run \`npx pullfrog auth codex\` to mint a complete credential.`
|
|
107996
|
-
);
|
|
107997
|
-
return null;
|
|
107998
|
-
}
|
|
107999
|
-
const root = resolveDataHome();
|
|
108000
|
-
if (!root) return null;
|
|
108001
|
-
const codexHome = join5(root, "codex");
|
|
108002
|
-
const authPath = join5(codexHome, "auth.json");
|
|
108003
|
-
mkdirSync5(codexHome, { recursive: true });
|
|
108004
|
-
writeFileSync4(authPath, stringifyCodexAuthBody(body), { mode: 384 });
|
|
108005
|
-
log.info(`\xBB installed Codex auth at ${authPath}`);
|
|
108006
|
-
return { codexHome, authPath, originalRefresh: body.tokens.refresh_token };
|
|
108007
|
-
}
|
|
108008
|
-
var dataHome;
|
|
108009
|
-
var unhostedSubscriptions = /* @__PURE__ */ new Set();
|
|
108010
|
-
function canInstallSubscription(name) {
|
|
108011
|
-
return name !== CODEX_AUTH_ENV && name !== XAI_AUTH_ENV || resolveDataHome() !== null;
|
|
108012
|
-
}
|
|
108013
|
-
function resolveDataHome() {
|
|
108014
|
-
if (process.env.CI !== "true") return join5(homedir2(), ".local", "share");
|
|
108015
|
-
if (dataHome === void 0) dataHome = bootstrapPullfrogDataDir();
|
|
108016
|
-
return dataHome;
|
|
108017
|
-
}
|
|
108018
|
-
function bootstrapPullfrogDataDir() {
|
|
108019
|
-
const user = userInfo().username;
|
|
108020
|
-
let primaryGroup;
|
|
108021
|
-
try {
|
|
108022
|
-
primaryGroup = execFileSync3("id", ["-gn", user], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
108023
|
-
} catch {
|
|
108024
|
-
primaryGroup = user;
|
|
108025
|
-
}
|
|
108026
|
-
try {
|
|
108027
|
-
execFileSync3("sudo", ["-n", "mkdir", "-p", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
108028
|
-
execFileSync3("sudo", ["-n", "chown", `${user}:${primaryGroup}`, PULLFROG_DATA_DIR], {
|
|
108029
|
-
stdio: "pipe"
|
|
108030
|
-
});
|
|
108031
|
-
execFileSync3("sudo", ["-n", "chmod", "700", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
108032
|
-
} catch (err) {
|
|
108033
|
-
log.warning(
|
|
108034
|
-
`\xBB subscription auth skipped: could not create ${PULLFROG_DATA_DIR} (${err instanceof Error ? err.message : String(err)}). it must live outside the agent sandbox's reach, which needs passwordless sudo on this runner; runs on a model that needs the subscription will report no key.`
|
|
108035
|
-
);
|
|
108036
|
-
for (const name of [CODEX_AUTH_ENV, XAI_AUTH_ENV]) {
|
|
108037
|
-
if (process.env[name]) unhostedSubscriptions.add(name);
|
|
108038
|
-
delete process.env[name];
|
|
108039
|
-
}
|
|
108040
|
-
return null;
|
|
108041
|
-
}
|
|
108042
|
-
return PULLFROG_DATA_DIR;
|
|
108043
|
-
}
|
|
108044
|
-
|
|
108045
107904
|
// utils/oauthWriteback.ts
|
|
108046
107905
|
var core2 = __toESM(require_core(), 1);
|
|
108047
107906
|
|
|
@@ -110271,6 +110130,7 @@ async function apiFetch(options) {
|
|
|
110271
110130
|
|
|
110272
110131
|
// utils/oauthWriteback.ts
|
|
110273
110132
|
var OAUTH_WRITEBACK_STATE = "oauth_writeback";
|
|
110133
|
+
var SUBSCRIPTION_DATA_DIR_STATE = "subscription_data_dir";
|
|
110274
110134
|
|
|
110275
110135
|
// utils/secretCommands.ts
|
|
110276
110136
|
var core3 = __toESM(require_core(), 1);
|
|
@@ -110281,6 +110141,212 @@ function saveSecretState(name, value2) {
|
|
|
110281
110141
|
if (isGitHubActions) core3.saveState(name, value2);
|
|
110282
110142
|
}
|
|
110283
110143
|
|
|
110144
|
+
// utils/xaiOAuth.ts
|
|
110145
|
+
function parseXaiAuthBody(raw2) {
|
|
110146
|
+
let parsed2;
|
|
110147
|
+
try {
|
|
110148
|
+
parsed2 = JSON.parse(raw2);
|
|
110149
|
+
} catch {
|
|
110150
|
+
return null;
|
|
110151
|
+
}
|
|
110152
|
+
if (!parsed2 || typeof parsed2 !== "object") return null;
|
|
110153
|
+
const v = parsed2;
|
|
110154
|
+
if (v.auth_mode !== "grok") return null;
|
|
110155
|
+
const tokens = v.tokens;
|
|
110156
|
+
if (!tokens || typeof tokens !== "object") return null;
|
|
110157
|
+
const t = tokens;
|
|
110158
|
+
if (typeof t.access_token !== "string" || t.access_token.length === 0) return null;
|
|
110159
|
+
if (typeof t.refresh_token !== "string" || t.refresh_token.length === 0) return null;
|
|
110160
|
+
return {
|
|
110161
|
+
auth_mode: "grok",
|
|
110162
|
+
...typeof v.refresh_rejected_at === "string" ? { refresh_rejected_at: v.refresh_rejected_at } : {},
|
|
110163
|
+
tokens: { access_token: t.access_token, refresh_token: t.refresh_token },
|
|
110164
|
+
...typeof v.last_refresh === "string" ? { last_refresh: v.last_refresh } : {}
|
|
110165
|
+
};
|
|
110166
|
+
}
|
|
110167
|
+
|
|
110168
|
+
// utils/codexHome.ts
|
|
110169
|
+
var CODEX_AUTH_ENV = "CODEX_AUTH_JSON";
|
|
110170
|
+
var XAI_AUTH_ENV = "GROK_AUTH_JSON";
|
|
110171
|
+
var installedSubscriptionPaths = /* @__PURE__ */ new Map();
|
|
110172
|
+
var installedDataHome;
|
|
110173
|
+
function getSubscriptionDataHome() {
|
|
110174
|
+
return installedDataHome;
|
|
110175
|
+
}
|
|
110176
|
+
function clearInstalledSubscription(name) {
|
|
110177
|
+
const path4 = installedSubscriptionPaths.get(name);
|
|
110178
|
+
if (!path4 || !existsSync4(path4)) return;
|
|
110179
|
+
const value2 = JSON.parse(readFileSync2(path4, "utf8"));
|
|
110180
|
+
if (!value2 || typeof value2 !== "object") return;
|
|
110181
|
+
if (name === "CODEX_AUTH_JSON" && "openai" in value2) delete value2.openai;
|
|
110182
|
+
if (name === "GROK_AUTH_JSON" && "xai" in value2) delete value2.xai;
|
|
110183
|
+
writeFileSync4(path4, `${JSON.stringify(value2)}
|
|
110184
|
+
`, { mode: 384 });
|
|
110185
|
+
installedSubscriptionPaths.delete(name);
|
|
110186
|
+
}
|
|
110187
|
+
var PULLFROG_DATA_DIR = "/var/lib/pullfrog";
|
|
110188
|
+
function isRejectedChain(body) {
|
|
110189
|
+
if (!body.refresh_rejected_at) return false;
|
|
110190
|
+
log.warning(
|
|
110191
|
+
`\xBB ${CODEX_AUTH_ENV} was rejected by OpenAI at ${body.refresh_rejected_at} and cannot be refreshed \u2014 re-run \`npx pullfrog auth codex\`. skipping it for this run.`
|
|
110192
|
+
);
|
|
110193
|
+
return true;
|
|
110194
|
+
}
|
|
110195
|
+
function installCodexAuth() {
|
|
110196
|
+
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
110197
|
+
if (!raw2) return null;
|
|
110198
|
+
const body = parseCodexAuthBody(raw2);
|
|
110199
|
+
if (!body) {
|
|
110200
|
+
log.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
110201
|
+
return null;
|
|
110202
|
+
}
|
|
110203
|
+
if (isRejectedChain(body)) return null;
|
|
110204
|
+
const expiresMs = decodeJwtExpMs(body.tokens.access_token) ?? 0;
|
|
110205
|
+
const xdgDataHome = resolveDataHome();
|
|
110206
|
+
if (!xdgDataHome) return null;
|
|
110207
|
+
const opencodeDir = join5(xdgDataHome, "opencode");
|
|
110208
|
+
const authPath = join5(opencodeDir, "auth.json");
|
|
110209
|
+
writeOpenCodeAuthEntry({
|
|
110210
|
+
opencodeDir,
|
|
110211
|
+
authPath,
|
|
110212
|
+
provider: "openai",
|
|
110213
|
+
entry: {
|
|
110214
|
+
type: "oauth",
|
|
110215
|
+
refresh: body.tokens.refresh_token,
|
|
110216
|
+
access: body.tokens.access_token,
|
|
110217
|
+
expires: expiresMs,
|
|
110218
|
+
...body.tokens.account_id ? { accountId: body.tokens.account_id } : {}
|
|
110219
|
+
}
|
|
110220
|
+
});
|
|
110221
|
+
installedDataHome = xdgDataHome;
|
|
110222
|
+
log.info(`\xBB installed Codex auth at ${authPath}`);
|
|
110223
|
+
installedSubscriptionPaths.set(CODEX_AUTH_ENV, authPath);
|
|
110224
|
+
return {
|
|
110225
|
+
authPath,
|
|
110226
|
+
originalRefresh: body.tokens.refresh_token,
|
|
110227
|
+
originalIdToken: body.tokens.id_token
|
|
110228
|
+
};
|
|
110229
|
+
}
|
|
110230
|
+
function writeOpenCodeAuthEntry(params) {
|
|
110231
|
+
let existing = {};
|
|
110232
|
+
if (existsSync4(params.authPath)) {
|
|
110233
|
+
try {
|
|
110234
|
+
const parsed2 = JSON.parse(readFileSync2(params.authPath, "utf8"));
|
|
110235
|
+
if (parsed2 && typeof parsed2 === "object") existing = parsed2;
|
|
110236
|
+
} catch {
|
|
110237
|
+
log.warning(`\xBB ${params.authPath} was unreadable; rewriting it`);
|
|
110238
|
+
}
|
|
110239
|
+
}
|
|
110240
|
+
const merged = { ...existing, [params.provider]: params.entry };
|
|
110241
|
+
mkdirSync5(params.opencodeDir, { recursive: true });
|
|
110242
|
+
writeFileSync4(params.authPath, `${JSON.stringify(merged, null, 2)}
|
|
110243
|
+
`, { mode: 384 });
|
|
110244
|
+
}
|
|
110245
|
+
function installXaiAuth() {
|
|
110246
|
+
const raw2 = process.env[XAI_AUTH_ENV];
|
|
110247
|
+
if (!raw2) return null;
|
|
110248
|
+
const body = parseXaiAuthBody(raw2);
|
|
110249
|
+
if (!body) {
|
|
110250
|
+
log.warning(`\xBB ${XAI_AUTH_ENV} present but malformed; ignoring`);
|
|
110251
|
+
return null;
|
|
110252
|
+
}
|
|
110253
|
+
if (isXaiRejectedChain(body)) return null;
|
|
110254
|
+
const xdgDataHome = resolveDataHome();
|
|
110255
|
+
if (!xdgDataHome) return null;
|
|
110256
|
+
const opencodeDir = join5(xdgDataHome, "opencode");
|
|
110257
|
+
const authPath = join5(opencodeDir, "auth.json");
|
|
110258
|
+
writeOpenCodeAuthEntry({
|
|
110259
|
+
opencodeDir,
|
|
110260
|
+
authPath,
|
|
110261
|
+
provider: "xai",
|
|
110262
|
+
// opencode refreshes when `expires` is inside its skew window, and falls
|
|
110263
|
+
// back to the JWT's own exp when the stored value is absent. Decoding it
|
|
110264
|
+
// here means the first request uses the token we already hold instead of
|
|
110265
|
+
// burning a rotation on startup.
|
|
110266
|
+
entry: {
|
|
110267
|
+
type: "oauth",
|
|
110268
|
+
refresh: body.tokens.refresh_token,
|
|
110269
|
+
access: body.tokens.access_token,
|
|
110270
|
+
expires: decodeJwtExpMs(body.tokens.access_token) ?? 0
|
|
110271
|
+
}
|
|
110272
|
+
});
|
|
110273
|
+
installedDataHome = xdgDataHome;
|
|
110274
|
+
log.info(`\xBB installed Grok auth at ${authPath}`);
|
|
110275
|
+
installedSubscriptionPaths.set(XAI_AUTH_ENV, authPath);
|
|
110276
|
+
return { authPath, originalRefresh: body.tokens.refresh_token };
|
|
110277
|
+
}
|
|
110278
|
+
function isXaiRejectedChain(body) {
|
|
110279
|
+
if (!body.refresh_rejected_at) return false;
|
|
110280
|
+
log.warning(
|
|
110281
|
+
`\xBB ${XAI_AUTH_ENV} was rejected by xAI at ${body.refresh_rejected_at} and cannot be refreshed \u2014 re-run \`npx pullfrog auth grok\`. skipping it for this run.`
|
|
110282
|
+
);
|
|
110283
|
+
return true;
|
|
110284
|
+
}
|
|
110285
|
+
function installCodexHome() {
|
|
110286
|
+
const raw2 = process.env[CODEX_AUTH_ENV];
|
|
110287
|
+
if (!raw2) return null;
|
|
110288
|
+
const body = parseCodexAuthBody(raw2);
|
|
110289
|
+
if (!body) {
|
|
110290
|
+
log.warning(`\xBB ${CODEX_AUTH_ENV} present but malformed; ignoring`);
|
|
110291
|
+
return null;
|
|
110292
|
+
}
|
|
110293
|
+
if (isRejectedChain(body)) return null;
|
|
110294
|
+
if (!body.tokens.id_token) {
|
|
110295
|
+
log.warning(
|
|
110296
|
+
`\xBB ${CODEX_AUTH_ENV} carries no id_token \u2014 the codex CLI cannot load it. re-run \`npx pullfrog auth codex\` to mint a complete credential.`
|
|
110297
|
+
);
|
|
110298
|
+
return null;
|
|
110299
|
+
}
|
|
110300
|
+
const root = resolveDataHome();
|
|
110301
|
+
if (!root) return null;
|
|
110302
|
+
const codexHome = join5(root, "codex");
|
|
110303
|
+
const authPath = join5(codexHome, "auth.json");
|
|
110304
|
+
mkdirSync5(codexHome, { recursive: true });
|
|
110305
|
+
writeFileSync4(authPath, stringifyCodexAuthBody(body), { mode: 384 });
|
|
110306
|
+
log.info(`\xBB installed Codex auth at ${authPath}`);
|
|
110307
|
+
return { codexHome, authPath, originalRefresh: body.tokens.refresh_token };
|
|
110308
|
+
}
|
|
110309
|
+
var dataHome;
|
|
110310
|
+
var unhostedSubscriptions = /* @__PURE__ */ new Set();
|
|
110311
|
+
function canInstallSubscription(name) {
|
|
110312
|
+
return name !== CODEX_AUTH_ENV && name !== XAI_AUTH_ENV || resolveDataHome() !== null;
|
|
110313
|
+
}
|
|
110314
|
+
function resolveDataHome() {
|
|
110315
|
+
if (process.env.CI !== "true") return join5(homedir2(), ".local", "share");
|
|
110316
|
+
if (dataHome === void 0) dataHome = bootstrapPullfrogDataDir();
|
|
110317
|
+
return dataHome;
|
|
110318
|
+
}
|
|
110319
|
+
function bootstrapPullfrogDataDir() {
|
|
110320
|
+
const user = userInfo().username;
|
|
110321
|
+
let primaryGroup;
|
|
110322
|
+
try {
|
|
110323
|
+
primaryGroup = execFileSync3("id", ["-gn", user], { stdio: "pipe", encoding: "utf-8" }).trim();
|
|
110324
|
+
} catch {
|
|
110325
|
+
primaryGroup = user;
|
|
110326
|
+
}
|
|
110327
|
+
try {
|
|
110328
|
+
execFileSync3("sudo", ["-n", "mkdir", "-p", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
110329
|
+
execFileSync3("sudo", ["-n", "chown", `${user}:${primaryGroup}`, PULLFROG_DATA_DIR], {
|
|
110330
|
+
stdio: "pipe"
|
|
110331
|
+
});
|
|
110332
|
+
execFileSync3("sudo", ["-n", "chmod", "700", PULLFROG_DATA_DIR], { stdio: "pipe" });
|
|
110333
|
+
} catch (err) {
|
|
110334
|
+
log.warning(
|
|
110335
|
+
`\xBB subscription auth skipped: could not create ${PULLFROG_DATA_DIR} (${err instanceof Error ? err.message : String(err)}). it must live outside the agent sandbox's reach, which needs passwordless sudo on this runner; runs on a model that needs the subscription will report no key.`
|
|
110336
|
+
);
|
|
110337
|
+
for (const name of [CODEX_AUTH_ENV, XAI_AUTH_ENV]) {
|
|
110338
|
+
if (process.env[name]) unhostedSubscriptions.add(name);
|
|
110339
|
+
delete process.env[name];
|
|
110340
|
+
}
|
|
110341
|
+
return null;
|
|
110342
|
+
}
|
|
110343
|
+
const runDir = mkdtempSync(join5(PULLFROG_DATA_DIR, "run-"));
|
|
110344
|
+
if (process.env.RUNNER_ENVIRONMENT !== "github-hosted") {
|
|
110345
|
+
saveSecretState(SUBSCRIPTION_DATA_DIR_STATE, runDir);
|
|
110346
|
+
}
|
|
110347
|
+
return runDir;
|
|
110348
|
+
}
|
|
110349
|
+
|
|
110284
110350
|
// utils/secrets.ts
|
|
110285
110351
|
var SENSITIVE_PATTERNS = [
|
|
110286
110352
|
/_KEY$/i,
|
|
@@ -110927,9 +110993,8 @@ var codex = agent({
|
|
|
110927
110993
|
initialUsage: initial.usage,
|
|
110928
110994
|
reflectionPrompt: buildReflectionPrompt(ctx.toolState),
|
|
110929
110995
|
// a resume needs the thread codex recorded. without one there is nothing
|
|
110930
|
-
// to continue, and `resume --last`
|
|
110931
|
-
//
|
|
110932
|
-
// runner with a shared CODEX_HOME is somebody else's run.
|
|
110996
|
+
// to continue, and `resume --last` could pick another run's session off CI,
|
|
110997
|
+
// where CODEX_HOME is the shared ~/.local/share/codex (in CI it is per run).
|
|
110933
110998
|
canResume: (r) => r.threadId !== void 0,
|
|
110934
110999
|
resume: async (c) => runCodex({
|
|
110935
111000
|
...runnerArgs,
|
|
@@ -110955,7 +111020,8 @@ var codex = agent({
|
|
|
110955
111020
|
// agents/opencode.ts
|
|
110956
111021
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
110957
111022
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
110958
|
-
import {
|
|
111023
|
+
import { totalmem } from "node:os";
|
|
111024
|
+
import { join as join8 } from "node:path";
|
|
110959
111025
|
import { performance as performance7 } from "node:perf_hooks";
|
|
110960
111026
|
|
|
110961
111027
|
// node_modules/.pnpm/@opencode-ai+sdk@1.18.29/node_modules/@opencode-ai/sdk/dist/v2/gen/core/serverSentEvents.gen.js
|
|
@@ -111232,13 +111298,13 @@ var defaultPathSerializer = ({ path: path4, url: _url3 }) => {
|
|
|
111232
111298
|
}
|
|
111233
111299
|
return url4;
|
|
111234
111300
|
};
|
|
111235
|
-
var getUrl = ({ baseUrl, path: path4, query, querySerializer, url: _url3 }) => {
|
|
111301
|
+
var getUrl = ({ baseUrl, path: path4, query: query2, querySerializer, url: _url3 }) => {
|
|
111236
111302
|
const pathUrl = _url3.startsWith("/") ? _url3 : `/${_url3}`;
|
|
111237
111303
|
let url4 = (baseUrl ?? "") + pathUrl;
|
|
111238
111304
|
if (path4) {
|
|
111239
111305
|
url4 = defaultPathSerializer({ path: path4, url: url4 });
|
|
111240
111306
|
}
|
|
111241
|
-
let search2 =
|
|
111307
|
+
let search2 = query2 ? querySerializer(query2) : "";
|
|
111242
111308
|
if (search2.startsWith("?")) {
|
|
111243
111309
|
search2 = search2.substring(1);
|
|
111244
111310
|
}
|
|
@@ -116306,9 +116372,9 @@ function rewrite(request2, values) {
|
|
|
116306
116372
|
const value2 = pick2(request2.headers.get(name), key === "directory" ? values.directory : values.workspace, key === "directory" ? encodeURIComponent : void 0);
|
|
116307
116373
|
if (!value2)
|
|
116308
116374
|
continue;
|
|
116309
|
-
for (const
|
|
116310
|
-
if (!url4.searchParams.has(
|
|
116311
|
-
url4.searchParams.set(
|
|
116375
|
+
for (const query2 of url4.pathname.startsWith("/api/") ? [key, `location[${key}]`] : [key]) {
|
|
116376
|
+
if (!url4.searchParams.has(query2)) {
|
|
116377
|
+
url4.searchParams.set(query2, value2);
|
|
116312
116378
|
}
|
|
116313
116379
|
}
|
|
116314
116380
|
changed = true;
|
|
@@ -116364,6 +116430,68 @@ var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
|
116364
116430
|
// agents/opencode.ts
|
|
116365
116431
|
var import_undici = __toESM(require_undici2(), 1);
|
|
116366
116432
|
|
|
116433
|
+
// utils/openCodeModels.ts
|
|
116434
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
116435
|
+
import { join as join7 } from "node:path";
|
|
116436
|
+
var baseline;
|
|
116437
|
+
var authorized;
|
|
116438
|
+
var failure;
|
|
116439
|
+
var ANSI_PATTERN = /\[[0-9;]*m/g;
|
|
116440
|
+
function openCodeHomeEnv(tmpdir3) {
|
|
116441
|
+
return {
|
|
116442
|
+
HOME: tmpdir3,
|
|
116443
|
+
XDG_CONFIG_HOME: join7(tmpdir3, ".config"),
|
|
116444
|
+
XDG_DATA_HOME: getSubscriptionDataHome() ?? join7(tmpdir3, ".local", "share"),
|
|
116445
|
+
XDG_CACHE_HOME: join7(tmpdir3, ".cache"),
|
|
116446
|
+
XDG_STATE_HOME: join7(tmpdir3, ".local", "state")
|
|
116447
|
+
};
|
|
116448
|
+
}
|
|
116449
|
+
function readModels(params) {
|
|
116450
|
+
const result = spawnSync3(params.cliPath, ["models"], {
|
|
116451
|
+
encoding: "utf-8",
|
|
116452
|
+
timeout: 3e4,
|
|
116453
|
+
env: { ...process.env, ...openCodeHomeEnv(params.tmpdir) },
|
|
116454
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
116455
|
+
});
|
|
116456
|
+
if (result.status !== 0) {
|
|
116457
|
+
const stderr = (result.stderr ?? "").replace(ANSI_PATTERN, "").trim();
|
|
116458
|
+
failure = stderr || result.error?.message;
|
|
116459
|
+
log.debug(`\xBB \`opencode models\` failed (${result.status}): ${failure}`);
|
|
116460
|
+
return /* @__PURE__ */ new Set();
|
|
116461
|
+
}
|
|
116462
|
+
failure = void 0;
|
|
116463
|
+
return new Set(
|
|
116464
|
+
result.stdout.split("\n").map((line) => line.trim()).filter(Boolean)
|
|
116465
|
+
);
|
|
116466
|
+
}
|
|
116467
|
+
function getModelsFailure() {
|
|
116468
|
+
return failure;
|
|
116469
|
+
}
|
|
116470
|
+
function captureBaselineModels(params) {
|
|
116471
|
+
baseline = readModels(params);
|
|
116472
|
+
log.debug(`\xBB opencode baseline: ${baseline.size} models`);
|
|
116473
|
+
}
|
|
116474
|
+
function captureAuthorizedModels(params) {
|
|
116475
|
+
authorized = readModels(params);
|
|
116476
|
+
const base = baseline;
|
|
116477
|
+
if (base) {
|
|
116478
|
+
const diff = [...authorized].filter((m) => !base.has(m));
|
|
116479
|
+
if (diff.length > 0) {
|
|
116480
|
+
log.info(`\xBB BYOK auth enabled ${diff.length} model(s): ${diff.join(", ")}`);
|
|
116481
|
+
}
|
|
116482
|
+
}
|
|
116483
|
+
log.debug(`\xBB opencode authorized: ${authorized.size} models`);
|
|
116484
|
+
}
|
|
116485
|
+
function authorizeModel(model) {
|
|
116486
|
+
getAuthorizedModels().add(model);
|
|
116487
|
+
}
|
|
116488
|
+
function getAuthorizedModels() {
|
|
116489
|
+
if (!authorized) {
|
|
116490
|
+
throw new Error("getAuthorizedModels called before captureAuthorizedModels");
|
|
116491
|
+
}
|
|
116492
|
+
return authorized;
|
|
116493
|
+
}
|
|
116494
|
+
|
|
116367
116495
|
// utils/worktree.ts
|
|
116368
116496
|
async function dirtyTrackedPaths(params = {}) {
|
|
116369
116497
|
const result = await spawn({
|
|
@@ -116480,7 +116608,8 @@ export default async function pullfrogEventsPlugin() {
|
|
|
116480
116608
|
};
|
|
116481
116609
|
}
|
|
116482
116610
|
`;
|
|
116483
|
-
function buildOpencodeSubagentGateSource(
|
|
116611
|
+
function buildOpencodeSubagentGateSource(ctx) {
|
|
116612
|
+
const bashRefusal = ctx.payload.shell === "disabled" ? "shell execution is disabled for this run and no shell tool exists \u2014 use read, grep and glob instead." : `native bash is disabled in Pullfrog runs \u2014 call ${formatMcpToolRef("opencode", "shell")} with the same command instead.`;
|
|
116484
116613
|
return `// AUTOGENERATED by Pullfrog. do not edit; it'll be overwritten on the next run.
|
|
116485
116614
|
// hard-blocks state-mutating MCP tool calls from opencode subagents (PR
|
|
116486
116615
|
// following pullfrog/app#796 \u2014 see action/agents/subagentToolGates.ts). see
|
|
@@ -116491,7 +116620,7 @@ function buildOpencodeSubagentGateSource(deniedTools) {
|
|
|
116491
116620
|
// embedded at template-render time so the plugin source has no imports. the
|
|
116492
116621
|
// denied set is derived from each tool's \`mutates\` flag \u2014 see
|
|
116493
116622
|
// action/agents/subagentToolGates.ts.
|
|
116494
|
-
const SUBAGENT_DENIED_TOOLS = new Set(${JSON.stringify(
|
|
116623
|
+
const SUBAGENT_DENIED_TOOLS = new Set(${JSON.stringify(ctx.subagentDeniedTools)});
|
|
116495
116624
|
|
|
116496
116625
|
// opencode presents MCP tools as \`pullfrog_<bare>\`; strip that to compare
|
|
116497
116626
|
// against the canonical bare names in SUBAGENT_DENIED_TOOLS. native tools
|
|
@@ -116527,7 +116656,7 @@ export default async function pullfrogSubagentGatePlugin() {
|
|
|
116527
116656
|
// above the sessionID check: the bash block must never depend on a
|
|
116528
116657
|
// session id being present.
|
|
116529
116658
|
if (tool === "bash") {
|
|
116530
|
-
throw new Error(
|
|
116659
|
+
throw new Error(${JSON.stringify(bashRefusal)});
|
|
116531
116660
|
}
|
|
116532
116661
|
if (!sessionID || !tool) return;
|
|
116533
116662
|
if (orchestratorSessionID === undefined) orchestratorSessionID = sessionID;
|
|
@@ -116547,58 +116676,6 @@ export default async function pullfrogSubagentGatePlugin() {
|
|
|
116547
116676
|
`;
|
|
116548
116677
|
}
|
|
116549
116678
|
|
|
116550
|
-
// utils/openCodeModels.ts
|
|
116551
|
-
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
116552
|
-
var baseline;
|
|
116553
|
-
var authorized;
|
|
116554
|
-
var failure;
|
|
116555
|
-
var ANSI_PATTERN = /\[[0-9;]*m/g;
|
|
116556
|
-
function readModels(cliPath) {
|
|
116557
|
-
const result = spawnSync3(cliPath, ["models"], {
|
|
116558
|
-
encoding: "utf-8",
|
|
116559
|
-
timeout: 3e4,
|
|
116560
|
-
env: process.env,
|
|
116561
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
116562
|
-
});
|
|
116563
|
-
if (result.status !== 0) {
|
|
116564
|
-
const stderr = (result.stderr ?? "").replace(ANSI_PATTERN, "").trim();
|
|
116565
|
-
failure = stderr || result.error?.message;
|
|
116566
|
-
log.debug(`\xBB \`opencode models\` failed (${result.status}): ${failure}`);
|
|
116567
|
-
return /* @__PURE__ */ new Set();
|
|
116568
|
-
}
|
|
116569
|
-
failure = void 0;
|
|
116570
|
-
return new Set(
|
|
116571
|
-
result.stdout.split("\n").map((line) => line.trim()).filter(Boolean)
|
|
116572
|
-
);
|
|
116573
|
-
}
|
|
116574
|
-
function getModelsFailure() {
|
|
116575
|
-
return failure;
|
|
116576
|
-
}
|
|
116577
|
-
function captureBaselineModels(cliPath) {
|
|
116578
|
-
baseline = readModels(cliPath);
|
|
116579
|
-
log.debug(`\xBB opencode baseline: ${baseline.size} models`);
|
|
116580
|
-
}
|
|
116581
|
-
function captureAuthorizedModels(cliPath) {
|
|
116582
|
-
authorized = readModels(cliPath);
|
|
116583
|
-
const base = baseline;
|
|
116584
|
-
if (base) {
|
|
116585
|
-
const diff = [...authorized].filter((m) => !base.has(m));
|
|
116586
|
-
if (diff.length > 0) {
|
|
116587
|
-
log.info(`\xBB BYOK auth enabled ${diff.length} model(s): ${diff.join(", ")}`);
|
|
116588
|
-
}
|
|
116589
|
-
}
|
|
116590
|
-
log.debug(`\xBB opencode authorized: ${authorized.size} models`);
|
|
116591
|
-
}
|
|
116592
|
-
function authorizeModel(model) {
|
|
116593
|
-
getAuthorizedModels().add(model);
|
|
116594
|
-
}
|
|
116595
|
-
function getAuthorizedModels() {
|
|
116596
|
-
if (!authorized) {
|
|
116597
|
-
throw new Error("getAuthorizedModels called before captureAuthorizedModels");
|
|
116598
|
-
}
|
|
116599
|
-
return authorized;
|
|
116600
|
-
}
|
|
116601
|
-
|
|
116602
116679
|
// agents/subagentModels.ts
|
|
116603
116680
|
function deriveSubagentModels(orchestratorSpec) {
|
|
116604
116681
|
if (!orchestratorSpec) return { reviewer: void 0 };
|
|
@@ -116828,11 +116905,12 @@ function bootOpencodeServer(params) {
|
|
|
116828
116905
|
log.debug(`[opencode serve] ${text}`);
|
|
116829
116906
|
});
|
|
116830
116907
|
let closed = false;
|
|
116908
|
+
let exitCause;
|
|
116831
116909
|
const close = async () => {
|
|
116832
116910
|
if (closed) return;
|
|
116833
116911
|
closed = true;
|
|
116834
116912
|
untrackChild(proc);
|
|
116835
|
-
if (proc.pid &&
|
|
116913
|
+
if (proc.pid && proc.exitCode === null && proc.signalCode === null) {
|
|
116836
116914
|
try {
|
|
116837
116915
|
process.kill(-proc.pid, "SIGTERM");
|
|
116838
116916
|
} catch {
|
|
@@ -116866,7 +116944,7 @@ function bootOpencodeServer(params) {
|
|
|
116866
116944
|
if (match3?.[1]) {
|
|
116867
116945
|
resolved = true;
|
|
116868
116946
|
log.info(`\xBB opencode server up: ${match3[1]}`);
|
|
116869
|
-
resolve3({ baseUrl: match3[1], proc, close, recentStderr });
|
|
116947
|
+
resolve3({ baseUrl: match3[1], proc, close, recentStderr, exitCause: () => exitCause });
|
|
116870
116948
|
}
|
|
116871
116949
|
}
|
|
116872
116950
|
const lines = text.split("\n");
|
|
@@ -116883,6 +116961,11 @@ function bootOpencodeServer(params) {
|
|
|
116883
116961
|
reject(new Error(`failed to spawn opencode serve: ${err.message}`));
|
|
116884
116962
|
}
|
|
116885
116963
|
});
|
|
116964
|
+
proc.once("exit", (code, signal) => {
|
|
116965
|
+
if (!resolved || !isTrackedChild(proc)) return;
|
|
116966
|
+
exitCause = describeServerExit(code, signal);
|
|
116967
|
+
log.warning(withServerStderr(`\xBB ${exitCause}`, recentStderr));
|
|
116968
|
+
});
|
|
116886
116969
|
proc.once("close", (code, signal) => {
|
|
116887
116970
|
if (!resolved) {
|
|
116888
116971
|
const tail = recentStderr.slice(-5).join("\n");
|
|
@@ -116916,6 +116999,12 @@ function withServerStderr(message, recentStderr) {
|
|
|
116916
116999
|
opencode server stderr:
|
|
116917
117000
|
${tail}` : message;
|
|
116918
117001
|
}
|
|
117002
|
+
function describeServerExit(code, signal) {
|
|
117003
|
+
if (signal !== "SIGKILL") return `opencode server exited mid-run (${signal ?? `code ${code}`})`;
|
|
117004
|
+
const limit = process.constrainedMemory();
|
|
117005
|
+
const memoryGb = ((limit > 0 ? Math.min(limit, totalmem()) : totalmem()) / 1024 ** 3).toFixed(1);
|
|
117006
|
+
return `opencode server was killed (SIGKILL) mid-run, usually by the kernel OOM killer \u2014 this runner has ${memoryGb} GB of memory`;
|
|
117007
|
+
}
|
|
116919
117008
|
function newTurn() {
|
|
116920
117009
|
return {
|
|
116921
117010
|
finalText: "",
|
|
@@ -116961,6 +117050,7 @@ async function dispatchEvent(ctx, event) {
|
|
|
116961
117050
|
const err = event.properties.error;
|
|
116962
117051
|
const message = err ? extractErrorMessage(err) : "(no error payload)";
|
|
116963
117052
|
log.info(`\xBB ${ctx.label} session error: ${message}`);
|
|
117053
|
+
if (err) ctx.lastSessionError = message;
|
|
116964
117054
|
return;
|
|
116965
117055
|
}
|
|
116966
117056
|
}
|
|
@@ -117099,6 +117189,7 @@ async function runPromptTurn(ctx, params) {
|
|
|
117099
117189
|
ctx.promptMessageID = void 0;
|
|
117100
117190
|
ctx.diagnostic.sawModelOutput = false;
|
|
117101
117191
|
ctx.diagnostic.idleSec = void 0;
|
|
117192
|
+
ctx.lastSessionError = void 0;
|
|
117102
117193
|
let assistant;
|
|
117103
117194
|
let returnedParts;
|
|
117104
117195
|
let networkError = null;
|
|
@@ -117141,12 +117232,14 @@ async function runPromptTurn(ctx, params) {
|
|
|
117141
117232
|
costUsd: usage.costUsd
|
|
117142
117233
|
});
|
|
117143
117234
|
}
|
|
117144
|
-
const
|
|
117235
|
+
const cause = ctx.serverExitCause() ?? ctx.diagnostic.lastProviderError;
|
|
117236
|
+
const diagnosis = cause ? ` \u2014 likely cause: ${cause}` : "";
|
|
117237
|
+
const promptCause = ctx.serverExitCause() ?? (ctx.diagnostic.sawModelOutput ? void 0 : ctx.lastSessionError) ?? ctx.diagnostic.lastProviderError;
|
|
117145
117238
|
if (networkError) {
|
|
117146
117239
|
return {
|
|
117147
117240
|
success: false,
|
|
117148
117241
|
output: finalText,
|
|
117149
|
-
error: params.signal.aborted ? `activity timeout: the model went silent and the turn was aborted by the activity watchdog (${networkError})${diagnosis}` : `opencode prompt failed: ${networkError}${
|
|
117242
|
+
error: params.signal.aborted ? `activity timeout: the model went silent and the turn was aborted by the activity watchdog (${networkError})${diagnosis}` : `opencode prompt failed: ${networkError}${promptCause ? ` \u2014 likely cause: ${promptCause}` : ""}`,
|
|
117150
117243
|
usage
|
|
117151
117244
|
};
|
|
117152
117245
|
}
|
|
@@ -117338,15 +117431,14 @@ var opencode = agent({
|
|
|
117338
117431
|
const isBedrockRoute = rawModel !== void 0 && bedrockModelId !== void 0 && bedrockModelId === rawModel;
|
|
117339
117432
|
const vertexModel = resolveVertexOpenCodeModel(rawModel);
|
|
117340
117433
|
const model = vertexModel ?? (isBedrockRoute ? `amazon-bedrock/${rawModel}` : rawModel);
|
|
117341
|
-
const
|
|
117342
|
-
|
|
117343
|
-
|
|
117344
|
-
|
|
117345
|
-
const opencodePluginDir = join7(homeEnv.XDG_CONFIG_HOME, "opencode", "plugin");
|
|
117434
|
+
const codexAuth = installCodexAuth();
|
|
117435
|
+
const xaiAuth = installXaiAuth();
|
|
117436
|
+
const homeEnv = openCodeHomeEnv(ctx.tmpdir);
|
|
117437
|
+
const opencodePluginDir = join8(homeEnv.XDG_CONFIG_HOME, "opencode", "plugin");
|
|
117346
117438
|
mkdirSync7(opencodePluginDir, { recursive: true });
|
|
117347
117439
|
writeFileSync6(
|
|
117348
|
-
|
|
117349
|
-
buildOpencodeSubagentGateSource(ctx
|
|
117440
|
+
join8(opencodePluginDir, PULLFROG_OPENCODE_GATE_PLUGIN_FILENAME),
|
|
117441
|
+
buildOpencodeSubagentGateSource(ctx)
|
|
117350
117442
|
);
|
|
117351
117443
|
const agentBrowserVersion = getDevDependencyVersion("agent-browser");
|
|
117352
117444
|
addSkill({
|
|
@@ -117356,8 +117448,6 @@ var opencode = agent({
|
|
|
117356
117448
|
agent: "opencode"
|
|
117357
117449
|
});
|
|
117358
117450
|
installBundledSkills({ home: homeEnv.HOME });
|
|
117359
|
-
const codexAuth = installCodexAuth();
|
|
117360
|
-
const xaiAuth = installXaiAuth();
|
|
117361
117451
|
const permissionOverride = JSON.stringify({
|
|
117362
117452
|
external_directory: { "*": "deny", "/tmp/*": "allow" },
|
|
117363
117453
|
read: { "*": "allow", ...GIT_NATIVE_READ_DENY_OPENCODE },
|
|
@@ -117376,7 +117466,6 @@ var opencode = agent({
|
|
|
117376
117466
|
delete env2.OPENCODE_EXPERIMENTAL_CODE_MODE;
|
|
117377
117467
|
const writebacks = [];
|
|
117378
117468
|
if (codexAuth) {
|
|
117379
|
-
env2.XDG_DATA_HOME = codexAuth.xdgDataHome;
|
|
117380
117469
|
delete env2.OPENAI_API_KEY;
|
|
117381
117470
|
writebacks.push({
|
|
117382
117471
|
secretName: "CODEX_AUTH_JSON",
|
|
@@ -117387,7 +117476,6 @@ var opencode = agent({
|
|
|
117387
117476
|
});
|
|
117388
117477
|
}
|
|
117389
117478
|
if (xaiAuth) {
|
|
117390
|
-
env2.XDG_DATA_HOME = xaiAuth.xdgDataHome;
|
|
117391
117479
|
delete env2.XAI_API_KEY;
|
|
117392
117480
|
writebacks.push({
|
|
117393
117481
|
secretName: "GROK_AUTH_JSON",
|
|
@@ -117459,6 +117547,8 @@ var opencode = agent({
|
|
|
117459
117547
|
loggedToolCallIDs: /* @__PURE__ */ new Set(),
|
|
117460
117548
|
mcpToolCalls: 0,
|
|
117461
117549
|
recentStderr: server.recentStderr,
|
|
117550
|
+
serverExitCause: server.exitCause,
|
|
117551
|
+
lastSessionError: void 0,
|
|
117462
117552
|
diagnostic: {
|
|
117463
117553
|
label: "Pullfrog",
|
|
117464
117554
|
recentStderr: server.recentStderr,
|
|
@@ -122889,10 +122979,10 @@ function getMatch(pattern, exp) {
|
|
|
122889
122979
|
}
|
|
122890
122980
|
function parseQuery(pattern, options = {}) {
|
|
122891
122981
|
return pattern.replace(/\\\|/g, ESCAPED_PIPE).split(OR_TOKEN).map((item) => {
|
|
122892
|
-
const
|
|
122982
|
+
const query2 = tokenize(item.replace(/\u0000/g, "|").trim()).filter((item2) => item2 && !!item2.trim());
|
|
122893
122983
|
const results = [];
|
|
122894
|
-
for (let i = 0, len =
|
|
122895
|
-
const queryItem =
|
|
122984
|
+
for (let i = 0, len = query2.length; i < len; i += 1) {
|
|
122985
|
+
const queryItem = query2[i];
|
|
122896
122986
|
let found = false;
|
|
122897
122987
|
let idx = -1;
|
|
122898
122988
|
while (!found && ++idx < matchersLen) {
|
|
@@ -122940,8 +123030,8 @@ var ExtendedSearch = class {
|
|
|
122940
123030
|
return options.useExtendedSearch;
|
|
122941
123031
|
}
|
|
122942
123032
|
searchIn(text) {
|
|
122943
|
-
const
|
|
122944
|
-
if (!
|
|
123033
|
+
const query2 = this.query;
|
|
123034
|
+
if (!query2) return {
|
|
122945
123035
|
isMatch: false,
|
|
122946
123036
|
score: 1
|
|
122947
123037
|
};
|
|
@@ -122952,8 +123042,8 @@ var ExtendedSearch = class {
|
|
|
122952
123042
|
const allIndices = [];
|
|
122953
123043
|
let totalScore = 0;
|
|
122954
123044
|
let hasInverse = false;
|
|
122955
|
-
for (let i = 0, qLen =
|
|
122956
|
-
const searchers =
|
|
123045
|
+
for (let i = 0, qLen = query2.length; i < qLen; i += 1) {
|
|
123046
|
+
const searchers = query2[i];
|
|
122957
123047
|
allIndices.length = 0;
|
|
122958
123048
|
numMatches = 0;
|
|
122959
123049
|
hasInverse = false;
|
|
@@ -123009,26 +123099,26 @@ var KeyType = {
|
|
|
123009
123099
|
PATH: "$path",
|
|
123010
123100
|
PATTERN: "$val"
|
|
123011
123101
|
};
|
|
123012
|
-
var isExpression = (
|
|
123013
|
-
var isPath = (
|
|
123014
|
-
var isLeaf = (
|
|
123015
|
-
var convertToExplicit = (
|
|
123016
|
-
function parse3(
|
|
123017
|
-
const next2 = (
|
|
123018
|
-
if (isString(
|
|
123102
|
+
var isExpression = (query2) => !!(query2[LogicalOperator.AND] || query2[LogicalOperator.OR]);
|
|
123103
|
+
var isPath = (query2) => !!query2[KeyType.PATH];
|
|
123104
|
+
var isLeaf = (query2) => !isArray2(query2) && isObject2(query2) && !isExpression(query2);
|
|
123105
|
+
var convertToExplicit = (query2) => ({ [LogicalOperator.AND]: Object.keys(query2).map((key) => ({ [key]: query2[key] })) });
|
|
123106
|
+
function parse3(query2, options, { auto = true } = {}) {
|
|
123107
|
+
const next2 = (query3) => {
|
|
123108
|
+
if (isString(query3)) {
|
|
123019
123109
|
const obj = {
|
|
123020
123110
|
keyId: null,
|
|
123021
|
-
pattern:
|
|
123111
|
+
pattern: query3
|
|
123022
123112
|
};
|
|
123023
|
-
if (auto) obj.searcher = createSearcher(
|
|
123113
|
+
if (auto) obj.searcher = createSearcher(query3, options);
|
|
123024
123114
|
return obj;
|
|
123025
123115
|
}
|
|
123026
|
-
const keys = Object.keys(
|
|
123027
|
-
const isQueryPath = isPath(
|
|
123028
|
-
if (!isQueryPath && keys.length > 1 && !isExpression(
|
|
123029
|
-
if (isLeaf(
|
|
123030
|
-
const key = isQueryPath ?
|
|
123031
|
-
const pattern = isQueryPath ?
|
|
123116
|
+
const keys = Object.keys(query3);
|
|
123117
|
+
const isQueryPath = isPath(query3);
|
|
123118
|
+
if (!isQueryPath && keys.length > 1 && !isExpression(query3)) return next2(convertToExplicit(query3));
|
|
123119
|
+
if (isLeaf(query3)) {
|
|
123120
|
+
const key = isQueryPath ? query3[KeyType.PATH] : keys[0];
|
|
123121
|
+
const pattern = isQueryPath ? query3[KeyType.PATTERN] : query3[key];
|
|
123032
123122
|
if (!isString(pattern)) throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
|
|
123033
123123
|
const obj = {
|
|
123034
123124
|
keyId: createKeyId(key),
|
|
@@ -123042,15 +123132,15 @@ function parse3(query, options, { auto = true } = {}) {
|
|
|
123042
123132
|
operator: keys[0]
|
|
123043
123133
|
};
|
|
123044
123134
|
keys.forEach((key) => {
|
|
123045
|
-
const value2 =
|
|
123135
|
+
const value2 = query3[key];
|
|
123046
123136
|
if (isArray2(value2)) value2.forEach((item) => {
|
|
123047
123137
|
node2.children.push(next2(item));
|
|
123048
123138
|
});
|
|
123049
123139
|
});
|
|
123050
123140
|
return node2;
|
|
123051
123141
|
};
|
|
123052
|
-
if (!isExpression(
|
|
123053
|
-
return next2(
|
|
123142
|
+
if (!isExpression(query2)) query2 = convertToExplicit(query2);
|
|
123143
|
+
return next2(query2);
|
|
123054
123144
|
}
|
|
123055
123145
|
function computeScoreSingle(matches, { ignoreFieldNorm = Config3.ignoreFieldNorm }) {
|
|
123056
123146
|
let totalScore = 1;
|
|
@@ -123346,13 +123436,13 @@ var Fuse = class {
|
|
|
123346
123436
|
this._lastQuery = null;
|
|
123347
123437
|
this._lastSearcher = null;
|
|
123348
123438
|
}
|
|
123349
|
-
_getSearcher(
|
|
123350
|
-
if (this._lastQuery ===
|
|
123351
|
-
const searcher = createSearcher(
|
|
123439
|
+
_getSearcher(query2) {
|
|
123440
|
+
if (this._lastQuery === query2) return this._lastSearcher;
|
|
123441
|
+
const searcher = createSearcher(query2, this._invertedIndex ? {
|
|
123352
123442
|
...this.options,
|
|
123353
123443
|
_invertedIndex: this._invertedIndex
|
|
123354
123444
|
} : this.options);
|
|
123355
|
-
this._lastQuery =
|
|
123445
|
+
this._lastQuery = query2;
|
|
123356
123446
|
this._lastSearcher = searcher;
|
|
123357
123447
|
return searcher;
|
|
123358
123448
|
}
|
|
@@ -123421,10 +123511,10 @@ var Fuse = class {
|
|
|
123421
123511
|
_normalizedKeys() {
|
|
123422
123512
|
return this._myIndex.keys.map((key) => this._keyStore.get(key.id) || key);
|
|
123423
123513
|
}
|
|
123424
|
-
search(
|
|
123514
|
+
search(query2, options) {
|
|
123425
123515
|
const { limit = -1 } = options || {};
|
|
123426
123516
|
const { includeMatches, includeScore, shouldSort, sortFn, ignoreFieldNorm } = this.options;
|
|
123427
|
-
if (isString(
|
|
123517
|
+
if (isString(query2) && !query2.trim()) {
|
|
123428
123518
|
let docs = this._docs.map((item, idx) => ({
|
|
123429
123519
|
item,
|
|
123430
123520
|
refIndex: idx
|
|
@@ -123432,25 +123522,25 @@ var Fuse = class {
|
|
|
123432
123522
|
if (isNumber(limit) && limit > -1) docs = docs.slice(0, limit);
|
|
123433
123523
|
return docs;
|
|
123434
123524
|
}
|
|
123435
|
-
const useHeap = shouldSort && isNumber(limit) && limit > 0 && isString(
|
|
123525
|
+
const useHeap = shouldSort && isNumber(limit) && limit > 0 && isString(query2);
|
|
123436
123526
|
const comparator = sortFn;
|
|
123437
123527
|
const stable = (a, b) => comparator(a, b) || a.idx - b.idx;
|
|
123438
123528
|
let results;
|
|
123439
123529
|
if (useHeap) {
|
|
123440
123530
|
const heap = new MaxHeap(limit, stable);
|
|
123441
|
-
if (isString(this._docs[0])) this._searchStringList(
|
|
123531
|
+
if (isString(this._docs[0])) this._searchStringList(query2, {
|
|
123442
123532
|
heap,
|
|
123443
123533
|
ignoreFieldNorm
|
|
123444
123534
|
});
|
|
123445
|
-
else this._searchObjectList(
|
|
123535
|
+
else this._searchObjectList(query2, {
|
|
123446
123536
|
heap,
|
|
123447
123537
|
ignoreFieldNorm
|
|
123448
123538
|
});
|
|
123449
123539
|
results = heap.extractSorted();
|
|
123450
123540
|
} else {
|
|
123451
|
-
results = isString(
|
|
123541
|
+
results = isString(query2) ? isString(this._docs[0]) ? this._searchStringList(query2) : this._searchObjectList(query2) : this._searchLogical(query2);
|
|
123452
123542
|
computeScore(results, { ignoreFieldNorm });
|
|
123453
|
-
if (shouldSort) results.sort(isString(
|
|
123543
|
+
if (shouldSort) results.sort(isString(query2) ? stable : comparator);
|
|
123454
123544
|
if (isNumber(limit) && limit > -1) results = results.slice(0, limit);
|
|
123455
123545
|
}
|
|
123456
123546
|
return format(results, this._docs, {
|
|
@@ -123458,8 +123548,8 @@ var Fuse = class {
|
|
|
123458
123548
|
includeScore
|
|
123459
123549
|
});
|
|
123460
123550
|
}
|
|
123461
|
-
_searchStringList(
|
|
123462
|
-
const searcher = this._getSearcher(
|
|
123551
|
+
_searchStringList(query2, { heap, ignoreFieldNorm } = {}) {
|
|
123552
|
+
const searcher = this._getSearcher(query2);
|
|
123463
123553
|
const requireAllTokens = this.options.useTokenSearch && this.options.tokenMatch === "all";
|
|
123464
123554
|
const { records } = this._myIndex;
|
|
123465
123555
|
const results = heap ? null : [];
|
|
@@ -123494,8 +123584,8 @@ var Fuse = class {
|
|
|
123494
123584
|
});
|
|
123495
123585
|
return results;
|
|
123496
123586
|
}
|
|
123497
|
-
_searchLogical(
|
|
123498
|
-
const expression = parse3(
|
|
123587
|
+
_searchLogical(query2) {
|
|
123588
|
+
const expression = parse3(query2, this.options);
|
|
123499
123589
|
const keys = this._normalizedKeys();
|
|
123500
123590
|
const evaluate = (node2, item, idx) => {
|
|
123501
123591
|
if (!("children" in node2)) {
|
|
@@ -123555,8 +123645,8 @@ var Fuse = class {
|
|
|
123555
123645
|
});
|
|
123556
123646
|
return results;
|
|
123557
123647
|
}
|
|
123558
|
-
_searchObjectList(
|
|
123559
|
-
const searcher = this._getSearcher(
|
|
123648
|
+
_searchObjectList(query2, { heap, ignoreFieldNorm } = {}) {
|
|
123649
|
+
const searcher = this._getSearcher(query2);
|
|
123560
123650
|
const requireAllTokens = this.options.useTokenSearch && this.options.tokenMatch === "all";
|
|
123561
123651
|
const { records } = this._myIndex;
|
|
123562
123652
|
const keys = this._normalizedKeys();
|
|
@@ -123783,10 +123873,10 @@ var getPattern = (label, next2) => {
|
|
|
123783
123873
|
if (label === "*") return "*";
|
|
123784
123874
|
const match3 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
123785
123875
|
if (match3) {
|
|
123786
|
-
const
|
|
123787
|
-
if (!patternCache[
|
|
123788
|
-
if (match3[2]) patternCache[
|
|
123789
|
-
|
|
123876
|
+
const cacheKey3 = `${label}#${next2}`;
|
|
123877
|
+
if (!patternCache[cacheKey3]) {
|
|
123878
|
+
if (match3[2]) patternCache[cacheKey3] = next2 && next2[0] !== ":" && next2[0] !== "*" ? [
|
|
123879
|
+
cacheKey3,
|
|
123790
123880
|
match3[1],
|
|
123791
123881
|
new RegExp(`^${match3[2]}(?=/${next2})`)
|
|
123792
123882
|
] : [
|
|
@@ -123794,13 +123884,13 @@ var getPattern = (label, next2) => {
|
|
|
123794
123884
|
match3[1],
|
|
123795
123885
|
new RegExp(`^${match3[2]}$`)
|
|
123796
123886
|
];
|
|
123797
|
-
else patternCache[
|
|
123887
|
+
else patternCache[cacheKey3] = [
|
|
123798
123888
|
label,
|
|
123799
123889
|
match3[1],
|
|
123800
123890
|
true
|
|
123801
123891
|
];
|
|
123802
123892
|
}
|
|
123803
|
-
return patternCache[
|
|
123893
|
+
return patternCache[cacheKey3];
|
|
123804
123894
|
}
|
|
123805
123895
|
return null;
|
|
123806
123896
|
};
|
|
@@ -134289,9 +134379,9 @@ var require_schemes2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
134289
134379
|
wsComponent.secure = void 0;
|
|
134290
134380
|
}
|
|
134291
134381
|
if (wsComponent.resourceName) {
|
|
134292
|
-
const [path4,
|
|
134382
|
+
const [path4, query2] = wsComponent.resourceName.split("?");
|
|
134293
134383
|
wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
|
|
134294
|
-
wsComponent.query =
|
|
134384
|
+
wsComponent.query = query2;
|
|
134295
134385
|
wsComponent.resourceName = void 0;
|
|
134296
134386
|
}
|
|
134297
134387
|
wsComponent.fragment = void 0;
|
|
@@ -134906,8 +134996,8 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
134906
134996
|
return this;
|
|
134907
134997
|
}
|
|
134908
134998
|
case "object": {
|
|
134909
|
-
const
|
|
134910
|
-
this._cache.delete(
|
|
134999
|
+
const cacheKey3 = schemaKeyRef;
|
|
135000
|
+
this._cache.delete(cacheKey3);
|
|
134911
135001
|
let id = schemaKeyRef[this.opts.schemaId];
|
|
134912
135002
|
if (id) {
|
|
134913
135003
|
id = (0, resolve_1.normalizeId)(id);
|
|
@@ -135050,10 +135140,10 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
135050
135140
|
Ajv5.ValidationError = validation_error_1.default;
|
|
135051
135141
|
Ajv5.MissingRefError = ref_error_1.default;
|
|
135052
135142
|
exports.default = Ajv5;
|
|
135053
|
-
function checkOptions(checkOpts, options, msg,
|
|
135143
|
+
function checkOptions(checkOpts, options, msg, log2 = "error") {
|
|
135054
135144
|
for (const key in checkOpts) {
|
|
135055
135145
|
const opt = key;
|
|
135056
|
-
if (opt in options) this.logger[
|
|
135146
|
+
if (opt in options) this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
|
|
135057
135147
|
}
|
|
135058
135148
|
}
|
|
135059
135149
|
function getSchEnv(keyRef) {
|
|
@@ -148574,9 +148664,9 @@ var require_schemes3 = /* @__PURE__ */ __commonJSMin2(((exports, module) => {
|
|
|
148574
148664
|
wsComponent.secure = void 0;
|
|
148575
148665
|
}
|
|
148576
148666
|
if (wsComponent.resourceName) {
|
|
148577
|
-
const [path4,
|
|
148667
|
+
const [path4, query2] = wsComponent.resourceName.split("?");
|
|
148578
148668
|
wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
|
|
148579
|
-
wsComponent.query =
|
|
148669
|
+
wsComponent.query = query2;
|
|
148580
148670
|
wsComponent.resourceName = void 0;
|
|
148581
148671
|
}
|
|
148582
148672
|
wsComponent.fragment = void 0;
|
|
@@ -149191,8 +149281,8 @@ var require_core$32 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
149191
149281
|
return this;
|
|
149192
149282
|
}
|
|
149193
149283
|
case "object": {
|
|
149194
|
-
const
|
|
149195
|
-
this._cache.delete(
|
|
149284
|
+
const cacheKey3 = schemaKeyRef;
|
|
149285
|
+
this._cache.delete(cacheKey3);
|
|
149196
149286
|
let id = schemaKeyRef[this.opts.schemaId];
|
|
149197
149287
|
if (id) {
|
|
149198
149288
|
id = (0, resolve_1.normalizeId)(id);
|
|
@@ -149335,10 +149425,10 @@ var require_core$32 = /* @__PURE__ */ __commonJSMin2(((exports) => {
|
|
|
149335
149425
|
Ajv5.ValidationError = validation_error_1.default;
|
|
149336
149426
|
Ajv5.MissingRefError = ref_error_1.default;
|
|
149337
149427
|
exports.default = Ajv5;
|
|
149338
|
-
function checkOptions(checkOpts, options, msg,
|
|
149428
|
+
function checkOptions(checkOpts, options, msg, log2 = "error") {
|
|
149339
149429
|
for (const key in checkOpts) {
|
|
149340
149430
|
const opt = key;
|
|
149341
|
-
if (opt in options) this.logger[
|
|
149431
|
+
if (opt in options) this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
|
|
149342
149432
|
}
|
|
149343
149433
|
}
|
|
149344
149434
|
function getSchEnv(keyRef) {
|
|
@@ -160031,7 +160121,7 @@ var require_depd = /* @__PURE__ */ __commonJSMin3(((exports, module) => {
|
|
|
160031
160121
|
if (!namespace) throw new TypeError("argument namespace is required");
|
|
160032
160122
|
var file2 = callSiteLocation(getStack()[1])[0];
|
|
160033
160123
|
function deprecate$1(message) {
|
|
160034
|
-
|
|
160124
|
+
log2.call(deprecate$1, message);
|
|
160035
160125
|
}
|
|
160036
160126
|
deprecate$1._file = file2;
|
|
160037
160127
|
deprecate$1._ignored = isignored(namespace);
|
|
@@ -160053,7 +160143,7 @@ var require_depd = /* @__PURE__ */ __commonJSMin3(((exports, module) => {
|
|
|
160053
160143
|
if (process.traceDeprecation) return true;
|
|
160054
160144
|
return containsNamespace(process.env.TRACE_DEPRECATION || "", namespace);
|
|
160055
160145
|
}
|
|
160056
|
-
function
|
|
160146
|
+
function log2(message, site) {
|
|
160057
160147
|
var haslisteners = eehaslisteners(process, "deprecation");
|
|
160058
160148
|
if (!haslisteners && this._ignored) return;
|
|
160059
160149
|
var caller;
|
|
@@ -160159,7 +160249,7 @@ var require_depd = /* @__PURE__ */ __commonJSMin3(((exports, module) => {
|
|
|
160159
160249
|
var args2 = createArgumentsString(fn2.length);
|
|
160160
160250
|
var site = callSiteLocation(getStack()[1]);
|
|
160161
160251
|
site.name = fn2.name;
|
|
160162
|
-
return new Function("fn", "log", "deprecate", "message", "site", '"use strict"\nreturn function (' + args2 + ") {log.call(deprecate, message, site)\nreturn fn.apply(this, arguments)\n}")(fn2,
|
|
160252
|
+
return new Function("fn", "log", "deprecate", "message", "site", '"use strict"\nreturn function (' + args2 + ") {log.call(deprecate, message, site)\nreturn fn.apply(this, arguments)\n}")(fn2, log2, this, message, site);
|
|
160163
160253
|
}
|
|
160164
160254
|
function wrapproperty(obj, prop, message) {
|
|
160165
160255
|
if (!obj || typeof obj !== "object" && typeof obj !== "function") throw new TypeError("argument obj must be object");
|
|
@@ -160173,11 +160263,11 @@ var require_depd = /* @__PURE__ */ __commonJSMin3(((exports, module) => {
|
|
|
160173
160263
|
var get2 = descriptor.get;
|
|
160174
160264
|
var set2 = descriptor.set;
|
|
160175
160265
|
if (typeof get2 === "function") descriptor.get = function getter() {
|
|
160176
|
-
|
|
160266
|
+
log2.call(deprecate$1, message, site);
|
|
160177
160267
|
return get2.apply(this, arguments);
|
|
160178
160268
|
};
|
|
160179
160269
|
if (typeof set2 === "function") descriptor.set = function setter() {
|
|
160180
|
-
|
|
160270
|
+
log2.call(deprecate$1, message, site);
|
|
160181
160271
|
return set2.apply(this, arguments);
|
|
160182
160272
|
};
|
|
160183
160273
|
Object.defineProperty(obj, prop, descriptor);
|
|
@@ -171225,7 +171315,7 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
|
|
|
171225
171315
|
);
|
|
171226
171316
|
}
|
|
171227
171317
|
};
|
|
171228
|
-
const
|
|
171318
|
+
const log2 = {
|
|
171229
171319
|
debug: (message, context) => {
|
|
171230
171320
|
this.#server.sendLoggingMessage({
|
|
171231
171321
|
data: {
|
|
@@ -171293,7 +171383,7 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
|
|
|
171293
171383
|
client: {
|
|
171294
171384
|
version: this.#server.getClientVersion()
|
|
171295
171385
|
},
|
|
171296
|
-
log:
|
|
171386
|
+
log: log2,
|
|
171297
171387
|
reportProgress: reportProgress2,
|
|
171298
171388
|
requestId: typeof request2.params?._meta?.requestId === "string" ? request2.params._meta.requestId : void 0,
|
|
171299
171389
|
session: this.#auth,
|
|
@@ -172377,7 +172467,7 @@ function closeBrowserDaemon(toolState) {
|
|
|
172377
172467
|
// mcp/checkout.ts
|
|
172378
172468
|
import { createHash as createHash2 } from "node:crypto";
|
|
172379
172469
|
import { statSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
172380
|
-
import { join as
|
|
172470
|
+
import { join as join16 } from "node:path";
|
|
172381
172471
|
|
|
172382
172472
|
// node_modules/.pnpm/@ark+schema@0.56.0/node_modules/@ark/schema/out/shared/errors.js
|
|
172383
172473
|
var ArkError = class _ArkError extends CastableBase {
|
|
@@ -174378,8 +174468,8 @@ var defaultableMorphCache = {};
|
|
|
174378
174468
|
var getDefaultableMorph = (node2) => {
|
|
174379
174469
|
if (!node2.hasDefault())
|
|
174380
174470
|
return;
|
|
174381
|
-
const
|
|
174382
|
-
return defaultableMorphCache[
|
|
174471
|
+
const cacheKey3 = `{${node2.compiledKey}: ${node2.value.id} = ${defaultValueSerializer(node2.default)}}`;
|
|
174472
|
+
return defaultableMorphCache[cacheKey3] ??= computeDefaultValueMorph(node2.key, node2.value, node2.default);
|
|
174383
174473
|
};
|
|
174384
174474
|
var computeDefaultValueMorph = (key, value2, defaultInput) => {
|
|
174385
174475
|
if (typeof defaultInput === "function") {
|
|
@@ -176552,15 +176642,15 @@ var getDefaultableMorphs = (node2) => {
|
|
|
176552
176642
|
if (!node2.defaultables)
|
|
176553
176643
|
return [];
|
|
176554
176644
|
const morphs = [];
|
|
176555
|
-
let
|
|
176645
|
+
let cacheKey3 = "[";
|
|
176556
176646
|
const lastDefaultableIndex = node2.prefixLength + node2.defaultablesLength - 1;
|
|
176557
176647
|
for (let i = node2.prefixLength; i <= lastDefaultableIndex; i++) {
|
|
176558
176648
|
const [elementNode, defaultValue] = node2.defaultables[i - node2.prefixLength];
|
|
176559
176649
|
morphs.push(computeDefaultValueMorph(i, elementNode, defaultValue));
|
|
176560
|
-
|
|
176650
|
+
cacheKey3 += `${i}: ${elementNode.id} = ${defaultValueSerializer(defaultValue)}, `;
|
|
176561
176651
|
}
|
|
176562
|
-
|
|
176563
|
-
return defaultableMorphsCache[
|
|
176652
|
+
cacheKey3 += "]";
|
|
176653
|
+
return defaultableMorphsCache[cacheKey3] ??= morphs;
|
|
176564
176654
|
};
|
|
176565
176655
|
var Sequence = {
|
|
176566
176656
|
implementation: implementation21,
|
|
@@ -177250,40 +177340,40 @@ var StructureNode = class extends BaseConstraint {
|
|
|
177250
177340
|
};
|
|
177251
177341
|
var defaultableMorphsCache2 = {};
|
|
177252
177342
|
var constructStructuralMorphCacheKey = (node2) => {
|
|
177253
|
-
let
|
|
177343
|
+
let cacheKey3 = "";
|
|
177254
177344
|
for (let i = 0; i < node2.defaultable.length; i++)
|
|
177255
|
-
|
|
177345
|
+
cacheKey3 += node2.defaultable[i].defaultValueMorphRef;
|
|
177256
177346
|
if (node2.sequence?.defaultValueMorphsReference)
|
|
177257
|
-
|
|
177347
|
+
cacheKey3 += node2.sequence?.defaultValueMorphsReference;
|
|
177258
177348
|
if (node2.undeclared === "delete") {
|
|
177259
|
-
|
|
177349
|
+
cacheKey3 += "delete !(";
|
|
177260
177350
|
if (node2.required)
|
|
177261
177351
|
for (const n of node2.required)
|
|
177262
|
-
|
|
177352
|
+
cacheKey3 += n.compiledKey + " | ";
|
|
177263
177353
|
if (node2.optional)
|
|
177264
177354
|
for (const n of node2.optional)
|
|
177265
|
-
|
|
177355
|
+
cacheKey3 += n.compiledKey + " | ";
|
|
177266
177356
|
if (node2.index)
|
|
177267
177357
|
for (const index of node2.index)
|
|
177268
|
-
|
|
177358
|
+
cacheKey3 += index.signature.id + " | ";
|
|
177269
177359
|
if (node2.sequence) {
|
|
177270
177360
|
if (node2.sequence.maxLength === null)
|
|
177271
|
-
|
|
177361
|
+
cacheKey3 += intrinsic.nonNegativeIntegerString.id;
|
|
177272
177362
|
else {
|
|
177273
177363
|
for (let i = 0; i < node2.sequence.tuple.length; i++)
|
|
177274
|
-
|
|
177364
|
+
cacheKey3 += i + " | ";
|
|
177275
177365
|
}
|
|
177276
177366
|
}
|
|
177277
|
-
|
|
177367
|
+
cacheKey3 += ")";
|
|
177278
177368
|
}
|
|
177279
|
-
return
|
|
177369
|
+
return cacheKey3;
|
|
177280
177370
|
};
|
|
177281
177371
|
var getPossibleMorph = (node2) => {
|
|
177282
|
-
const
|
|
177283
|
-
if (!
|
|
177372
|
+
const cacheKey3 = constructStructuralMorphCacheKey(node2);
|
|
177373
|
+
if (!cacheKey3)
|
|
177284
177374
|
return void 0;
|
|
177285
|
-
if (defaultableMorphsCache2[
|
|
177286
|
-
return defaultableMorphsCache2[
|
|
177375
|
+
if (defaultableMorphsCache2[cacheKey3])
|
|
177376
|
+
return defaultableMorphsCache2[cacheKey3];
|
|
177287
177377
|
const $arkStructuralMorph = (data, ctx) => {
|
|
177288
177378
|
for (let i = 0; i < node2.defaultable.length; i++) {
|
|
177289
177379
|
if (!(node2.defaultable[i].key in data))
|
|
@@ -177300,7 +177390,7 @@ var getPossibleMorph = (node2) => {
|
|
|
177300
177390
|
}
|
|
177301
177391
|
return data;
|
|
177302
177392
|
};
|
|
177303
|
-
return defaultableMorphsCache2[
|
|
177393
|
+
return defaultableMorphsCache2[cacheKey3] = $arkStructuralMorph;
|
|
177304
177394
|
};
|
|
177305
177395
|
var precompileMorphs = (js, node2) => {
|
|
177306
177396
|
const requiresContext = node2.defaultable.some((node3) => node3.defaultValueMorph.length === 2) || node2.sequence?.defaultValueMorphs.some((morph) => morph.length === 2);
|
|
@@ -179705,10 +179795,10 @@ var schema = ark.schema;
|
|
|
179705
179795
|
var define2 = ark.define;
|
|
179706
179796
|
var declare = ark.declare;
|
|
179707
179797
|
|
|
179708
|
-
// node_modules/.pnpm/yes@0.
|
|
179798
|
+
// node_modules/.pnpm/yes@0.2.3_typescript@5.9.3/node_modules/yes/dist/index.js
|
|
179709
179799
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
179710
179800
|
|
|
179711
|
-
// node_modules/.pnpm/yes@0.
|
|
179801
|
+
// node_modules/.pnpm/yes@0.2.3_typescript@5.9.3/node_modules/yes/dist/cache/adapter.js
|
|
179712
179802
|
var AdapterError = class extends Error {
|
|
179713
179803
|
method;
|
|
179714
179804
|
/** the full store key, or the op's prefix when the call covered many keys. never the raw input. */
|
|
@@ -180306,43 +180396,45 @@ var I = class d2 {
|
|
|
180306
180396
|
}
|
|
180307
180397
|
};
|
|
180308
180398
|
|
|
180309
|
-
// node_modules/.pnpm/yes@0.
|
|
180310
|
-
function memory(
|
|
180311
|
-
const store = new I({ max:
|
|
180399
|
+
// node_modules/.pnpm/yes@0.2.3_typescript@5.9.3/node_modules/yes/dist/cache/memory.js
|
|
180400
|
+
function memory({ maxItems = 1e3 } = {}) {
|
|
180401
|
+
const store = new I({ max: maxItems });
|
|
180312
180402
|
return {
|
|
180313
180403
|
get: (key) => store.get(key),
|
|
180314
180404
|
peek: (key) => store.peek(key),
|
|
180315
|
-
// the TTL rides on each entry
|
|
180316
|
-
|
|
180317
|
-
set: (key, entry, ttlMs) => {
|
|
180318
|
-
store.set(key, entry, { ttl: ttlMs });
|
|
180319
|
-
},
|
|
180405
|
+
// the TTL rides on each entry, so ops with different lifetimes can share one store
|
|
180406
|
+
set: (key, entry, ttlMs) => store.set(key, entry, { ttl: ttlMs }),
|
|
180320
180407
|
delete: (keys) => {
|
|
180321
180408
|
for (const key of keys)
|
|
180322
180409
|
store.delete(key);
|
|
180323
180410
|
},
|
|
180324
|
-
// a snapshot, so deleting while iterating is safe
|
|
180325
|
-
// entries itself.
|
|
180411
|
+
// a snapshot, so deleting while iterating is safe
|
|
180326
180412
|
list: (prefix) => [...store.entries()].filter(([key]) => key.startsWith(prefix))
|
|
180327
180413
|
};
|
|
180328
180414
|
}
|
|
180329
180415
|
|
|
180330
|
-
// node_modules/.pnpm/yes@0.
|
|
180416
|
+
// node_modules/.pnpm/yes@0.2.3_typescript@5.9.3/node_modules/yes/dist/key.js
|
|
180331
180417
|
import { hash as hash2 } from "node:crypto";
|
|
180332
180418
|
function hashKey(value2) {
|
|
180333
|
-
return hash2("sha1",
|
|
180419
|
+
return hash2("sha1", canonical(value2));
|
|
180420
|
+
}
|
|
180421
|
+
function canonical(value2) {
|
|
180422
|
+
return serialize(value2, 0);
|
|
180423
|
+
}
|
|
180424
|
+
function cacheKey2(value2) {
|
|
180425
|
+
if (value2 === null)
|
|
180426
|
+
throw new Error("null cannot be part of a cache key");
|
|
180427
|
+
return value2 === void 0 ? "~void" : hashKey(value2);
|
|
180334
180428
|
}
|
|
180335
|
-
var MAX_DEPTH = 64;
|
|
180336
180429
|
function serialize(value2, depth) {
|
|
180337
180430
|
switch (typeof value2) {
|
|
180338
|
-
case "string":
|
|
180339
|
-
return JSON.stringify(value2);
|
|
180340
180431
|
case "number":
|
|
180341
|
-
if (
|
|
180342
|
-
|
|
180343
|
-
|
|
180432
|
+
if (Number.isFinite(value2))
|
|
180433
|
+
return String(value2);
|
|
180434
|
+
throw new Error(`${value2} cannot be part of a cache key`);
|
|
180435
|
+
case "string":
|
|
180344
180436
|
case "boolean":
|
|
180345
|
-
return value2
|
|
180437
|
+
return JSON.stringify(value2);
|
|
180346
180438
|
case "undefined":
|
|
180347
180439
|
throw new Error("undefined cannot be part of a cache key, except as an object property");
|
|
180348
180440
|
case "object":
|
|
@@ -180352,9 +180444,8 @@ function serialize(value2, depth) {
|
|
|
180352
180444
|
}
|
|
180353
180445
|
if (value2 === null)
|
|
180354
180446
|
return "null";
|
|
180355
|
-
if (depth ===
|
|
180356
|
-
throw new Error(
|
|
180357
|
-
depth++;
|
|
180447
|
+
if (depth++ === 64)
|
|
180448
|
+
throw new Error("an input nested more than 64 levels deep, or circular");
|
|
180358
180449
|
if (Array.isArray(value2)) {
|
|
180359
180450
|
let out2 = "[";
|
|
180360
180451
|
for (let i = 0; i < value2.length; i++)
|
|
@@ -180366,77 +180457,26 @@ function serialize(value2, depth) {
|
|
|
180366
180457
|
const name = proto.constructor?.name || "class instance";
|
|
180367
180458
|
throw new Error(`a ${name} cannot be part of a cache key: only JSON data can`);
|
|
180368
180459
|
}
|
|
180369
|
-
const record3 = value2;
|
|
180370
|
-
const keys = Object.keys(record3).sort();
|
|
180371
180460
|
let out = "";
|
|
180372
|
-
for (const key of keys) {
|
|
180373
|
-
const v =
|
|
180461
|
+
for (const key of Object.keys(value2).sort()) {
|
|
180462
|
+
const v = value2[key];
|
|
180374
180463
|
if (v !== void 0)
|
|
180375
180464
|
out += `${out ? "," : ""}${JSON.stringify(key)}:${serialize(v, depth)}`;
|
|
180376
180465
|
}
|
|
180377
180466
|
return `{${out}}`;
|
|
180378
180467
|
}
|
|
180379
180468
|
|
|
180380
|
-
// node_modules/.pnpm/yes@0.
|
|
180381
|
-
|
|
180382
|
-
|
|
180383
|
-
|
|
180384
|
-
return VOID_KEY;
|
|
180385
|
-
if (value2 === null) {
|
|
180386
|
-
throw new Error("cache key cannot be null");
|
|
180387
|
-
}
|
|
180388
|
-
try {
|
|
180389
|
-
return hashKey(value2);
|
|
180390
|
-
} catch (error49) {
|
|
180391
|
-
throw new Error(`cache key cannot be hashed: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
180392
|
-
}
|
|
180393
|
-
}
|
|
180394
|
-
function jitter(delayMs) {
|
|
180395
|
-
const half = delayMs / 2;
|
|
180396
|
-
return Math.round(half + Math.random() * half);
|
|
180397
|
-
}
|
|
180398
|
-
var DEFAULT_RETRY_AFTER_CAP_MS = 2e4;
|
|
180399
|
-
function getErrorResponseHeaders(error49) {
|
|
180400
|
-
if (error49 === null || typeof error49 !== "object")
|
|
180401
|
-
return void 0;
|
|
180402
|
-
const source = error49;
|
|
180403
|
-
const headers = source.response?.headers ?? source.headers;
|
|
180404
|
-
if (headers === null || typeof headers !== "object")
|
|
180405
|
-
return void 0;
|
|
180406
|
-
return headers;
|
|
180407
|
-
}
|
|
180408
|
-
function retryAfterMs(error49) {
|
|
180409
|
-
const headers = getErrorResponseHeaders(error49);
|
|
180410
|
-
if (!headers)
|
|
180411
|
-
return void 0;
|
|
180412
|
-
const retryAfter = headers["retry-after"];
|
|
180413
|
-
if (typeof retryAfter === "string" && retryAfter.trim() !== "") {
|
|
180414
|
-
const seconds = Number(retryAfter);
|
|
180415
|
-
if (Number.isFinite(seconds))
|
|
180416
|
-
return Math.max(0, seconds * 1e3);
|
|
180417
|
-
const dateMs = Date.parse(retryAfter);
|
|
180418
|
-
if (!Number.isNaN(dateMs))
|
|
180419
|
-
return Math.max(0, dateMs - Date.now());
|
|
180420
|
-
}
|
|
180421
|
-
if (headers["x-ratelimit-remaining"] === "0") {
|
|
180422
|
-
const reset = headers["x-ratelimit-reset"];
|
|
180423
|
-
if (typeof reset === "string" && reset.trim() !== "") {
|
|
180424
|
-
const resetEpoch = Number(reset);
|
|
180425
|
-
if (Number.isFinite(resetEpoch))
|
|
180426
|
-
return Math.max(0, resetEpoch * 1e3 - Date.now());
|
|
180427
|
-
}
|
|
180428
|
-
}
|
|
180429
|
-
return void 0;
|
|
180469
|
+
// node_modules/.pnpm/yes@0.2.3_typescript@5.9.3/node_modules/yes/dist/index.js
|
|
180470
|
+
function delay2(schedule, attempt) {
|
|
180471
|
+
const d3 = schedule[attempt - 1];
|
|
180472
|
+
return d3 === void 0 ? -1 : Math.round(d3 / 2 + Math.random() * d3 / 2);
|
|
180430
180473
|
}
|
|
180431
180474
|
var ValidationError = class extends Error {
|
|
180432
|
-
|
|
180433
|
-
issues;
|
|
180475
|
+
name = "ValidationError";
|
|
180434
180476
|
constructor(result) {
|
|
180435
|
-
const
|
|
180436
|
-
super(message);
|
|
180437
|
-
this.
|
|
180438
|
-
this.result = result;
|
|
180439
|
-
this.issues = result.issues;
|
|
180477
|
+
const { message } = result;
|
|
180478
|
+
super(typeof message === "string" ? message : `validation failed: ${result.issues.map((i) => i.message).join(", ")}`);
|
|
180479
|
+
Object.assign(this, { result, issues: result.issues });
|
|
180440
180480
|
}
|
|
180441
180481
|
};
|
|
180442
180482
|
async function assertSchema(schema2, value2) {
|
|
@@ -180445,322 +180485,212 @@ async function assertSchema(schema2, value2) {
|
|
|
180445
180485
|
throw new ValidationError(result);
|
|
180446
180486
|
return result.value;
|
|
180447
180487
|
}
|
|
180448
|
-
|
|
180449
|
-
|
|
180450
|
-
|
|
180451
|
-
|
|
180452
|
-
|
|
180453
|
-
|
|
180454
|
-
|
|
180455
|
-
|
|
180456
|
-
|
|
180457
|
-
|
|
180458
|
-
|
|
180459
|
-
|
|
180460
|
-
|
|
180461
|
-
|
|
180462
|
-
|
|
180463
|
-
|
|
180464
|
-
};
|
|
180465
|
-
}
|
|
180466
|
-
|
|
180467
|
-
|
|
180468
|
-
|
|
180469
|
-
|
|
180470
|
-
|
|
180471
|
-
|
|
180472
|
-
|
|
180473
|
-
var isThenable = (value2) => typeof value2?.then === "function";
|
|
180474
|
-
function freshEntry(value2) {
|
|
180475
|
-
if (value2 === null || typeof value2 !== "object" || !("value" in value2))
|
|
180476
|
-
return void 0;
|
|
180477
|
-
const expires = value2.expires;
|
|
180478
|
-
return typeof expires === "number" && expires > Date.now() ? value2 : void 0;
|
|
180479
|
-
}
|
|
180480
|
-
var adapterMethods = ["get", "set", "delete", "list"];
|
|
180481
|
-
function callAdapter(method, key, run) {
|
|
180482
|
-
let result;
|
|
180483
|
-
try {
|
|
180484
|
-
result = run();
|
|
180485
|
-
} catch (error49) {
|
|
180486
|
-
throw new AdapterError(method, key, error49);
|
|
180487
|
-
}
|
|
180488
|
-
if (!isThenable(result))
|
|
180489
|
-
return result;
|
|
180490
|
-
return result.then(void 0, (error49) => {
|
|
180491
|
-
throw new AdapterError(method, key, error49);
|
|
180492
|
-
});
|
|
180493
|
-
}
|
|
180494
|
-
var DELETE_BATCH = 1e3;
|
|
180495
|
-
function sweep(store, prefix, match3) {
|
|
180496
|
-
const now = Date.now();
|
|
180497
|
-
const keys = [];
|
|
180498
|
-
let count = 0;
|
|
180499
|
-
let matchError;
|
|
180500
|
-
const take = ([key, entry]) => {
|
|
180501
|
-
if (!(entry.expires > now))
|
|
180502
|
-
return void keys.push(key);
|
|
180503
|
-
let matched;
|
|
180488
|
+
function op(options) {
|
|
180489
|
+
return build3(options, true);
|
|
180490
|
+
}
|
|
180491
|
+
function build3(options, cacheMethods) {
|
|
180492
|
+
const { name, input: inputSchema, output: outputSchema, run, dedupe, ttl, cache: adapter } = options;
|
|
180493
|
+
const { retry } = options;
|
|
180494
|
+
const delayFor = Array.isArray(retry) ? (_, attempt) => delay2(retry, attempt) : retry;
|
|
180495
|
+
if (ttl !== void 0 && typeof ttl !== "function" && !isLifetime(ttl)) {
|
|
180496
|
+
throw new TypeError(`yes.op: ttl must be a positive number of milliseconds, got ${ttl}`);
|
|
180497
|
+
}
|
|
180498
|
+
const lifetime = typeof ttl === "function" ? ttl : () => ttl;
|
|
180499
|
+
if (adapter && (!name || name.includes(":"))) {
|
|
180500
|
+
throw new TypeError(`yes.op: an op with a cache adapter needs a name without ":", got ${JSON.stringify(name)}`);
|
|
180501
|
+
}
|
|
180502
|
+
if (adapter && ttl === void 0)
|
|
180503
|
+
throw new TypeError(`yes.op: a cache adapter does nothing without a ttl`);
|
|
180504
|
+
const store = ttl === void 0 ? void 0 : adapter ?? memory({ maxItems: options.maxItems });
|
|
180505
|
+
const prefix = adapter ? `yes:${name}:` : "";
|
|
180506
|
+
const label = name ? `[${name}] ` : "";
|
|
180507
|
+
const logCache = (event) => () => {
|
|
180508
|
+
if (name && store && process.env.NODE_ENV === "production")
|
|
180509
|
+
console.log(`${label}cache ${event}`);
|
|
180510
|
+
};
|
|
180511
|
+
const { cacheHit = logCache("hit"), cacheMiss = logCache("miss") } = options;
|
|
180512
|
+
const keyOf = (input) => {
|
|
180504
180513
|
try {
|
|
180505
|
-
|
|
180514
|
+
return cacheKey2(input);
|
|
180506
180515
|
} catch (error49) {
|
|
180507
|
-
|
|
180508
|
-
throw error49;
|
|
180509
|
-
}
|
|
180510
|
-
if (matched) {
|
|
180511
|
-
keys.push(key);
|
|
180512
|
-
count++;
|
|
180516
|
+
throw new Error(`${label}${error49.message}. dedupe and ttl key the input, and a query always dedupes; a write is yes.mutation, which never keys.`, { cause: error49 });
|
|
180513
180517
|
}
|
|
180514
180518
|
};
|
|
180515
|
-
const
|
|
180516
|
-
|
|
180519
|
+
const report = (attempt, message, error49, key) => {
|
|
180520
|
+
console.log(`${label}attempt ${attempt} ${message}`);
|
|
180521
|
+
const data = key === void 0 ? { error: error49, attempt } : { key, error: error49, attempt };
|
|
180522
|
+
console.log(...label ? [label, data] : [data]);
|
|
180517
180523
|
};
|
|
180518
|
-
const
|
|
180519
|
-
for (let
|
|
180520
|
-
const batch = keys.slice(i, i + DELETE_BATCH);
|
|
180521
|
-
const deleted = callAdapter("delete", prefix, () => store.delete(batch));
|
|
180522
|
-
if (isThenable(deleted))
|
|
180523
|
-
return Promise.resolve(deleted).then(() => deleteFrom(i + DELETE_BATCH));
|
|
180524
|
-
}
|
|
180525
|
-
return count;
|
|
180526
|
-
};
|
|
180527
|
-
let listed;
|
|
180528
|
-
try {
|
|
180529
|
-
listed = store.list(prefix);
|
|
180530
|
-
} catch (error49) {
|
|
180531
|
-
return fail(error49);
|
|
180532
|
-
}
|
|
180533
|
-
if (!isThenable(listed) && Symbol.iterator in Object(listed)) {
|
|
180534
|
-
try {
|
|
180535
|
-
for (const item of listed)
|
|
180536
|
-
take(item);
|
|
180537
|
-
} catch (error49) {
|
|
180538
|
-
fail(error49);
|
|
180539
|
-
}
|
|
180540
|
-
return deleteFrom(0);
|
|
180541
|
-
}
|
|
180542
|
-
return (async () => {
|
|
180543
|
-
try {
|
|
180544
|
-
for await (const item of await listed)
|
|
180545
|
-
take(item);
|
|
180546
|
-
} catch (error49) {
|
|
180547
|
-
fail(error49);
|
|
180548
|
-
}
|
|
180549
|
-
return deleteFrom(0);
|
|
180550
|
-
})();
|
|
180551
|
-
}
|
|
180552
|
-
function _op(fn2, options, schemas = {}) {
|
|
180553
|
-
const { ttl, cache: adapter } = options;
|
|
180554
|
-
const shouldCache = ttl !== void 0;
|
|
180555
|
-
if (shouldCache && !(ttl > 0 && Number.isFinite(ttl))) {
|
|
180556
|
-
throw new Error(`ttl must be a positive number of milliseconds, got ${ttl}`);
|
|
180557
|
-
}
|
|
180558
|
-
if (adapter) {
|
|
180559
|
-
if (!options.name)
|
|
180560
|
-
throw new Error(`an op with a cache adapter needs a name: its keys are "yes:<name>:<hash>"`);
|
|
180561
|
-
if (options.name.includes(":")) {
|
|
180562
|
-
throw new Error(`op name "${options.name}" cannot contain ":" with a cache adapter: its keys would overlap another op's`);
|
|
180563
|
-
}
|
|
180564
|
-
if (!shouldCache)
|
|
180565
|
-
throw new Error(`${options.name}: a cache adapter does nothing without a ttl`);
|
|
180566
|
-
if (options.maxItems !== void 0) {
|
|
180567
|
-
throw new Error(`${options.name}: maxItems sizes the default memory store; size the adapter instead`);
|
|
180568
|
-
}
|
|
180569
|
-
const missing = adapterMethods.filter((method) => typeof adapter[method] !== "function");
|
|
180570
|
-
if (missing.length) {
|
|
180571
|
-
throw new Error(`${options.name}: cache is missing ${missing.join(", ")}; an adapter has get, set, delete and list (a Map or a Keyv is not one)`);
|
|
180572
|
-
}
|
|
180573
|
-
}
|
|
180574
|
-
const defaultStore = shouldCache && !adapter ? memory({ maxItems: options.maxItems }) : void 0;
|
|
180575
|
-
const store = adapter ?? defaultStore;
|
|
180576
|
-
const prefix = adapter ? `yes:${options.name}:` : "";
|
|
180577
|
-
const inFlightPromises = /* @__PURE__ */ new Map();
|
|
180578
|
-
const namePrefix = options.name ? `[${options.name}] ` : "";
|
|
180579
|
-
const defaultCacheHit = options.cacheHit === null ? () => {
|
|
180580
|
-
} : options.cacheHit ?? (() => {
|
|
180581
|
-
if (options.name && shouldCache)
|
|
180582
|
-
log2.prod(`${namePrefix}cache hit`);
|
|
180583
|
-
});
|
|
180584
|
-
const defaultCacheMiss = options.cacheMiss === null ? () => {
|
|
180585
|
-
} : options.cacheMiss ?? (() => {
|
|
180586
|
-
if (options.name && shouldCache)
|
|
180587
|
-
log2.prod(`${namePrefix}cache miss`);
|
|
180588
|
-
});
|
|
180589
|
-
const methodKey = (value2, method) => {
|
|
180590
|
-
const toKey = (input) => {
|
|
180524
|
+
const attempts = async (input, ctx, key, trace) => {
|
|
180525
|
+
for (let attempt = 1; ; attempt++) {
|
|
180591
180526
|
try {
|
|
180592
|
-
|
|
180593
|
-
|
|
180594
|
-
|
|
180595
|
-
|
|
180596
|
-
}
|
|
180597
|
-
|
|
180598
|
-
|
|
180599
|
-
|
|
180600
|
-
|
|
180601
|
-
|
|
180602
|
-
|
|
180603
|
-
|
|
180604
|
-
|
|
180605
|
-
|
|
180606
|
-
|
|
180607
|
-
|
|
180608
|
-
|
|
180609
|
-
|
|
180610
|
-
} catch (error49) {
|
|
180611
|
-
const errorMessage = error49 instanceof Error ? error49.message : String(error49);
|
|
180612
|
-
throw new Error(`failed to create cache key${namePrefix ? ` for ${options.name}` : ""}: ${errorMessage}`);
|
|
180613
|
-
}
|
|
180614
|
-
const trace = debugTrace(namePrefix, key);
|
|
180615
|
-
trace?.log("cache lookup started");
|
|
180616
|
-
const inFlight = inFlightPromises.get(key);
|
|
180617
|
-
if (inFlight) {
|
|
180618
|
-
trace?.log("cache hit (in-flight)");
|
|
180619
|
-
defaultCacheHit(key);
|
|
180620
|
-
return inFlight;
|
|
180621
|
-
}
|
|
180622
|
-
const fullKey = store ? prefix + key : "";
|
|
180623
|
-
let pendingRead;
|
|
180624
|
-
if (store) {
|
|
180625
|
-
let read2;
|
|
180626
|
-
try {
|
|
180627
|
-
read2 = store.get(fullKey);
|
|
180628
|
-
} catch (error49) {
|
|
180629
|
-
throw new AdapterError("get", fullKey, error49);
|
|
180630
|
-
}
|
|
180631
|
-
if (isThenable(read2)) {
|
|
180632
|
-
pendingRead = read2.then(void 0, (error49) => {
|
|
180633
|
-
throw new AdapterError("get", fullKey, error49);
|
|
180634
|
-
});
|
|
180635
|
-
} else {
|
|
180636
|
-
const entry = store === defaultStore ? read2 : freshEntry(read2);
|
|
180637
|
-
if (entry) {
|
|
180638
|
-
trace?.log("cache hit (from store)", { runtime: trace.since(trace.start) });
|
|
180639
|
-
defaultCacheHit(key);
|
|
180640
|
-
return entry.value;
|
|
180527
|
+
const returned = await run(input, ctx);
|
|
180528
|
+
const result = outputSchema ? await assertSchema(outputSchema, returned) : returned;
|
|
180529
|
+
trace?.(`run resolved on attempt ${attempt}`);
|
|
180530
|
+
return result;
|
|
180531
|
+
} catch (thrown) {
|
|
180532
|
+
let error49 = thrown;
|
|
180533
|
+
let wait = -1;
|
|
180534
|
+
if (delayFor && !(error49 instanceof ValidationError)) {
|
|
180535
|
+
try {
|
|
180536
|
+
wait = delayFor(error49, attempt);
|
|
180537
|
+
} catch (stop2) {
|
|
180538
|
+
error49 = stop2;
|
|
180539
|
+
}
|
|
180540
|
+
}
|
|
180541
|
+
if (wait >= 0) {
|
|
180542
|
+
report(attempt, `failed, retrying in ${wait}ms`, error49, key);
|
|
180543
|
+
await sleep2(wait);
|
|
180544
|
+
continue;
|
|
180641
180545
|
}
|
|
180546
|
+
if (attempt > 1)
|
|
180547
|
+
report(attempt, "failed, not retrying", error49, key);
|
|
180548
|
+
trace?.(`run failed on attempt ${attempt}`, { error: error49 });
|
|
180549
|
+
throw error49;
|
|
180642
180550
|
}
|
|
180643
180551
|
}
|
|
180644
|
-
|
|
180645
|
-
|
|
180552
|
+
};
|
|
180553
|
+
const hit = (key, trace, from, value2) => {
|
|
180554
|
+
trace?.(`cache hit (${from})`);
|
|
180555
|
+
cacheHit?.(key);
|
|
180556
|
+
return value2;
|
|
180557
|
+
};
|
|
180558
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
180559
|
+
const call = async (rawInput, ctx) => {
|
|
180560
|
+
const input = inputSchema ? await assertSchema(inputSchema, rawInput) : rawInput;
|
|
180561
|
+
if (!dedupe && !store)
|
|
180562
|
+
return attempts(input, ctx, void 0, debugTrace(label));
|
|
180563
|
+
const key = keyOf(input);
|
|
180564
|
+
const trace = debugTrace(label, key);
|
|
180565
|
+
const shared = inFlight.get(key);
|
|
180566
|
+
if (shared)
|
|
180567
|
+
return hit(key, trace, "in-flight", shared);
|
|
180568
|
+
const fullKey = prefix + key;
|
|
180569
|
+
const read2 = store && callAdapter("get", fullKey, () => store.get(fullKey));
|
|
180570
|
+
const entry = freshEntry(read2);
|
|
180571
|
+
if (entry)
|
|
180572
|
+
return hit(key, trace, "from store", entry.value);
|
|
180646
180573
|
const promise2 = (async () => {
|
|
180647
|
-
|
|
180648
|
-
|
|
180649
|
-
|
|
180650
|
-
|
|
180651
|
-
|
|
180652
|
-
|
|
180653
|
-
|
|
180654
|
-
|
|
180655
|
-
trace?.log("cache miss, executing function");
|
|
180656
|
-
defaultCacheMiss(key);
|
|
180657
|
-
let result;
|
|
180658
|
-
let lastError;
|
|
180659
|
-
let attempt = 0;
|
|
180660
|
-
for (; attempt <= retries.length; attempt++) {
|
|
180661
|
-
try {
|
|
180662
|
-
const returned = await fn2(input, ctx);
|
|
180663
|
-
result = schemas.output ? await assertSchema(schemas.output, returned) : returned;
|
|
180664
|
-
break;
|
|
180665
|
-
} catch (error49) {
|
|
180666
|
-
if (error49 instanceof ValidationError || options.rethrow?.(error49))
|
|
180667
|
-
throw error49;
|
|
180668
|
-
lastError = error49;
|
|
180669
|
-
const isLastAttempt = attempt >= retries.length;
|
|
180670
|
-
if (isLastAttempt) {
|
|
180671
|
-
if (namePrefix) {
|
|
180672
|
-
log2.info(`${namePrefix}attempt ${attempt + 1}/${retries.length + 1} failed, no more retries`);
|
|
180673
|
-
log2.info(`${namePrefix}`, { key, error: error49, attempt });
|
|
180674
|
-
} else {
|
|
180675
|
-
log2.info(`attempt ${attempt + 1}/${retries.length + 1} failed, no more retries`);
|
|
180676
|
-
log2.info({ key, error: error49, attempt });
|
|
180677
|
-
}
|
|
180678
|
-
} else {
|
|
180679
|
-
let delay2 = retries[attempt];
|
|
180680
|
-
if (options.retryAfter) {
|
|
180681
|
-
const extract = options.retryAfter === true ? retryAfterMs : options.retryAfter;
|
|
180682
|
-
const hint = extract(error49);
|
|
180683
|
-
if (hint !== void 0) {
|
|
180684
|
-
const cap = options.retryAfterCap ?? DEFAULT_RETRY_AFTER_CAP_MS;
|
|
180685
|
-
delay2 = Math.max(delay2, Math.min(cap, hint));
|
|
180686
|
-
}
|
|
180687
|
-
}
|
|
180688
|
-
delay2 = jitter(delay2);
|
|
180689
|
-
if (namePrefix) {
|
|
180690
|
-
log2.info(`${namePrefix}attempt ${attempt + 1}/${retries.length + 1} failed, retrying in ${delay2}ms`);
|
|
180691
|
-
log2.info(`${namePrefix}`, { key, error: error49, attempt });
|
|
180692
|
-
} else {
|
|
180693
|
-
log2.info(`attempt ${attempt + 1}/${retries.length + 1} failed, retrying in ${delay2}ms`);
|
|
180694
|
-
log2.info({ key, error: error49, attempt });
|
|
180695
|
-
}
|
|
180696
|
-
await sleep2(delay2);
|
|
180697
|
-
}
|
|
180698
|
-
}
|
|
180699
|
-
}
|
|
180700
|
-
if (attempt > retries.length) {
|
|
180701
|
-
trace?.log("function failed after all retries", {
|
|
180702
|
-
runtime: trace.since(execStart),
|
|
180703
|
-
attempts: retries.length + 1,
|
|
180704
|
-
error: lastError instanceof Error ? lastError.message : lastError
|
|
180705
|
-
});
|
|
180706
|
-
throw lastError;
|
|
180707
|
-
}
|
|
180708
|
-
const skip = options.skipCache ? options.skipCache(result) : false;
|
|
180709
|
-
const storable = store !== void 0 && result !== null && result !== void 0 && !(result instanceof Error) && !skip;
|
|
180710
|
-
let cached4 = false;
|
|
180711
|
-
if (storable) {
|
|
180574
|
+
const stored = isThenable(read2) ? freshEntry(await read2) : void 0;
|
|
180575
|
+
if (stored)
|
|
180576
|
+
return hit(key, trace, "from store", stored.value);
|
|
180577
|
+
trace?.("cache miss, running");
|
|
180578
|
+
cacheMiss?.(key);
|
|
180579
|
+
const result = await attempts(input, ctx, key, trace);
|
|
180580
|
+
const ms = store && !options.skipCache?.(result) && result != null && !(result instanceof Error) && lifetime(result);
|
|
180581
|
+
if (store && isLifetime(ms)) {
|
|
180712
180582
|
const created = Date.now();
|
|
180713
|
-
const entry = { value: result, created, expires: created + ttl, input };
|
|
180714
180583
|
try {
|
|
180715
|
-
|
|
180716
|
-
if (isThenable(written))
|
|
180717
|
-
await written;
|
|
180718
|
-
cached4 = true;
|
|
180584
|
+
await store.set(fullKey, { value: result, created, expires: created + ms, input }, ms);
|
|
180719
180585
|
} catch (error49) {
|
|
180720
|
-
|
|
180586
|
+
console.error(`${label}cache write failed, returning the result uncached`, new AdapterError("set", fullKey, error49));
|
|
180721
180587
|
}
|
|
180722
180588
|
}
|
|
180723
|
-
trace?.log("function executed successfully", { runtime: trace.since(execStart), attempt: attempt + 1, cached: cached4 });
|
|
180724
180589
|
return result;
|
|
180725
180590
|
})();
|
|
180726
|
-
|
|
180727
|
-
|
|
180728
|
-
|
|
180729
|
-
|
|
180730
|
-
|
|
180591
|
+
if (!dedupe)
|
|
180592
|
+
return promise2;
|
|
180593
|
+
inFlight.set(key, promise2);
|
|
180594
|
+
return promise2.finally(() => inFlight.delete(key));
|
|
180595
|
+
};
|
|
180596
|
+
if (!cacheMethods)
|
|
180597
|
+
return call;
|
|
180598
|
+
const withKey = (input, use) => {
|
|
180599
|
+
const toKey = (result2) => use(prefix + keyOf(result2 && !result2.issues ? result2.value : input));
|
|
180600
|
+
const result = inputSchema?.["~standard"].validate(input);
|
|
180601
|
+
return result instanceof Promise ? result.then(toKey) : toKey(result);
|
|
180602
|
+
};
|
|
180603
|
+
return Object.assign(call, {
|
|
180604
|
+
clear: async (input) => {
|
|
180605
|
+
if (!store)
|
|
180606
|
+
return;
|
|
180607
|
+
if (input === void 0)
|
|
180608
|
+
await sweep(store, prefix, () => true);
|
|
180609
|
+
else
|
|
180610
|
+
await withKey(input, (key) => callAdapter("delete", key, () => store.delete([key])));
|
|
180611
|
+
},
|
|
180612
|
+
// the memory store peeks, so asking whether a key is cached does not change which key is evicted next
|
|
180613
|
+
has: async (input) => !!store && !!freshEntry(await withKey(input, (key) => callAdapter("get", key, () => "peek" in store ? store.peek(key) : store.get(key)))),
|
|
180614
|
+
// not `async`: on the memory store a predicate that throws throws here, not in a promise nobody awaits
|
|
180615
|
+
invalidate: (match3) => {
|
|
180616
|
+
const accepts = typeof match3 === "function" ? match3 : fieldsMatch(match3);
|
|
180617
|
+
return Promise.resolve(store ? sweep(store, prefix, accepts) : 0);
|
|
180731
180618
|
}
|
|
180732
|
-
};
|
|
180733
|
-
|
|
180734
|
-
|
|
180735
|
-
|
|
180736
|
-
|
|
180737
|
-
|
|
180738
|
-
|
|
180619
|
+
});
|
|
180620
|
+
}
|
|
180621
|
+
function query(options) {
|
|
180622
|
+
return op({ ...options, dedupe: true });
|
|
180623
|
+
}
|
|
180624
|
+
function mutation({ dedupe: _dedupe, ttl: _ttl, cache: _cache, ...options }) {
|
|
180625
|
+
return build3(options, false);
|
|
180626
|
+
}
|
|
180627
|
+
function debugTrace(label, key) {
|
|
180628
|
+
if (process.env.LOG_LEVEL !== "debug")
|
|
180629
|
+
return;
|
|
180630
|
+
const prefix = `${label}[${(/* @__PURE__ */ new Date()).toISOString()}]`;
|
|
180631
|
+
const start = performance.now();
|
|
180632
|
+
return (message, data) => console.log(`${prefix} ${message} +${Math.round(performance.now() - start)}ms`, { ...key && { key }, ...data });
|
|
180633
|
+
}
|
|
180634
|
+
var isLifetime = (ms) => typeof ms === "number" && ms > 0 && Number.isFinite(ms);
|
|
180635
|
+
function fieldsMatch(partial3) {
|
|
180636
|
+
const fields = Object.entries(partial3).map(([field, value2]) => [
|
|
180637
|
+
field,
|
|
180638
|
+
value2 === void 0 ? void 0 : canonical(value2)
|
|
180639
|
+
]);
|
|
180640
|
+
return (input) => typeof input === "object" && input !== null && fields.every(([field, value2]) => {
|
|
180641
|
+
const actual = input[field];
|
|
180642
|
+
return actual === void 0 ? value2 === void 0 : value2 !== void 0 && canonical(actual) === value2;
|
|
180643
|
+
});
|
|
180644
|
+
}
|
|
180645
|
+
var isThenable = (value2) => typeof value2?.then === "function";
|
|
180646
|
+
function freshEntry(value2) {
|
|
180647
|
+
return typeof value2?.expires === "number" && value2.expires > Date.now() && "value" in value2 ? value2 : void 0;
|
|
180648
|
+
}
|
|
180649
|
+
function callAdapter(method, key, run) {
|
|
180650
|
+
try {
|
|
180651
|
+
const result = run();
|
|
180652
|
+
if (!isThenable(result))
|
|
180653
|
+
return result;
|
|
180654
|
+
return result.then(void 0, (error49) => {
|
|
180655
|
+
throw new AdapterError(method, key, error49);
|
|
180656
|
+
});
|
|
180657
|
+
} catch (error49) {
|
|
180658
|
+
throw new AdapterError(method, key, error49);
|
|
180659
|
+
}
|
|
180660
|
+
}
|
|
180661
|
+
function sweep(store, prefix, match3) {
|
|
180662
|
+
const purge = (listed2) => {
|
|
180663
|
+
const now = Date.now();
|
|
180664
|
+
const keys = [];
|
|
180665
|
+
let count = 0;
|
|
180666
|
+
for (const [key, { input, expires }] of listed2) {
|
|
180667
|
+
if (!(expires > now))
|
|
180668
|
+
keys.push(key);
|
|
180669
|
+
else if (match3(input)) {
|
|
180670
|
+
keys.push(key);
|
|
180671
|
+
count++;
|
|
180672
|
+
}
|
|
180739
180673
|
}
|
|
180740
|
-
|
|
180741
|
-
|
|
180742
|
-
|
|
180743
|
-
|
|
180744
|
-
|
|
180745
|
-
|
|
180746
|
-
|
|
180747
|
-
if (!store)
|
|
180748
|
-
return false;
|
|
180749
|
-
let fullKey = methodKey(key, "has");
|
|
180750
|
-
if (typeof fullKey !== "string")
|
|
180751
|
-
fullKey = await fullKey;
|
|
180752
|
-
const target = fullKey;
|
|
180753
|
-
const memoryStore = store;
|
|
180754
|
-
const read2 = callAdapter("get", target, () => memoryStore.peek ? memoryStore.peek(target) : store.get(target));
|
|
180755
|
-
return freshEntry(await read2) !== void 0;
|
|
180756
|
-
};
|
|
180757
|
-
cachedFn.invalidate = (predicate) => {
|
|
180758
|
-
if (!store)
|
|
180759
|
-
return Promise.resolve(0);
|
|
180760
|
-
const count = sweep(store, prefix, predicate);
|
|
180761
|
-
return typeof count === "number" ? Promise.resolve(count) : count;
|
|
180674
|
+
const remove = (from) => {
|
|
180675
|
+
if (from >= keys.length)
|
|
180676
|
+
return count;
|
|
180677
|
+
const deleted = callAdapter("delete", prefix, () => store.delete(keys.slice(from, from + 1e3)));
|
|
180678
|
+
return isThenable(deleted) ? Promise.resolve(deleted).then(() => remove(from + 1e3)) : remove(from + 1e3);
|
|
180679
|
+
};
|
|
180680
|
+
return remove(0);
|
|
180762
180681
|
};
|
|
180763
|
-
|
|
180682
|
+
const listed = callAdapter("list", prefix, () => {
|
|
180683
|
+
const listed2 = store.list(prefix);
|
|
180684
|
+
if (Array.isArray(listed2))
|
|
180685
|
+
return listed2;
|
|
180686
|
+
return (async () => {
|
|
180687
|
+
const items = [];
|
|
180688
|
+
for await (const item of await listed2)
|
|
180689
|
+
items.push(item);
|
|
180690
|
+
return items;
|
|
180691
|
+
})();
|
|
180692
|
+
});
|
|
180693
|
+
return Array.isArray(listed) ? purge(listed) : listed.then(purge);
|
|
180764
180694
|
}
|
|
180765
180695
|
|
|
180766
180696
|
// utils/progressComment.ts
|
|
@@ -180908,13 +180838,14 @@ function ensureRepoState(toolState, init) {
|
|
|
180908
180838
|
// utils/changeImpact.ts
|
|
180909
180839
|
import { spawn as spawn2 } from "node:child_process";
|
|
180910
180840
|
import { writeFileSync as writeFileSync7 } from "node:fs";
|
|
180911
|
-
import { join as
|
|
180841
|
+
import { join as join9 } from "node:path";
|
|
180912
180842
|
var MAX_CANDIDATES = 24;
|
|
180913
180843
|
var MAX_ATOM_LENGTH = 128;
|
|
180914
180844
|
var MAX_ATOMS = 12;
|
|
180915
180845
|
var MAX_REFERENCES = 6;
|
|
180916
180846
|
var MAX_EXCERPT = 160;
|
|
180917
180847
|
var MAX_BYTES = 16e3;
|
|
180848
|
+
var LOOKUP_BUDGET_MS = 6e4;
|
|
180918
180849
|
function isSymbolShaped(atom) {
|
|
180919
180850
|
return atom.length >= 4 && atom.length <= MAX_ATOM_LENGTH && /[A-Z_]/.test(atom);
|
|
180920
180851
|
}
|
|
@@ -181117,7 +181048,7 @@ function consumeGrepChunk(params) {
|
|
|
181117
181048
|
async function lookupReferences(params) {
|
|
181118
181049
|
const buckets = emptyBuckets(params.candidates);
|
|
181119
181050
|
if (params.candidates.length === 0) return { buckets, error: void 0 };
|
|
181120
|
-
const
|
|
181051
|
+
const pattern = params.candidates.map((candidate) => candidate.atom).join("|");
|
|
181121
181052
|
const child = spawn2(
|
|
181122
181053
|
"git",
|
|
181123
181054
|
[
|
|
@@ -181128,13 +181059,14 @@ async function lookupReferences(params) {
|
|
|
181128
181059
|
"-z",
|
|
181129
181060
|
"-I",
|
|
181130
181061
|
"-w",
|
|
181131
|
-
"-
|
|
181132
|
-
|
|
181062
|
+
"-E",
|
|
181063
|
+
"-e",
|
|
181064
|
+
pattern,
|
|
181133
181065
|
params.treeish,
|
|
181134
181066
|
"--",
|
|
181135
181067
|
":(top)"
|
|
181136
181068
|
],
|
|
181137
|
-
{ env: resolveEnv(void 0), stdio: ["ignore", "pipe", "pipe"] }
|
|
181069
|
+
{ env: resolveEnv(void 0), stdio: ["ignore", "pipe", "pipe"], signal: params.signal }
|
|
181138
181070
|
);
|
|
181139
181071
|
const state = createGrepRecordState();
|
|
181140
181072
|
const maxAtomLength = Math.max(...params.candidates.map((candidate) => candidate.atom.length));
|
|
@@ -181154,7 +181086,7 @@ async function lookupReferences(params) {
|
|
|
181154
181086
|
child.stderr.resume();
|
|
181155
181087
|
const status = await new Promise((resolve3) => {
|
|
181156
181088
|
child.once("error", (error49) => {
|
|
181157
|
-
spawnError = error49.message;
|
|
181089
|
+
spawnError = error49.cause instanceof Error ? error49.cause.message : error49.message;
|
|
181158
181090
|
resolve3(null);
|
|
181159
181091
|
});
|
|
181160
181092
|
child.once("close", resolve3);
|
|
@@ -181242,8 +181174,10 @@ async function createChangeImpactArtifact(ctx, params) {
|
|
|
181242
181174
|
const lookup2 = await lookupReferences({
|
|
181243
181175
|
candidates: candidates.selected,
|
|
181244
181176
|
addedLines: candidates.addedLines,
|
|
181245
|
-
treeish: params.headSha
|
|
181177
|
+
treeish: params.headSha,
|
|
181178
|
+
signal: AbortSignal.any([params.signal, AbortSignal.timeout(LOOKUP_BUDGET_MS)])
|
|
181246
181179
|
});
|
|
181180
|
+
params.signal.throwIfAborted();
|
|
181247
181181
|
const artifact = formatArtifact({
|
|
181248
181182
|
entries: candidates.selected.map((change) => {
|
|
181249
181183
|
return { change, bucket: lookup2.buckets.get(change.atom) ?? { count: 0, samples: [] } };
|
|
@@ -181255,7 +181189,7 @@ async function createChangeImpactArtifact(ctx, params) {
|
|
|
181255
181189
|
headSha: params.headSha,
|
|
181256
181190
|
lookupError: lookup2.error
|
|
181257
181191
|
});
|
|
181258
|
-
const path4 =
|
|
181192
|
+
const path4 = join9(ctx.tmpdir, `pr-${params.pullNumber}-${params.headSha.slice(0, 7)}-impact.md`);
|
|
181259
181193
|
writeFileSync7(path4, artifact.content);
|
|
181260
181194
|
return {
|
|
181261
181195
|
path: path4,
|
|
@@ -181509,7 +181443,7 @@ function readNumber(params) {
|
|
|
181509
181443
|
import { execSync } from "node:child_process";
|
|
181510
181444
|
import { createHash } from "node:crypto";
|
|
181511
181445
|
import { readFileSync as readFileSync4, realpathSync, unlinkSync } from "node:fs";
|
|
181512
|
-
import { join as
|
|
181446
|
+
import { join as join10 } from "node:path";
|
|
181513
181447
|
|
|
181514
181448
|
// utils/shell.ts
|
|
181515
181449
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -181599,7 +181533,7 @@ function resolveHooksDir(cwd, gitPath) {
|
|
|
181599
181533
|
cwd,
|
|
181600
181534
|
log: false
|
|
181601
181535
|
}).trim();
|
|
181602
|
-
const hooksDir =
|
|
181536
|
+
const hooksDir = join10(commonDir, "hooks");
|
|
181603
181537
|
hooksDirCache.set(cwd, hooksDir);
|
|
181604
181538
|
return hooksDir;
|
|
181605
181539
|
}
|
|
@@ -181646,7 +181580,8 @@ async function $git(subcommand, args2, options) {
|
|
|
181646
181580
|
GIT_CONFIG_COUNT: "0",
|
|
181647
181581
|
GIT_CONFIG_PARAMETERS: ""
|
|
181648
181582
|
},
|
|
181649
|
-
activityTimeout: 0
|
|
181583
|
+
activityTimeout: 0,
|
|
181584
|
+
signal: options.signal
|
|
181650
181585
|
});
|
|
181651
181586
|
if (result.stderr.includes("askpass-compromised")) {
|
|
181652
181587
|
log.info("askpass code was replayed after revoke \u2014 token has been revoked");
|
|
@@ -181713,9 +181648,10 @@ import { spawnSync as spawnSync7 } from "node:child_process";
|
|
|
181713
181648
|
// mcp/shell.ts
|
|
181714
181649
|
import { spawn as spawn3, spawnSync as spawnSync6 } from "node:child_process";
|
|
181715
181650
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
181716
|
-
import {
|
|
181651
|
+
import { once } from "node:events";
|
|
181652
|
+
import { closeSync, existsSync as existsSync7, openSync, writeFileSync as writeFileSync8 } from "node:fs";
|
|
181717
181653
|
import { userInfo as userInfo2 } from "node:os";
|
|
181718
|
-
import { join as
|
|
181654
|
+
import { join as join11 } from "node:path";
|
|
181719
181655
|
import { setTimeout as sleep3 } from "node:timers/promises";
|
|
181720
181656
|
|
|
181721
181657
|
// node_modules/.pnpm/@toon-format+toon@1.4.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
@@ -182359,7 +182295,7 @@ function buildFsMounts(repoDir) {
|
|
|
182359
182295
|
function shimMount() {
|
|
182360
182296
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
182361
182297
|
if (!tempDir) return "";
|
|
182362
|
-
const dir =
|
|
182298
|
+
const dir = join11(tempDir, "pm-bin").replace(/'/g, "'\\''");
|
|
182363
182299
|
return `[ -d '${dir}' ] && mount --bind '${dir}' '${dir}' 2>/dev/null && mount -o remount,bind,ro '${dir}' 2>/dev/null;`;
|
|
182364
182300
|
}
|
|
182365
182301
|
var _repoRoot;
|
|
@@ -182530,7 +182466,7 @@ ${spawnError}` : spawnError;
|
|
|
182530
182466
|
}
|
|
182531
182467
|
function capOutput(output) {
|
|
182532
182468
|
if (output.length <= MAX_OUTPUT_CHARS) return output;
|
|
182533
|
-
const fullPath =
|
|
182469
|
+
const fullPath = join11(getTempDir(), `shell-${randomUUID3().slice(0, 8)}.log`);
|
|
182534
182470
|
writeFileSync8(fullPath, output);
|
|
182535
182471
|
const elided = output.length - MAX_OUTPUT_CHARS;
|
|
182536
182472
|
return `... [${elided} chars truncated; output saved to ${fullPath}] ...
|
|
@@ -182546,7 +182482,7 @@ function ShellTool(ctx) {
|
|
|
182546
182482
|
return tool({
|
|
182547
182483
|
name: "shell",
|
|
182548
182484
|
timeoutMs: 12e4,
|
|
182549
|
-
description: `Execute shell commands securely. Environment is filtered to remove API keys and secrets.
|
|
182485
|
+
description: `Execute shell commands securely.${ctx.payload.shell === "restricted" ? " Environment is filtered to remove API keys and secrets." : ""}
|
|
182550
182486
|
|
|
182551
182487
|
Example: \`shell({ command: "pnpm test", description: "run the test suite" })\`.
|
|
182552
182488
|
|
|
@@ -182567,6 +182503,7 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
182567
182503
|
}
|
|
182568
182504
|
const timeout = Math.min(params.timeout ?? 3e4, 12e4);
|
|
182569
182505
|
const cwd = params.working_directory ?? process.cwd();
|
|
182506
|
+
if (!existsSync7(cwd)) throw new Error(`working_directory does not exist: ${cwd}`);
|
|
182570
182507
|
const env2 = resolveEnv(ctx.payload.shell === "enabled" ? "inherit" : "restricted");
|
|
182571
182508
|
if (params.command.includes("agent-browser")) {
|
|
182572
182509
|
const daemonError = ensureBrowserDaemon(ctx.toolState);
|
|
@@ -182585,8 +182522,8 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
182585
182522
|
if (params.background) {
|
|
182586
182523
|
const tempDir = getTempDir();
|
|
182587
182524
|
const handle = `bg-${randomUUID3().slice(0, 8)}`;
|
|
182588
|
-
const outputPath =
|
|
182589
|
-
const pidPath =
|
|
182525
|
+
const outputPath = join11(tempDir, `${handle}.log`);
|
|
182526
|
+
const pidPath = join11(tempDir, `${handle}.pid`);
|
|
182590
182527
|
const logFd = openSync(outputPath, "a");
|
|
182591
182528
|
let proc;
|
|
182592
182529
|
try {
|
|
@@ -182600,7 +182537,8 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
182600
182537
|
closeSync(logFd);
|
|
182601
182538
|
}
|
|
182602
182539
|
if (!proc.pid) {
|
|
182603
|
-
|
|
182540
|
+
const [error49] = await once(proc, "error");
|
|
182541
|
+
throw new Error(`failed to start background process: ${error49.message}`);
|
|
182604
182542
|
}
|
|
182605
182543
|
proc.unref();
|
|
182606
182544
|
writeFileSync8(pidPath, `${proc.pid}
|
|
@@ -182877,12 +182815,12 @@ function postProcessRangeDiff(raw2, contextLines = 3) {
|
|
|
182877
182815
|
// mcp/git.ts
|
|
182878
182816
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
182879
182817
|
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
182880
|
-
import { join as
|
|
182818
|
+
import { join as join14 } from "node:path";
|
|
182881
182819
|
|
|
182882
182820
|
// utils/apiCommit.ts
|
|
182883
182821
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
182884
182822
|
import { lstat, readlink } from "node:fs/promises";
|
|
182885
|
-
import { join as
|
|
182823
|
+
import { join as join12 } from "node:path";
|
|
182886
182824
|
var GITHUB_API = "https://api.github.com";
|
|
182887
182825
|
var MAX_BLOB_BYTES = 30 * 1024 * 1024;
|
|
182888
182826
|
var BLOB_UPLOAD_CONCURRENCY = 8;
|
|
@@ -182947,7 +182885,7 @@ async function assertApiCommittable(files) {
|
|
|
182947
182885
|
const root = getRepoRoot();
|
|
182948
182886
|
const attrs = $(
|
|
182949
182887
|
"git",
|
|
182950
|
-
["check-attr", "filter", "-z", "--", ...present.map((p) =>
|
|
182888
|
+
["check-attr", "filter", "-z", "--", ...present.map((p) => join12(root, p))],
|
|
182951
182889
|
{ log: false }
|
|
182952
182890
|
);
|
|
182953
182891
|
const parts = attrs.split("\0");
|
|
@@ -182959,7 +182897,7 @@ async function assertApiCommittable(files) {
|
|
|
182959
182897
|
}
|
|
182960
182898
|
}
|
|
182961
182899
|
for (const path4 of present) {
|
|
182962
|
-
const stat = await lstat(
|
|
182900
|
+
const stat = await lstat(join12(root, path4));
|
|
182963
182901
|
if (stat.isDirectory()) {
|
|
182964
182902
|
throw new Error(
|
|
182965
182903
|
`'${path4}' is a directory (nested repository or submodule?) \u2014 signed commits only support files and symlinks.`
|
|
@@ -182968,7 +182906,7 @@ async function assertApiCommittable(files) {
|
|
|
182968
182906
|
}
|
|
182969
182907
|
}
|
|
182970
182908
|
async function createBlobEntry(params) {
|
|
182971
|
-
const absPath =
|
|
182909
|
+
const absPath = join12(params.repoRoot, params.path);
|
|
182972
182910
|
const stat = await lstat(absPath);
|
|
182973
182911
|
if (stat.size > MAX_BLOB_BYTES) {
|
|
182974
182912
|
throw new Error(
|
|
@@ -183148,7 +183086,7 @@ this usually means your local branch has commits that were never pushed \u2014 s
|
|
|
183148
183086
|
var core4 = __toESM(require_core(), 1);
|
|
183149
183087
|
import { createSign } from "node:crypto";
|
|
183150
183088
|
import { rename, writeFile } from "node:fs/promises";
|
|
183151
|
-
import { dirname as dirname3, join as
|
|
183089
|
+
import { dirname as dirname3, join as join13 } from "node:path";
|
|
183152
183090
|
|
|
183153
183091
|
// node_modules/.pnpm/@octokit+plugin-throttling@11.0.5_@octokit+core@7.0.8/node_modules/@octokit/plugin-throttling/dist-bundle/index.js
|
|
183154
183092
|
var import_light = __toESM(require_light(), 1);
|
|
@@ -184391,7 +184329,7 @@ async function fetchWrapper(requestOptions) {
|
|
|
184391
184329
|
"fetch is not set. Please pass a fetch implementation as new Octokit({ request: { fetch }}). Learn more at https://github.com/octokit/octokit.js/#fetch-missing"
|
|
184392
184330
|
);
|
|
184393
184331
|
}
|
|
184394
|
-
const
|
|
184332
|
+
const log2 = requestOptions.request?.log || console;
|
|
184395
184333
|
const parseSuccessResponseBody = requestOptions.request?.parseSuccessResponseBody !== false;
|
|
184396
184334
|
const body = isPlainObject8(requestOptions.body) || Array.isArray(requestOptions.body) ? JSONStringify(requestOptions.body) : requestOptions.body;
|
|
184397
184335
|
const requestHeaders = Object.fromEntries(
|
|
@@ -184449,7 +184387,7 @@ async function fetchWrapper(requestOptions) {
|
|
|
184449
184387
|
if ("deprecation" in responseHeaders) {
|
|
184450
184388
|
const matches = responseHeaders.link && responseHeaders.link.match(/<([^<>]+)>; rel="deprecation"/);
|
|
184451
184389
|
const deprecationLink = matches && matches.pop();
|
|
184452
|
-
|
|
184390
|
+
log2.warn(
|
|
184453
184391
|
`[@octokit/request] "${requestOptions.method} ${requestOptions.url}" is deprecated. It is scheduled to be removed on ${responseHeaders.sunset}${deprecationLink ? `. See ${deprecationLink}` : ""}`
|
|
184454
184392
|
);
|
|
184455
184393
|
}
|
|
@@ -184587,9 +184525,9 @@ var NON_VARIABLE_OPTIONS = [
|
|
|
184587
184525
|
];
|
|
184588
184526
|
var FORBIDDEN_VARIABLE_OPTIONS = ["query", "method", "url"];
|
|
184589
184527
|
var GHES_V3_SUFFIX_REGEX = /\/api\/v3\/?$/;
|
|
184590
|
-
function graphql(request2,
|
|
184528
|
+
function graphql(request2, query2, options) {
|
|
184591
184529
|
if (options) {
|
|
184592
|
-
if (typeof
|
|
184530
|
+
if (typeof query2 === "string" && "query" in options) {
|
|
184593
184531
|
return Promise.reject(
|
|
184594
184532
|
new Error(`[@octokit/graphql] "query" cannot be used as variable name`)
|
|
184595
184533
|
);
|
|
@@ -184603,7 +184541,7 @@ function graphql(request2, query, options) {
|
|
|
184603
184541
|
);
|
|
184604
184542
|
}
|
|
184605
184543
|
}
|
|
184606
|
-
const parsedOptions = typeof
|
|
184544
|
+
const parsedOptions = typeof query2 === "string" ? Object.assign({ query: query2 }, options) : query2;
|
|
184607
184545
|
const requestOptions = Object.keys(
|
|
184608
184546
|
parsedOptions
|
|
184609
184547
|
).reduce((result, key) => {
|
|
@@ -184638,8 +184576,8 @@ function graphql(request2, query, options) {
|
|
|
184638
184576
|
}
|
|
184639
184577
|
function withDefaults3(request2, newDefaults) {
|
|
184640
184578
|
const newRequest2 = request2.defaults(newDefaults);
|
|
184641
|
-
const newApi = (
|
|
184642
|
-
return graphql(newRequest2,
|
|
184579
|
+
const newApi = (query2, options) => {
|
|
184580
|
+
return graphql(newRequest2, query2, options);
|
|
184643
184581
|
};
|
|
184644
184582
|
return Object.assign(newApi, {
|
|
184645
184583
|
defaults: withDefaults3.bind(null, newRequest2),
|
|
@@ -187483,16 +187421,17 @@ function translateIdTokenError(error49) {
|
|
|
187483
187421
|
if (!status) return error49;
|
|
187484
187422
|
return new TokenExchangeError(Number(status), error49.message);
|
|
187485
187423
|
}
|
|
187486
|
-
var mintIdToken =
|
|
187487
|
-
async () => {
|
|
187424
|
+
var mintIdToken = query({
|
|
187425
|
+
run: async () => {
|
|
187488
187426
|
try {
|
|
187489
187427
|
return await core4.getIDToken(OIDC_AUDIENCE);
|
|
187490
187428
|
} catch (error49) {
|
|
187491
187429
|
throw translateIdTokenError(error49);
|
|
187492
187430
|
}
|
|
187493
187431
|
},
|
|
187494
|
-
|
|
187495
|
-
|
|
187432
|
+
ttl: 6e4,
|
|
187433
|
+
name: "OIDC ID token"
|
|
187434
|
+
});
|
|
187496
187435
|
async function acquireTokenViaOIDC(opts) {
|
|
187497
187436
|
const oidcToken = opts?.oidc ? await fetchIdTokenFromStash(opts.oidc) : await mintIdToken();
|
|
187498
187437
|
const repos = [...opts?.repos ?? []];
|
|
@@ -187650,10 +187589,10 @@ function isTransientTokenError(error49) {
|
|
|
187650
187589
|
}
|
|
187651
187590
|
async function acquireNewToken(opts) {
|
|
187652
187591
|
if (opts?.oidc || isOIDCAvailable()) {
|
|
187653
|
-
return await
|
|
187592
|
+
return await mutation({
|
|
187593
|
+
run: () => acquireTokenViaOIDC(opts),
|
|
187654
187594
|
name: "token exchange",
|
|
187655
|
-
|
|
187656
|
-
rethrow: (error49) => !isTransientTokenError(error49)
|
|
187595
|
+
retry: (error49, attempt) => isTransientTokenError(error49) ? delay2([1e3, 2e3], attempt) : -1
|
|
187657
187596
|
})();
|
|
187658
187597
|
}
|
|
187659
187598
|
if (process.env.GITHUB_ACTIONS === "true") {
|
|
@@ -187696,7 +187635,7 @@ function getGitHubUsageSummary() {
|
|
|
187696
187635
|
}
|
|
187697
187636
|
async function writeGitHubUsageSummaryToFile(path4) {
|
|
187698
187637
|
const summary2 = getGitHubUsageSummary();
|
|
187699
|
-
const tmpPath =
|
|
187638
|
+
const tmpPath = join13(dirname3(path4), `.usage-summary-${process.pid}.tmp`);
|
|
187700
187639
|
await writeFile(tmpPath, JSON.stringify(summary2));
|
|
187701
187640
|
await rename(tmpPath, path4);
|
|
187702
187641
|
}
|
|
@@ -187987,19 +187926,19 @@ async function pushWithRetry(args2, token, refreshGitToken, cwd = process.cwd())
|
|
|
187987
187926
|
if ((kind === "transient" || kind === "transient-auth") && attempt < TRANSIENT_RETRY_DELAYS_MS.length) {
|
|
187988
187927
|
if (kind === "transient-auth" && refreshGitToken) {
|
|
187989
187928
|
currentToken = await refreshGitToken(currentToken);
|
|
187990
|
-
const
|
|
187929
|
+
const delay4 = Math.round(1e3 * (0.75 + Math.random() * 0.5));
|
|
187991
187930
|
log.info(
|
|
187992
|
-
`push attempt ${attempt + 1} failed (auth), re-minted token, retrying in ${
|
|
187931
|
+
`push attempt ${attempt + 1} failed (auth), re-minted token, retrying in ${delay4}ms: ${msg.slice(0, 300)}`
|
|
187993
187932
|
);
|
|
187994
|
-
await new Promise((r) => setTimeout(r,
|
|
187933
|
+
await new Promise((r) => setTimeout(r, delay4));
|
|
187995
187934
|
continue;
|
|
187996
187935
|
}
|
|
187997
187936
|
const baseDelay = TRANSIENT_RETRY_DELAYS_MS[attempt] ?? 5e3;
|
|
187998
|
-
const
|
|
187937
|
+
const delay3 = Math.round(baseDelay * (0.75 + Math.random() * 0.5));
|
|
187999
187938
|
log.info(
|
|
188000
|
-
`push attempt ${attempt + 1} failed (transient), retrying in ${
|
|
187939
|
+
`push attempt ${attempt + 1} failed (transient), retrying in ${delay3}ms: ${msg.slice(0, 300)}`
|
|
188001
187940
|
);
|
|
188002
|
-
await new Promise((r) => setTimeout(r,
|
|
187941
|
+
await new Promise((r) => setTimeout(r, delay3));
|
|
188003
187942
|
continue;
|
|
188004
187943
|
}
|
|
188005
187944
|
throw err;
|
|
@@ -188324,7 +188263,7 @@ function countAhead(head, base, cwd) {
|
|
|
188324
188263
|
function spillGitOutput(params) {
|
|
188325
188264
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
188326
188265
|
if (!tempDir) throw new Error("PULLFROG_TEMP_DIR not set");
|
|
188327
|
-
const outputPath =
|
|
188266
|
+
const outputPath = join14(tempDir, `git-${params.command}-${randomUUID4().slice(0, 8)}.txt`);
|
|
188328
188267
|
writeFileSync9(outputPath, params.output);
|
|
188329
188268
|
const previewByLines = params.output.split("\n").slice(0, OVERFLOW_PREVIEW_LINES).join("\n");
|
|
188330
188269
|
const preview = previewByLines.length <= OVERFLOW_PREVIEW_MAX_CHARS ? previewByLines : `${previewByLines.slice(0, OVERFLOW_PREVIEW_MAX_CHARS)}\u2026`;
|
|
@@ -188724,6 +188663,112 @@ function isTransientOctokitError(error49) {
|
|
|
188724
188663
|
return isTransientNetworkError(error49);
|
|
188725
188664
|
}
|
|
188726
188665
|
|
|
188666
|
+
// utils/runContext.ts
|
|
188667
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
188668
|
+
var START_KEY = randomUUID5();
|
|
188669
|
+
var defaultSettings = {
|
|
188670
|
+
model: null,
|
|
188671
|
+
effort: null,
|
|
188672
|
+
modes: [],
|
|
188673
|
+
setupScript: null,
|
|
188674
|
+
postCheckoutScript: null,
|
|
188675
|
+
prepushScript: null,
|
|
188676
|
+
stopScript: null,
|
|
188677
|
+
push: "restricted",
|
|
188678
|
+
shell: "restricted",
|
|
188679
|
+
prApproveEnabled: false,
|
|
188680
|
+
reviewDrafts: false,
|
|
188681
|
+
autoMergeEnabled: false,
|
|
188682
|
+
codexAgent: false,
|
|
188683
|
+
signedCommits: false,
|
|
188684
|
+
repoIntelligence: false,
|
|
188685
|
+
progressComments: true,
|
|
188686
|
+
statusChecks: true,
|
|
188687
|
+
approvalCheck: false,
|
|
188688
|
+
modeInstructions: {},
|
|
188689
|
+
learnings: null,
|
|
188690
|
+
learningsHeadings: [],
|
|
188691
|
+
envAllowlist: null,
|
|
188692
|
+
xrepoBrief: null,
|
|
188693
|
+
xrepoLearnings: null,
|
|
188694
|
+
xrepoLearningsHeadings: []
|
|
188695
|
+
};
|
|
188696
|
+
var defaultRunContext = {
|
|
188697
|
+
settings: defaultSettings,
|
|
188698
|
+
apiToken: "",
|
|
188699
|
+
oss: false,
|
|
188700
|
+
plan: "none"
|
|
188701
|
+
};
|
|
188702
|
+
var unknownSecretsRunContext = {
|
|
188703
|
+
...defaultRunContext,
|
|
188704
|
+
secretsUnavailable: true
|
|
188705
|
+
};
|
|
188706
|
+
async function fetchRunContext(params) {
|
|
188707
|
+
const timeoutMs = 3e4;
|
|
188708
|
+
const controller = new AbortController();
|
|
188709
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
188710
|
+
try {
|
|
188711
|
+
const headers = {
|
|
188712
|
+
Authorization: `Bearer ${params.token}`,
|
|
188713
|
+
"X-Pullfrog-Credential-Pools": "1"
|
|
188714
|
+
};
|
|
188715
|
+
if (params.oidcToken) {
|
|
188716
|
+
headers["X-GitHub-OIDC-Token"] = params.oidcToken;
|
|
188717
|
+
}
|
|
188718
|
+
const query2 = new URLSearchParams({ start: START_KEY });
|
|
188719
|
+
if (params.runType) query2.set("type", params.runType);
|
|
188720
|
+
if (params.plainPrompt) query2.set("prompt", "plain");
|
|
188721
|
+
if (params.routedTier) query2.set("tier", params.routedTier);
|
|
188722
|
+
const search2 = query2.toString();
|
|
188723
|
+
const response = await apiFetch({
|
|
188724
|
+
path: `/api/repo/${params.repoContext.owner}/${params.repoContext.name}/run-context${search2 ? `?${search2}` : ""}`,
|
|
188725
|
+
headers,
|
|
188726
|
+
signal: controller.signal
|
|
188727
|
+
});
|
|
188728
|
+
clearTimeout(timeoutId);
|
|
188729
|
+
if (response.status === 402) {
|
|
188730
|
+
const body = await response.json().catch(() => null);
|
|
188731
|
+
const reason = typeof body === "object" && body !== null && "reason" in body ? body.reason : null;
|
|
188732
|
+
const commercialRefused = reason === "subscription_unpaid" || reason === "subscription_ended" ? reason : "commercial";
|
|
188733
|
+
return { ...defaultRunContext, commercialRefused };
|
|
188734
|
+
}
|
|
188735
|
+
if (!response.ok) {
|
|
188736
|
+
return response.status >= 500 ? unknownSecretsRunContext : defaultRunContext;
|
|
188737
|
+
}
|
|
188738
|
+
const data = await response.json();
|
|
188739
|
+
if (data === null) {
|
|
188740
|
+
return defaultRunContext;
|
|
188741
|
+
}
|
|
188742
|
+
return {
|
|
188743
|
+
settings: {
|
|
188744
|
+
...defaultSettings,
|
|
188745
|
+
...data.settings,
|
|
188746
|
+
modes: data.settings?.modes ?? [],
|
|
188747
|
+
setupScript: data.settings?.setupScript ?? null,
|
|
188748
|
+
postCheckoutScript: data.settings?.postCheckoutScript ?? null,
|
|
188749
|
+
prepushScript: data.settings?.prepushScript ?? null,
|
|
188750
|
+
stopScript: data.settings?.stopScript ?? null,
|
|
188751
|
+
learningsHeadings: data.settings?.learningsHeadings ?? [],
|
|
188752
|
+
xrepoBrief: data.settings?.xrepoBrief ?? null,
|
|
188753
|
+
xrepoLearnings: data.settings?.xrepoLearnings ?? null,
|
|
188754
|
+
xrepoLearningsHeadings: data.settings?.xrepoLearningsHeadings ?? []
|
|
188755
|
+
},
|
|
188756
|
+
apiToken: data.apiToken,
|
|
188757
|
+
oss: data.oss ?? false,
|
|
188758
|
+
plan: data.plan ?? "none",
|
|
188759
|
+
proxyModel: data.proxyModel,
|
|
188760
|
+
dbSecrets: data.dbSecrets,
|
|
188761
|
+
credentialAccess: data.credentialAccess,
|
|
188762
|
+
secretsUnavailable: data.secretsUnavailable,
|
|
188763
|
+
routerUnfunded: data.routerUnfunded,
|
|
188764
|
+
trialFallback: data.trialFallback
|
|
188765
|
+
};
|
|
188766
|
+
} catch {
|
|
188767
|
+
clearTimeout(timeoutId);
|
|
188768
|
+
return unknownSecretsRunContext;
|
|
188769
|
+
}
|
|
188770
|
+
}
|
|
188771
|
+
|
|
188727
188772
|
// utils/patchWorkflowRunFields.ts
|
|
188728
188773
|
var STRING_KEYS = [
|
|
188729
188774
|
"prNodeId",
|
|
@@ -188742,6 +188787,7 @@ var NUMBER_KEYS = [
|
|
|
188742
188787
|
"cacheWriteTokens",
|
|
188743
188788
|
"costUsd"
|
|
188744
188789
|
];
|
|
188790
|
+
var FLAG_KEYS = ["reviewSkipped"];
|
|
188745
188791
|
async function patchWorkflowRunFields(ctx, fields) {
|
|
188746
188792
|
if (ctx.runId === void 0 || !ctx.apiToken) return;
|
|
188747
188793
|
if (ctx.toolState.workflowRunUnclaimed) return;
|
|
@@ -188758,10 +188804,17 @@ async function patchWorkflowRunFields(ctx, fields) {
|
|
|
188758
188804
|
body[key] = value2;
|
|
188759
188805
|
}
|
|
188760
188806
|
}
|
|
188807
|
+
for (const key of FLAG_KEYS) {
|
|
188808
|
+
if (fields[key]) body[key] = true;
|
|
188809
|
+
}
|
|
188810
|
+
if (fields.succeeded !== void 0) body.succeeded = fields.succeeded;
|
|
188761
188811
|
if (Object.keys(body).length === 0) return;
|
|
188812
|
+
body.startKey = START_KEY;
|
|
188813
|
+
const runAttempt = Number(process.env.GITHUB_RUN_ATTEMPT);
|
|
188814
|
+
if (Number.isInteger(runAttempt) && runAttempt >= 1) body.runAttempt = runAttempt;
|
|
188762
188815
|
try {
|
|
188763
|
-
await
|
|
188764
|
-
async () => {
|
|
188816
|
+
await mutation({
|
|
188817
|
+
run: async () => {
|
|
188765
188818
|
const response = await apiFetch({
|
|
188766
188819
|
path: `/api/workflow-run/${ctx.runId}`,
|
|
188767
188820
|
method: "PATCH",
|
|
@@ -188772,17 +188825,18 @@ async function patchWorkflowRunFields(ctx, fields) {
|
|
|
188772
188825
|
body: JSON.stringify(body),
|
|
188773
188826
|
signal: AbortSignal.timeout(1e4)
|
|
188774
188827
|
});
|
|
188775
|
-
if (response.status === 404)
|
|
188828
|
+
if (response.status === 404) {
|
|
188829
|
+
ctx.toolState.workflowRunUnclaimed = true;
|
|
188830
|
+
log.info(`\xBB Pullfrog has no record of run ${ctx.runId}; skipping run metadata updates`);
|
|
188831
|
+
return;
|
|
188832
|
+
}
|
|
188776
188833
|
if (!response.ok) throw new Error(`PATCH workflow-run: ${response.status}`);
|
|
188777
188834
|
},
|
|
188778
|
-
|
|
188779
|
-
|
|
188780
|
-
|
|
188781
|
-
|
|
188782
|
-
|
|
188783
|
-
rethrow: (error49) => !isTransientNetworkError(error49)
|
|
188784
|
-
}
|
|
188785
|
-
)();
|
|
188835
|
+
// only retry transient network errors; explicit HTTP failures throw
|
|
188836
|
+
// a status-bearing message and should fail fast.
|
|
188837
|
+
retry: (error49, attempt) => isTransientNetworkError(error49) ? delay2([2e3, 4e3], attempt) : -1,
|
|
188838
|
+
name: "patchWorkflowRunFields"
|
|
188839
|
+
})();
|
|
188786
188840
|
} catch (error49) {
|
|
188787
188841
|
log.warning(`patchWorkflowRunFields failed: ${error49}`);
|
|
188788
188842
|
}
|
|
@@ -188955,6 +189009,9 @@ var ReportProgress = type({
|
|
|
188955
189009
|
body: type.string.describe("the progress update content to share"),
|
|
188956
189010
|
"target_plan_comment?": type("boolean").describe(
|
|
188957
189011
|
"for revising an existing plan comment ONLY. set to true only when the PlanEdit checklist from select_mode tells you to (i.e. a prior plan comment was found for this issue). NEVER set on the initial plan post \u2014 the initial plan reuses the run's progress comment and is posted by calling report_progress without this flag."
|
|
189012
|
+
),
|
|
189013
|
+
"no_review_needed?": type("boolean").describe(
|
|
189014
|
+
"IncrementalReview only: true when you judged the new commits need no review, never for a blocker."
|
|
188958
189015
|
)
|
|
188959
189016
|
});
|
|
188960
189017
|
async function reportProgress(ctx, params) {
|
|
@@ -189082,6 +189139,9 @@ function ReportProgressTool(ctx) {
|
|
|
189082
189139
|
description: 'Share progress on the associated GitHub issue/PR. The first call creates a comment; subsequent calls update it in place. Example: `report_progress({ body: "Implemented the auth check and added tests." })`. Call this at the end of every run with a brief final summary (1-3 sentences) unless the mode guidance instructs otherwise. The current task list is automatically appended in a collapsible section \u2014 do not restate individual steps.',
|
|
189083
189140
|
parameters: ReportProgress,
|
|
189084
189141
|
execute: execute(async (params) => {
|
|
189142
|
+
if (params.no_review_needed) {
|
|
189143
|
+
ctx.toolState.noReviewNeededSha = primaryRepoState(ctx.toolState).checkoutSha;
|
|
189144
|
+
}
|
|
189085
189145
|
if (ctx.toolState.standaloneCommentId !== void 0 && !params.target_plan_comment) {
|
|
189086
189146
|
ctx.toolState.lastProgressBody = params.body;
|
|
189087
189147
|
return {
|
|
@@ -189613,18 +189673,15 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
189613
189673
|
}
|
|
189614
189674
|
let result;
|
|
189615
189675
|
try {
|
|
189616
|
-
result = await
|
|
189617
|
-
() => body ? createAndSubmitWithFooter(ctx, params, {
|
|
189676
|
+
result = await mutation({
|
|
189677
|
+
run: () => body ? createAndSubmitWithFooter(ctx, params, {
|
|
189618
189678
|
body,
|
|
189619
189679
|
approved: approved ?? false,
|
|
189620
189680
|
hasComments: (params.comments?.length ?? 0) > 0
|
|
189621
189681
|
}) : createReviewWithStrandedRecovery(ctx, params),
|
|
189622
|
-
|
|
189623
|
-
|
|
189624
|
-
|
|
189625
|
-
name: "review submission"
|
|
189626
|
-
}
|
|
189627
|
-
)();
|
|
189682
|
+
retry: (error49, attempt) => isTransientReviewError(error49) ? delay2(TRANSIENT_REVIEW_RETRY_DELAYS_MS, attempt) : -1,
|
|
189683
|
+
name: "review submission"
|
|
189684
|
+
})();
|
|
189628
189685
|
} catch (err) {
|
|
189629
189686
|
if (ctx.toolState.approval) ctx.toolState.approval.wouldApprove = false;
|
|
189630
189687
|
if (isTransientReviewError(err)) {
|
|
@@ -189861,11 +189918,11 @@ async function reportReviewNodeId(ctx, params) {
|
|
|
189861
189918
|
|
|
189862
189919
|
// utils/setup.ts
|
|
189863
189920
|
import { execFileSync as execFileSync6, execSync as execSync2 } from "node:child_process";
|
|
189864
|
-
import { mkdtempSync, readdirSync, realpathSync as realpathSync2, rmSync as rmSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
189921
|
+
import { mkdtempSync as mkdtempSync2, readdirSync, realpathSync as realpathSync2, rmSync as rmSync2, unlinkSync as unlinkSync2 } from "node:fs";
|
|
189865
189922
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
189866
|
-
import { join as
|
|
189923
|
+
import { join as join15 } from "node:path";
|
|
189867
189924
|
function createTempDirectory() {
|
|
189868
|
-
const path4 =
|
|
189925
|
+
const path4 = mkdtempSync2(join15(tmpdir2(), "pullfrog-"));
|
|
189869
189926
|
process.env.PULLFROG_TEMP_DIR = path4;
|
|
189870
189927
|
log.info(`\xBB created temp dir at ${path4}`);
|
|
189871
189928
|
return { path: path4, [Symbol.dispose]: () => removeTempDirectory(path4) };
|
|
@@ -189925,13 +189982,13 @@ function wipeRunnerLeakSurface() {
|
|
|
189925
189982
|
return [];
|
|
189926
189983
|
}
|
|
189927
189984
|
};
|
|
189928
|
-
const fileCommandsDir =
|
|
189985
|
+
const fileCommandsDir = join15(runnerTemp, "_runner_file_commands");
|
|
189929
189986
|
for (const entry of listDir(fileCommandsDir)) {
|
|
189930
|
-
tryUnlink(
|
|
189987
|
+
tryUnlink(join15(fileCommandsDir, entry));
|
|
189931
189988
|
}
|
|
189932
189989
|
for (const entry of listDir(runnerTemp)) {
|
|
189933
189990
|
if (entry.endsWith(".sh") || /^git-credentials-.*\.config$/.test(entry)) {
|
|
189934
|
-
tryUnlink(
|
|
189991
|
+
tryUnlink(join15(runnerTemp, entry));
|
|
189935
189992
|
}
|
|
189936
189993
|
}
|
|
189937
189994
|
if (wiped.length > 0) {
|
|
@@ -190203,7 +190260,7 @@ async function ensureBeforeShaReachable(params) {
|
|
|
190203
190260
|
"origin",
|
|
190204
190261
|
tempBranch
|
|
190205
190262
|
],
|
|
190206
|
-
{ token: params.gitToken, refreshGitToken: params.refreshGitToken },
|
|
190263
|
+
{ token: params.gitToken, refreshGitToken: params.refreshGitToken, signal: params.signal },
|
|
190207
190264
|
`before_sha temp branch ${tempBranch}`
|
|
190208
190265
|
);
|
|
190209
190266
|
log.debug(`\xBB fetched before_sha via temp branch ${tempBranch}`);
|
|
@@ -190244,7 +190301,7 @@ function cleanupStaleGitLocks() {
|
|
|
190244
190301
|
} catch {
|
|
190245
190302
|
continue;
|
|
190246
190303
|
}
|
|
190247
|
-
if (now - mtimeMs < STALE_LOCK_AGE_MS) continue;
|
|
190304
|
+
if (now - mtimeMs < STALE_LOCK_AGE_MS || mtimeMs >= performance.timeOrigin) continue;
|
|
190248
190305
|
try {
|
|
190249
190306
|
unlinkSync3(relPath);
|
|
190250
190307
|
log.warning(`\xBB removed stale ${relPath} from prior run`);
|
|
@@ -190277,7 +190334,7 @@ async function abortIfPullRequestMoved(args2) {
|
|
|
190277
190334
|
);
|
|
190278
190335
|
}
|
|
190279
190336
|
async function checkoutPrBranch(pr, params) {
|
|
190280
|
-
const { octokit, owner, name, gitToken, refreshGitToken, toolState, beforeSha } = params;
|
|
190337
|
+
const { octokit, owner, name, gitToken, refreshGitToken, toolState, beforeSha, signal } = params;
|
|
190281
190338
|
rejectIfLeadingDash(pr.baseRef, "PR base ref");
|
|
190282
190339
|
rejectIfLeadingDash(pr.headRef, "PR head ref");
|
|
190283
190340
|
const repoState = requireRepoState(toolState, owner, name);
|
|
@@ -190291,18 +190348,18 @@ async function checkoutPrBranch(pr, params) {
|
|
|
190291
190348
|
log.debug(`\xBB fetching base branch (${pr.baseRef})...`);
|
|
190292
190349
|
await $gitFetchWithDeepen(
|
|
190293
190350
|
["--no-tags", "origin", pr.baseRef],
|
|
190294
|
-
{ token: gitToken, refreshGitToken },
|
|
190351
|
+
{ token: gitToken, refreshGitToken, signal },
|
|
190295
190352
|
`base branch ${pr.baseRef}`
|
|
190296
190353
|
);
|
|
190297
190354
|
if (!alreadyOnBranch) {
|
|
190298
190355
|
$("git", ["checkout", "-B", pr.baseRef, `origin/${pr.baseRef}`], { log: false });
|
|
190299
190356
|
log.debug(`\xBB fetching PR #${pr.number} (${localBranch})...`);
|
|
190300
|
-
await
|
|
190301
|
-
async () => {
|
|
190357
|
+
await mutation({
|
|
190358
|
+
run: async () => {
|
|
190302
190359
|
try {
|
|
190303
190360
|
await $gitFetchWithDeepen(
|
|
190304
190361
|
["--no-tags", "origin", `+pull/${pr.number}/head:${localBranch}`],
|
|
190305
|
-
{ token: gitToken, refreshGitToken },
|
|
190362
|
+
{ token: gitToken, refreshGitToken, signal },
|
|
190306
190363
|
`PR #${pr.number}`
|
|
190307
190364
|
);
|
|
190308
190365
|
} catch (e) {
|
|
@@ -190313,12 +190370,9 @@ async function checkoutPrBranch(pr, params) {
|
|
|
190313
190370
|
throw e;
|
|
190314
190371
|
}
|
|
190315
190372
|
},
|
|
190316
|
-
|
|
190317
|
-
|
|
190318
|
-
|
|
190319
|
-
rethrow: (e) => !PULL_REF_MISSING_PATTERN.test(e instanceof Error ? e.message : String(e))
|
|
190320
|
-
}
|
|
190321
|
-
)();
|
|
190373
|
+
retry: (error49, attempt) => PULL_REF_MISSING_PATTERN.test(error49 instanceof Error ? error49.message : String(error49)) ? delay2(PULL_REF_RETRY_DELAYS_MS, attempt) : -1,
|
|
190374
|
+
name: `pull/${pr.number}/head fetch`
|
|
190375
|
+
})();
|
|
190322
190376
|
$("git", ["checkout", localBranch], { log: false });
|
|
190323
190377
|
log.debug(`\xBB checked out PR #${pr.number}`);
|
|
190324
190378
|
repoState.checkoutSha = $("git", ["rev-parse", "HEAD"], { log: false }).trim();
|
|
@@ -190330,7 +190384,8 @@ async function checkoutPrBranch(pr, params) {
|
|
|
190330
190384
|
repo: name,
|
|
190331
190385
|
gitToken,
|
|
190332
190386
|
refreshGitToken,
|
|
190333
|
-
isShallow
|
|
190387
|
+
isShallow,
|
|
190388
|
+
signal
|
|
190334
190389
|
}) : false;
|
|
190335
190390
|
if (isShallow) {
|
|
190336
190391
|
let deepenDepth = 0;
|
|
@@ -190365,7 +190420,8 @@ async function checkoutPrBranch(pr, params) {
|
|
|
190365
190420
|
if (deepenDepth) {
|
|
190366
190421
|
log.debug(`\xBB deepening by ${deepenDepth} to reach merge base...`);
|
|
190367
190422
|
await $git("fetch", [`--deepen=${deepenDepth}`, "--no-tags", "origin"], {
|
|
190368
|
-
token: gitToken
|
|
190423
|
+
token: gitToken,
|
|
190424
|
+
signal
|
|
190369
190425
|
});
|
|
190370
190426
|
}
|
|
190371
190427
|
}
|
|
@@ -190403,6 +190459,7 @@ async function checkoutPrBranch(pr, params) {
|
|
|
190403
190459
|
remoteBranch: pr.headRef,
|
|
190404
190460
|
localBranch
|
|
190405
190461
|
};
|
|
190462
|
+
signal.throwIfAborted();
|
|
190406
190463
|
const postCheckoutHook = await executeLifecycleHook({
|
|
190407
190464
|
event: "post-checkout",
|
|
190408
190465
|
script: params.postCheckoutScript,
|
|
@@ -190413,19 +190470,30 @@ async function checkoutPrBranch(pr, params) {
|
|
|
190413
190470
|
}
|
|
190414
190471
|
var inFlightCheckouts = /* @__PURE__ */ new Map();
|
|
190415
190472
|
var CHECKOUT_DEADLINE_MS = 57e4;
|
|
190416
|
-
|
|
190417
|
-
|
|
190418
|
-
const
|
|
190419
|
-
|
|
190473
|
+
var CHECKOUT_ABORT_GRACE_MS = 15e3;
|
|
190474
|
+
function withCheckoutDeadline(run, pullNumber) {
|
|
190475
|
+
const exceeded = `checkout_pr #${pullNumber} exceeded ${CHECKOUT_DEADLINE_MS / 1e3}s`;
|
|
190476
|
+
const retry = "retry the call to start a fresh attempt.";
|
|
190477
|
+
const controller = new AbortController();
|
|
190478
|
+
const abortTimer = setTimeout(
|
|
190479
|
+
() => controller.abort(new Error(`${exceeded} and was cancelled; ${retry}`)),
|
|
190480
|
+
CHECKOUT_DEADLINE_MS
|
|
190481
|
+
);
|
|
190482
|
+
let backstopTimer;
|
|
190483
|
+
const backstop = new Promise((_, reject) => {
|
|
190484
|
+
backstopTimer = setTimeout(
|
|
190420
190485
|
() => reject(
|
|
190421
190486
|
new Error(
|
|
190422
|
-
|
|
190487
|
+
`${exceeded} and was asked to cancel, but a step that cannot be interrupted (the post-checkout hook or a GitHub API call) was still running ${CHECKOUT_ABORT_GRACE_MS / 1e3}s later. ${retry}`
|
|
190423
190488
|
)
|
|
190424
190489
|
),
|
|
190425
|
-
CHECKOUT_DEADLINE_MS
|
|
190490
|
+
CHECKOUT_DEADLINE_MS + CHECKOUT_ABORT_GRACE_MS
|
|
190426
190491
|
);
|
|
190427
190492
|
});
|
|
190428
|
-
return Promise.race([
|
|
190493
|
+
return Promise.race([run(controller.signal), backstop]).finally(() => {
|
|
190494
|
+
clearTimeout(abortTimer);
|
|
190495
|
+
clearTimeout(backstopTimer);
|
|
190496
|
+
});
|
|
190429
190497
|
}
|
|
190430
190498
|
function headsEqual(a, b) {
|
|
190431
190499
|
if (a.kind === "branch" && b.kind === "branch") return a.name === b.name;
|
|
@@ -190437,7 +190505,7 @@ function describeHead(h) {
|
|
|
190437
190505
|
return `detached HEAD \`${h.sha}\``;
|
|
190438
190506
|
}
|
|
190439
190507
|
function CheckoutPrTool(ctx) {
|
|
190440
|
-
const runCheckout = async (pull_number) => {
|
|
190508
|
+
const runCheckout = async (pull_number, signal) => {
|
|
190441
190509
|
const prResponse = await ctx.octokit.rest.pulls.get({
|
|
190442
190510
|
owner: ctx.repo.owner,
|
|
190443
190511
|
repo: ctx.repo.name,
|
|
@@ -190466,7 +190534,8 @@ function CheckoutPrTool(ctx) {
|
|
|
190466
190534
|
toolState: ctx.toolState,
|
|
190467
190535
|
shell: ctx.payload.shell,
|
|
190468
190536
|
postCheckoutScript: ctx.postCheckoutScript,
|
|
190469
|
-
beforeSha: primary.beforeSha
|
|
190537
|
+
beforeSha: primary.beforeSha,
|
|
190538
|
+
signal
|
|
190470
190539
|
});
|
|
190471
190540
|
const tempDir = process.env.PULLFROG_TEMP_DIR;
|
|
190472
190541
|
if (!tempDir) {
|
|
@@ -190488,7 +190557,7 @@ function CheckoutPrTool(ctx) {
|
|
|
190488
190557
|
headSha: checkoutSha
|
|
190489
190558
|
});
|
|
190490
190559
|
if (incremental.status === "ok") {
|
|
190491
|
-
incrementalDiffPath =
|
|
190560
|
+
incrementalDiffPath = join16(
|
|
190492
190561
|
tempDir,
|
|
190493
190562
|
`pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
|
|
190494
190563
|
);
|
|
@@ -190505,7 +190574,7 @@ function CheckoutPrTool(ctx) {
|
|
|
190505
190574
|
const diffPreview = formatResult.content.split("\n").slice(0, 100).join("\n");
|
|
190506
190575
|
log.debug(`formatted diff preview (first 100 lines):
|
|
190507
190576
|
${diffPreview}`);
|
|
190508
|
-
const diffPath =
|
|
190577
|
+
const diffPath = join16(tempDir, `pr-${pull_number}-${headShort}.diff`);
|
|
190509
190578
|
writeFileSync10(diffPath, formatResult.content);
|
|
190510
190579
|
log.debug(`wrote diff to ${diffPath} (${formatResult.content.length} bytes)`);
|
|
190511
190580
|
primary.diffCoverage = createDiffCoverageState({
|
|
@@ -190545,7 +190614,8 @@ ${diffPreview}`);
|
|
|
190545
190614
|
files: formatResult.files,
|
|
190546
190615
|
pullNumber: pull_number,
|
|
190547
190616
|
baseSha: prResponse.data.base.sha,
|
|
190548
|
-
headSha: checkoutSha
|
|
190617
|
+
headSha: checkoutSha,
|
|
190618
|
+
signal
|
|
190549
190619
|
});
|
|
190550
190620
|
impactPath = impact.path;
|
|
190551
190621
|
log.info(
|
|
@@ -190651,7 +190721,10 @@ ${dirty}`
|
|
|
190651
190721
|
);
|
|
190652
190722
|
}
|
|
190653
190723
|
}
|
|
190654
|
-
const promise2 = withCheckoutDeadline(
|
|
190724
|
+
const promise2 = withCheckoutDeadline(
|
|
190725
|
+
(signal) => runCheckout(pull_number, signal),
|
|
190726
|
+
pull_number
|
|
190727
|
+
);
|
|
190655
190728
|
inFlightCheckouts.set(pull_number, promise2);
|
|
190656
190729
|
try {
|
|
190657
190730
|
return await promise2;
|
|
@@ -190664,7 +190737,7 @@ ${dirty}`
|
|
|
190664
190737
|
|
|
190665
190738
|
// mcp/checkSuite.ts
|
|
190666
190739
|
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync11 } from "node:fs";
|
|
190667
|
-
import { join as
|
|
190740
|
+
import { join as join17 } from "node:path";
|
|
190668
190741
|
var GetCheckSuiteLogs = type({
|
|
190669
190742
|
check_suite_id: type.number.describe("the id from check_suite.id")
|
|
190670
190743
|
});
|
|
@@ -190760,7 +190833,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190760
190833
|
if (!tempDir) {
|
|
190761
190834
|
throw new Error("PULLFROG_TEMP_DIR not set");
|
|
190762
190835
|
}
|
|
190763
|
-
const logsDir =
|
|
190836
|
+
const logsDir = join17(tempDir, "ci-logs");
|
|
190764
190837
|
mkdirSync8(logsDir, { recursive: true });
|
|
190765
190838
|
const jobResults = [];
|
|
190766
190839
|
for (const run of failedRuns) {
|
|
@@ -190787,7 +190860,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190787
190860
|
);
|
|
190788
190861
|
}
|
|
190789
190862
|
const logsText = await logsResult.text();
|
|
190790
|
-
const logPath =
|
|
190863
|
+
const logPath = join17(logsDir, `job-${job.id}.log`);
|
|
190791
190864
|
writeFileSync11(logPath, logsText);
|
|
190792
190865
|
const analysis = analyzeLog(logsText, 80);
|
|
190793
190866
|
const failedSteps = job.steps?.filter((s) => s.conclusion === "failure").map((s) => `Step ${s.number}: ${s.name}`) ?? [];
|
|
@@ -190837,7 +190910,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
190837
190910
|
|
|
190838
190911
|
// mcp/commitInfo.ts
|
|
190839
190912
|
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
190840
|
-
import { join as
|
|
190913
|
+
import { join as join18 } from "node:path";
|
|
190841
190914
|
var CommitInfo = type({
|
|
190842
190915
|
sha: type.string.describe("the commit SHA (full or abbreviated) to fetch")
|
|
190843
190916
|
});
|
|
@@ -190861,7 +190934,7 @@ function CommitInfoTool(ctx) {
|
|
|
190861
190934
|
"PULLFROG_TEMP_DIR not set - get_commit_info must run in pullfrog action context"
|
|
190862
190935
|
);
|
|
190863
190936
|
}
|
|
190864
|
-
const diffFile =
|
|
190937
|
+
const diffFile = join18(tempDir, `commit-${sha.slice(0, 7)}.diff`);
|
|
190865
190938
|
writeFileSync12(diffFile, formatResult.content);
|
|
190866
190939
|
log.debug(`wrote commit diff to ${diffFile} (${formatResult.content.length} bytes)`);
|
|
190867
190940
|
return {
|
|
@@ -190998,14 +191071,14 @@ function ReopenCurrentTool(ctx) {
|
|
|
190998
191071
|
import { performance as performance8 } from "node:perf_hooks";
|
|
190999
191072
|
|
|
191000
191073
|
// prep/installNodeDependencies.ts
|
|
191001
|
-
import { existsSync as
|
|
191002
|
-
import { join as
|
|
191074
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
191075
|
+
import { join as join20 } from "node:path";
|
|
191003
191076
|
|
|
191004
191077
|
// utils/packageManager.ts
|
|
191005
191078
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
191006
|
-
import { existsSync as
|
|
191079
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
191007
191080
|
import { mkdir, readFile as readFile2 } from "node:fs/promises";
|
|
191008
|
-
import { delimiter, join as
|
|
191081
|
+
import { delimiter, join as join19 } from "node:path";
|
|
191009
191082
|
var SUPPORTED_NAMES = ["npm", "pnpm", "yarn", "bun"];
|
|
191010
191083
|
var COREPACK_MANAGED = ["pnpm", "yarn"];
|
|
191011
191084
|
function isSupported(name) {
|
|
@@ -191043,8 +191116,8 @@ function parseDevEnginesField(field) {
|
|
|
191043
191116
|
};
|
|
191044
191117
|
}
|
|
191045
191118
|
async function resolvePackageManagerSpec(cwd) {
|
|
191046
|
-
const pkgPath =
|
|
191047
|
-
if (!
|
|
191119
|
+
const pkgPath = join19(cwd, "package.json");
|
|
191120
|
+
if (!existsSync8(pkgPath)) return null;
|
|
191048
191121
|
let pkg;
|
|
191049
191122
|
try {
|
|
191050
191123
|
pkg = JSON.parse(await readFile2(pkgPath, "utf-8"));
|
|
@@ -191102,7 +191175,7 @@ async function currentVersion(name) {
|
|
|
191102
191175
|
return result.stdout.trim();
|
|
191103
191176
|
}
|
|
191104
191177
|
function packageManagerBinDir(tmpdir3) {
|
|
191105
|
-
return
|
|
191178
|
+
return join19(tmpdir3, "pm-bin");
|
|
191106
191179
|
}
|
|
191107
191180
|
async function ensurePackageManager(params) {
|
|
191108
191181
|
const spec = params.spec;
|
|
@@ -191165,7 +191238,7 @@ async function installFallback(name, installSpec) {
|
|
|
191165
191238
|
});
|
|
191166
191239
|
if (result.exitCode !== 0) return result.stderr || `failed to install ${name}`;
|
|
191167
191240
|
if (name === "deno") {
|
|
191168
|
-
const denoPath =
|
|
191241
|
+
const denoPath = join19(process.env.HOME || "", ".deno", "bin");
|
|
191169
191242
|
process.env.PATH = `${denoPath}:${process.env.PATH}`;
|
|
191170
191243
|
}
|
|
191171
191244
|
log.info(`\xBB installed ${name}`);
|
|
@@ -191198,8 +191271,8 @@ async function isCommandAvailable2(command) {
|
|
|
191198
191271
|
var installNodeDependencies = {
|
|
191199
191272
|
name: "installNodeDependencies",
|
|
191200
191273
|
shouldRun: () => {
|
|
191201
|
-
const packageJsonPath =
|
|
191202
|
-
return
|
|
191274
|
+
const packageJsonPath = join20(process.cwd(), "package.json");
|
|
191275
|
+
return existsSync9(packageJsonPath);
|
|
191203
191276
|
},
|
|
191204
191277
|
run: async (options) => {
|
|
191205
191278
|
const declared = await resolvePackageManagerSpec(process.cwd());
|
|
@@ -191293,14 +191366,14 @@ ${errorMessage}`]
|
|
|
191293
191366
|
};
|
|
191294
191367
|
|
|
191295
191368
|
// prep/installPythonDependencies.ts
|
|
191296
|
-
import { existsSync as
|
|
191297
|
-
import { join as
|
|
191369
|
+
import { existsSync as existsSync10, readFileSync as readFileSync5 } from "node:fs";
|
|
191370
|
+
import { join as join21 } from "node:path";
|
|
191298
191371
|
function declaresBuildSystem(path4) {
|
|
191299
191372
|
return /^\s*\[\s*build-system\s*\]/m.test(readFileSync5(path4, "utf8"));
|
|
191300
191373
|
}
|
|
191301
191374
|
function configApplies(config3, cwd) {
|
|
191302
|
-
const path4 =
|
|
191303
|
-
return
|
|
191375
|
+
const path4 = join21(cwd, config3.file);
|
|
191376
|
+
return existsSync10(path4) && (config3.applies?.(path4) ?? true);
|
|
191304
191377
|
}
|
|
191305
191378
|
var PYTHON_CONFIGS = [
|
|
191306
191379
|
{
|
|
@@ -191622,7 +191695,7 @@ function AwaitDependencyInstallationTool(ctx) {
|
|
|
191622
191695
|
|
|
191623
191696
|
// mcp/gh.ts
|
|
191624
191697
|
import { mkdirSync as mkdirSync9 } from "node:fs";
|
|
191625
|
-
import { join as
|
|
191698
|
+
import { join as join22 } from "node:path";
|
|
191626
191699
|
var GH_TIMEOUT_MS = 12e4;
|
|
191627
191700
|
var GhParams = type({
|
|
191628
191701
|
args: type.string.array().describe(
|
|
@@ -191644,7 +191717,7 @@ function GhTool(ctx) {
|
|
|
191644
191717
|
description: `Run the GitHub CLI against ${ctx.repo.owner}/${ctx.repo.name}. Pass argv as an array \u2014 there is no shell, so pipes, redirects and \`&&\` do not work; use gh's own \`--json\`/\`--jq\` flags instead. \`gh api graphql\` is available. Authenticated with ${permissions ? formatPermissions(permissions) : "no permissions"} on this repo only; anything else 403s. Pushing, merging and ref writes are not available \u2014 use the git tools.`,
|
|
191645
191718
|
parameters: GhParams,
|
|
191646
191719
|
execute: execute(async (params) => {
|
|
191647
|
-
const configDir =
|
|
191720
|
+
const configDir = join22(ctx.tmpdir, "gh-config");
|
|
191648
191721
|
mkdirSync9(configDir, { recursive: true });
|
|
191649
191722
|
const command = ["gh", ...params.args.map(shellQuote)].join(" ");
|
|
191650
191723
|
const result = await runSandboxed({
|
|
@@ -192368,7 +192441,7 @@ function PullRequestInfoTool(ctx) {
|
|
|
192368
192441
|
|
|
192369
192442
|
// mcp/reviewComments.ts
|
|
192370
192443
|
import { writeFileSync as writeFileSync13 } from "node:fs";
|
|
192371
|
-
import { join as
|
|
192444
|
+
import { join as join23 } from "node:path";
|
|
192372
192445
|
var COMMENTS_PER_THREAD = 50;
|
|
192373
192446
|
var REVIEW_THREADS_QUERY = `
|
|
192374
192447
|
query ($owner: String!, $name: String!, $prNumber: Int!, $cursor: String) {
|
|
@@ -192664,8 +192737,8 @@ function buildThreadBlocks(threads, filePatchMap, reviewId) {
|
|
|
192664
192737
|
}
|
|
192665
192738
|
return threadBlocks;
|
|
192666
192739
|
}
|
|
192667
|
-
var fetchAllReviewThreads =
|
|
192668
|
-
async (key, ctx) => {
|
|
192740
|
+
var fetchAllReviewThreads = query({
|
|
192741
|
+
run: async (key, ctx) => {
|
|
192669
192742
|
const threads = [];
|
|
192670
192743
|
let cursor = null;
|
|
192671
192744
|
for (let page = 0; page < 50; page += 1) {
|
|
@@ -192682,21 +192755,21 @@ var fetchAllReviewThreads = op(
|
|
|
192682
192755
|
}
|
|
192683
192756
|
return threads;
|
|
192684
192757
|
},
|
|
192685
|
-
|
|
192686
|
-
|
|
192687
|
-
|
|
192688
|
-
|
|
192758
|
+
ttl: 6e4,
|
|
192759
|
+
name: "reviewThreads"
|
|
192760
|
+
});
|
|
192761
|
+
var fetchPrFiles = query({
|
|
192762
|
+
run: async (key, ctx) => ctx.octokit.paginate(ctx.octokit.rest.pulls.listFiles, {
|
|
192689
192763
|
owner: key.owner,
|
|
192690
192764
|
repo: key.name,
|
|
192691
192765
|
pull_number: key.pullNumber,
|
|
192692
192766
|
per_page: 100
|
|
192693
192767
|
}),
|
|
192694
|
-
|
|
192695
|
-
|
|
192768
|
+
ttl: 6e4,
|
|
192769
|
+
name: "prFiles"
|
|
192770
|
+
});
|
|
192696
192771
|
function invalidateReviewThreadCache(repo) {
|
|
192697
|
-
fetchAllReviewThreads.invalidate(
|
|
192698
|
-
(cached4) => cached4.owner === repo.owner && cached4.name === repo.name
|
|
192699
|
-
);
|
|
192772
|
+
fetchAllReviewThreads.invalidate({ owner: repo.owner, name: repo.name });
|
|
192700
192773
|
}
|
|
192701
192774
|
async function getReviewThreads(input) {
|
|
192702
192775
|
const allThreads = structuredClone(
|
|
@@ -192862,7 +192935,7 @@ function GetReviewCommentsTool(ctx) {
|
|
|
192862
192935
|
throw new Error("PULLFROG_TEMP_DIR not set");
|
|
192863
192936
|
}
|
|
192864
192937
|
const filename = `review-${params.review_id}-threads.md`;
|
|
192865
|
-
const commentsPath =
|
|
192938
|
+
const commentsPath = join23(tempDir, filename);
|
|
192866
192939
|
writeFileSync13(commentsPath, formatted.content);
|
|
192867
192940
|
log.debug(`wrote ${threadBlocks.length} threads to ${commentsPath}`);
|
|
192868
192941
|
return {
|
|
@@ -193232,7 +193305,7 @@ function UploadFileTool(ctx) {
|
|
|
193232
193305
|
|
|
193233
193306
|
// mcp/xrepo.ts
|
|
193234
193307
|
import { mkdirSync as mkdirSync10, rmSync as rmSync3 } from "node:fs";
|
|
193235
|
-
import { join as
|
|
193308
|
+
import { join as join24 } from "node:path";
|
|
193236
193309
|
function assertValidRepoName(name) {
|
|
193237
193310
|
if (!/^[A-Za-z0-9._-]+$/.test(name) || name.startsWith("-") || name.includes("..")) {
|
|
193238
193311
|
throw new Error(
|
|
@@ -193312,7 +193385,7 @@ function CheckoutRepoTool(ctx) {
|
|
|
193312
193385
|
return { path: existing.dir, access: existing.access, note: "already checked out." };
|
|
193313
193386
|
}
|
|
193314
193387
|
const access = accessFor(ctx, repo);
|
|
193315
|
-
const dir =
|
|
193388
|
+
const dir = join24(ctx.tmpdir, "xrepo", repo);
|
|
193316
193389
|
mkdirSync10(dir, { recursive: true });
|
|
193317
193390
|
const state = ensureRepoState(ctx.toolState, { owner, name: repo, dir, access });
|
|
193318
193391
|
const rc = resolveRepoCtx(ctx, repo);
|
|
@@ -193423,7 +193496,7 @@ function buildCommonTools(ctx, outputSchema) {
|
|
|
193423
193496
|
if (isStandalone || outputSchema) {
|
|
193424
193497
|
tools.push(SetOutputTool(ctx, outputSchema));
|
|
193425
193498
|
}
|
|
193426
|
-
if (ctx.payload.shell
|
|
193499
|
+
if (ctx.payload.shell !== "disabled") {
|
|
193427
193500
|
tools.push(ShellTool(ctx));
|
|
193428
193501
|
tools.push(KillBackgroundTool(ctx));
|
|
193429
193502
|
}
|
|
@@ -193678,6 +193751,7 @@ function isByokSetupError(text) {
|
|
|
193678
193751
|
var SECRETS_UNAVAILABLE_MARKER = "couldn't load your Pullfrog secrets";
|
|
193679
193752
|
var ROUTER_UNFUNDED_MARKER = "your Pullfrog Router balance is empty";
|
|
193680
193753
|
var CREDENTIAL_REJECTED_MARKER = "was rejected by its provider";
|
|
193754
|
+
var CREDENTIAL_POOL_REFUSED_MARKER = "No configured credential can serve this run";
|
|
193681
193755
|
var NoUsableCredentialError = class extends Error {
|
|
193682
193756
|
};
|
|
193683
193757
|
function throwKeyError(params) {
|
|
@@ -193944,7 +194018,8 @@ function isOAuthCredentialExpiredError(text) {
|
|
|
193944
194018
|
text
|
|
193945
194019
|
) || // the provider no longer recognises the token at all (#1086) — same dead
|
|
193946
194020
|
// credential, phrased as a lookup miss rather than a state transition.
|
|
193947
|
-
/Could not find the appropriate key in your authentication token/i.test(text) ||
|
|
194021
|
+
/Could not find the appropriate key in your authentication token/i.test(text) || // the reversed word order: `Encountered invalidated oauth token for user` (#1474).
|
|
194022
|
+
/(?:expired|invalidated|revoked) (?:OAuth|authentication) token/i.test(text) || /Token refresh failed/i.test(text)
|
|
193948
194023
|
);
|
|
193949
194024
|
}
|
|
193950
194025
|
function isMalformedKeyError(text) {
|
|
@@ -193991,7 +194066,7 @@ function buildRejectedCredentialError(params) {
|
|
|
193991
194066
|
].join("\n");
|
|
193992
194067
|
}
|
|
193993
194068
|
const where = params.inPullfrogStore ? `[Update it in Pullfrog \u2192](${settingsUrl})` : `[Update the GitHub Actions secret \u2192](https://github.com/${params.owner}/${params.name}/settings/secrets/actions)`;
|
|
193994
|
-
const keysUrl =
|
|
194069
|
+
const keysUrl = providerDashboard(params.credential)?.keys;
|
|
193995
194070
|
const issue3 = keysUrl ? `[Issue a new key \u2192](${keysUrl}) \xB7 ` : "";
|
|
193996
194071
|
return [
|
|
193997
194072
|
`**Your \`${params.credential}\` ${CREDENTIAL_REJECTED_MARKER}**${detail}, so the agent never ran.`,
|
|
@@ -194001,12 +194076,43 @@ function buildRejectedCredentialError(params) {
|
|
|
194001
194076
|
`${issue3}${where} \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
194002
194077
|
].join("\n");
|
|
194003
194078
|
}
|
|
194004
|
-
function
|
|
194079
|
+
function providerDashboard(credential) {
|
|
194005
194080
|
for (const [id, provider2] of Object.entries(providers)) {
|
|
194006
|
-
if (provider2.envVars.includes(credential)) return PROVIDER_DASHBOARDS[id]
|
|
194081
|
+
if (provider2.envVars.includes(credential)) return PROVIDER_DASHBOARDS[id];
|
|
194007
194082
|
}
|
|
194008
194083
|
return void 0;
|
|
194009
194084
|
}
|
|
194085
|
+
function buildCredentialPoolRefusedError(params) {
|
|
194086
|
+
const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
|
|
194087
|
+
return [
|
|
194088
|
+
`**${CREDENTIAL_POOL_REFUSED_MARKER}.** Every credential configured for \`${params.model}\` was rejected or is out of quota, so the agent never ran.`,
|
|
194089
|
+
"",
|
|
194090
|
+
...params.refused.map(
|
|
194091
|
+
(credential) => `- ${describeRefusal({ ...params, credential, settingsUrl })}`
|
|
194092
|
+
),
|
|
194093
|
+
"",
|
|
194094
|
+
`[Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
194095
|
+
].join("\n");
|
|
194096
|
+
}
|
|
194097
|
+
function describeRefusal(params) {
|
|
194098
|
+
const credential = params.credential;
|
|
194099
|
+
const verdict = credential.verdict;
|
|
194100
|
+
const workflow = credential.source === "workflow";
|
|
194101
|
+
const head = `\`${credential.name}\` from ${workflow ? "the workflow" : `${credential.source} scope`}: \`${verdict.detail}\` \u2014`;
|
|
194102
|
+
const subscription = SUBSCRIPTION_CREDENTIALS[credential.name];
|
|
194103
|
+
const dashboard = providerDashboard(credential.name);
|
|
194104
|
+
if (verdict.status === "exhausted" && subscription) {
|
|
194105
|
+
const wait = verdict.resetAt ? `it resets at **${verdict.resetAt.toISOString().slice(0, 16).replace("T", " ")} UTC**; re-trigger after that` : "re-trigger after the limit resets";
|
|
194106
|
+
return `${head} ${wait}, or add an API key for this provider, which Pullfrog falls back to automatically.`;
|
|
194107
|
+
}
|
|
194108
|
+
if (verdict.status === "exhausted")
|
|
194109
|
+
return `${head} add credit or raise its quota with the provider.${dashboard ? ` [Top up \u2192](${dashboard.billing})` : ""}`;
|
|
194110
|
+
if (subscription)
|
|
194111
|
+
return `${head} re-authenticate with \`${subscription.command}\`, or switch this repo to a model you hold an API key for. [Re-authenticate \u2192](${subscription.docs})`;
|
|
194112
|
+
const where = workflow ? `[Update the GitHub Actions secret \u2192](https://github.com/${params.owner}/${params.name}/settings/secrets/actions)` : `[Update it in Pullfrog \u2192](${params.settingsUrl})`;
|
|
194113
|
+
const issue3 = dashboard?.keys ? `[Issue a new key \u2192](${dashboard.keys}) \xB7 ` : "";
|
|
194114
|
+
return `${head} issue a new key and update the copy Pullfrog uses. ${issue3}${where}`;
|
|
194115
|
+
}
|
|
194010
194116
|
function formatApiKeyErrorSummary(params) {
|
|
194011
194117
|
if (params.raw.includes(MISSING_KEY_MARKER)) {
|
|
194012
194118
|
if (params.raw.startsWith(`**${MISSING_KEY_MARKER}**`)) return params.raw;
|
|
@@ -194255,11 +194361,11 @@ function formatBillingErrorSummary(error49, owner) {
|
|
|
194255
194361
|
}
|
|
194256
194362
|
if (error49.code === "router_monthly_limit") {
|
|
194257
194363
|
return [
|
|
194258
|
-
"**Pullfrog Router
|
|
194364
|
+
"**Pullfrog Router is out of credit, and the monthly spend limit blocks the next auto-reload.**",
|
|
194259
194365
|
"",
|
|
194260
|
-
"
|
|
194366
|
+
"Top up by hand, ask your admin to raise the cap, or wait for it to reset at 00:00 UTC on the 1st.",
|
|
194261
194367
|
"",
|
|
194262
|
-
`[Adjust limit \u2192](${billingConsoleUrl(owner)})`
|
|
194368
|
+
`[Top up balance \u2192](${billingConsoleUrl(owner)}) \xB7 [Adjust limit \u2192](${billingConsoleUrl(owner)})`
|
|
194263
194369
|
].join("\n");
|
|
194264
194370
|
}
|
|
194265
194371
|
if (error49.code === "commercial_plan_required") {
|
|
@@ -194546,7 +194652,13 @@ var codexUsageSchema = external_exports.object({
|
|
|
194546
194652
|
limit_reached: external_exports.boolean(),
|
|
194547
194653
|
primary_window: codexWindowSchema,
|
|
194548
194654
|
secondary_window: codexWindowSchema
|
|
194549
|
-
}).optional()
|
|
194655
|
+
}).optional(),
|
|
194656
|
+
credits: external_exports.object({
|
|
194657
|
+
has_credits: external_exports.boolean().optional(),
|
|
194658
|
+
unlimited: external_exports.boolean().optional(),
|
|
194659
|
+
overage_limit_reached: external_exports.boolean().optional()
|
|
194660
|
+
}).nullish(),
|
|
194661
|
+
spend_control: external_exports.object({ reached: external_exports.boolean().optional() }).nullish()
|
|
194550
194662
|
});
|
|
194551
194663
|
var unknown4 = { status: "unknown" };
|
|
194552
194664
|
async function readSubscriptionEndpoint(input) {
|
|
@@ -194589,9 +194701,12 @@ async function probeSubscription(input) {
|
|
|
194589
194701
|
const body = await response.json().catch(() => null);
|
|
194590
194702
|
if (!codex2) return unknown4;
|
|
194591
194703
|
const parsed2 = codexUsageSchema.safeParse(body);
|
|
194592
|
-
|
|
194593
|
-
|
|
194704
|
+
if (!parsed2.success || !parsed2.data.rate_limit) return unknown4;
|
|
194705
|
+
const limit = parsed2.data.rate_limit;
|
|
194594
194706
|
if (limit.allowed && !limit.limit_reached) return { status: "usable" };
|
|
194707
|
+
const credits = parsed2.data.credits;
|
|
194708
|
+
if ((credits?.has_credits || credits?.unlimited) && !credits.overage_limit_reached && !parsed2.data.spend_control?.reached)
|
|
194709
|
+
return { status: "usable" };
|
|
194595
194710
|
const windows = [limit.primary_window, limit.secondary_window];
|
|
194596
194711
|
const full = windows.filter((window2) => (window2?.used_percent ?? 0) >= 100);
|
|
194597
194712
|
const resets = (full.length ? full : windows).flatMap(
|
|
@@ -194639,15 +194754,24 @@ async function probeInference(input) {
|
|
|
194639
194754
|
const error49 = external_exports.object({ error: external_exports.object({ code: external_exports.string() }) }).safeParse(await response.json().catch(() => null));
|
|
194640
194755
|
return error49.success && error49.data.error.code === "insufficient_quota" ? { status: "exhausted", detail: "refused with 429: insufficient quota", resetAt: void 0 } : unknown4;
|
|
194641
194756
|
}
|
|
194757
|
+
if (response?.status === 401 || response?.status === 403)
|
|
194758
|
+
return {
|
|
194759
|
+
status: "rejected",
|
|
194760
|
+
detail: `rejected with ${response.status}${await providerReason(response)}`
|
|
194761
|
+
};
|
|
194642
194762
|
await response?.body?.cancel();
|
|
194643
194763
|
if (!response) return unknown4;
|
|
194644
194764
|
if (response.ok) return { status: "usable" };
|
|
194645
|
-
if (response.status === 401 || response.status === 403)
|
|
194646
|
-
return { status: "rejected", detail: `rejected with ${response.status}` };
|
|
194647
194765
|
if (response.status === 402)
|
|
194648
194766
|
return { status: "exhausted", detail: "refused with 402", resetAt: void 0 };
|
|
194649
194767
|
return unknown4;
|
|
194650
194768
|
}
|
|
194769
|
+
async function providerReason(response) {
|
|
194770
|
+
const body = external_exports.object({ error: external_exports.union([external_exports.string(), external_exports.object({ message: external_exports.string() })]) }).safeParse(await response.json().catch(() => null));
|
|
194771
|
+
if (!body.success) return "";
|
|
194772
|
+
const error49 = body.data.error;
|
|
194773
|
+
return `: ${(typeof error49 === "string" ? error49 : error49.message).slice(0, 300)}`;
|
|
194774
|
+
}
|
|
194651
194775
|
|
|
194652
194776
|
// utils/credentialPool.ts
|
|
194653
194777
|
var receipts = {};
|
|
@@ -194656,8 +194780,8 @@ function saveReceipts() {
|
|
|
194656
194780
|
for (const receipt of Object.values(receipts)) maskSecret(receipt);
|
|
194657
194781
|
saveSecretState("credential_receipts", JSON.stringify(receipts));
|
|
194658
194782
|
}
|
|
194659
|
-
var select =
|
|
194660
|
-
async (input) => {
|
|
194783
|
+
var select = mutation({
|
|
194784
|
+
run: async (input) => {
|
|
194661
194785
|
const response = await apiFetch({
|
|
194662
194786
|
path: "/api/runtime/credentials",
|
|
194663
194787
|
method: "POST",
|
|
@@ -194675,11 +194799,8 @@ var select = op(
|
|
|
194675
194799
|
});
|
|
194676
194800
|
return selectedCredentialSchema.parse(await response.json());
|
|
194677
194801
|
},
|
|
194678
|
-
|
|
194679
|
-
|
|
194680
|
-
rethrow: (error49) => error49 instanceof Error && typeof error49.cause === "number" && error49.cause >= 400 && error49.cause < 500
|
|
194681
|
-
}
|
|
194682
|
-
);
|
|
194802
|
+
retry: (error49, attempt) => error49 instanceof Error && typeof error49.cause === "number" && error49.cause >= 400 && error49.cause < 500 ? -1 : delay2([250, 1e3], attempt)
|
|
194803
|
+
});
|
|
194683
194804
|
function subscriptionForModel(model) {
|
|
194684
194805
|
if (!model.includes("/")) return null;
|
|
194685
194806
|
const provider2 = getModelProvider(model);
|
|
@@ -194742,12 +194863,14 @@ async function selectConfiguredCredential(input) {
|
|
|
194742
194863
|
const subscription = subscriptionForModel(model);
|
|
194743
194864
|
const names = getModelEnvVars(model).filter((name) => name !== subscription);
|
|
194744
194865
|
if (subscription) names.unshift(subscription);
|
|
194866
|
+
const opencodePinned = process.env.PULLFROG_AGENT?.trim() === "opencode";
|
|
194867
|
+
const presentable = (name) => canInstallSubscription(name) && !(opencodePinned && CLAUDE_CODE_ONLY_CREDENTIALS.includes(name));
|
|
194745
194868
|
const candidates = access.candidates.filter(
|
|
194746
|
-
(candidate) => names.includes(candidate.name) &&
|
|
194869
|
+
(candidate) => names.includes(candidate.name) && presentable(candidate.name)
|
|
194747
194870
|
);
|
|
194748
194871
|
if (!candidates.length) return false;
|
|
194749
194872
|
const options = [
|
|
194750
|
-
...names.filter((name) => workflowCredentials[name] &&
|
|
194873
|
+
...names.filter((name) => workflowCredentials[name] && presentable(name)).map((name) => ({ name, candidate: void 0 })),
|
|
194751
194874
|
...candidates.map((candidate) => ({ name: candidate.name, candidate }))
|
|
194752
194875
|
].sort((a, b) => Number(b.name === subscription) - Number(a.name === subscription));
|
|
194753
194876
|
const refused = [];
|
|
@@ -194762,11 +194885,16 @@ async function selectConfiguredCredential(input) {
|
|
|
194762
194885
|
if (option.candidate) log.info(`\xBB selected ${option.name} from ${from}`);
|
|
194763
194886
|
return true;
|
|
194764
194887
|
}
|
|
194765
|
-
refused.push(
|
|
194888
|
+
refused.push({ name: option.name, source: option.candidate?.source ?? "workflow", verdict });
|
|
194766
194889
|
log.info(`\xBB ${option.name} from ${from} unavailable; trying the next credential`);
|
|
194767
194890
|
}
|
|
194768
194891
|
throw new Error(
|
|
194769
|
-
|
|
194892
|
+
buildCredentialPoolRefusedError({
|
|
194893
|
+
model,
|
|
194894
|
+
refused,
|
|
194895
|
+
owner: input.ctx.repo.owner,
|
|
194896
|
+
name: input.ctx.repo.name
|
|
194897
|
+
})
|
|
194770
194898
|
);
|
|
194771
194899
|
}
|
|
194772
194900
|
async function probe(input) {
|
|
@@ -194804,10 +194932,10 @@ function activate(input) {
|
|
|
194804
194932
|
}
|
|
194805
194933
|
|
|
194806
194934
|
// utils/gitAuthServer.ts
|
|
194807
|
-
import { randomUUID as
|
|
194935
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
194808
194936
|
import { writeFileSync as writeFileSync14 } from "node:fs";
|
|
194809
194937
|
import { createServer as createServer3 } from "node:http";
|
|
194810
|
-
import { join as
|
|
194938
|
+
import { join as join25 } from "node:path";
|
|
194811
194939
|
var REVOKED_TRAP_MS = 6e4;
|
|
194812
194940
|
function revokeGitHubToken(token) {
|
|
194813
194941
|
fetch("https://api.github.com/installation/token", {
|
|
@@ -194862,7 +194990,7 @@ async function startGitAuthServer(tmpdir3) {
|
|
|
194862
194990
|
const port = rawAddr.port;
|
|
194863
194991
|
log.debug(`git auth server listening on 127.0.0.1:${port}`);
|
|
194864
194992
|
function register7(token) {
|
|
194865
|
-
const code =
|
|
194993
|
+
const code = randomUUID6();
|
|
194866
194994
|
codes.set(code, { token, state: "active" });
|
|
194867
194995
|
return code;
|
|
194868
194996
|
}
|
|
@@ -194874,9 +195002,9 @@ async function startGitAuthServer(tmpdir3) {
|
|
|
194874
195002
|
entry.timeout.unref();
|
|
194875
195003
|
}
|
|
194876
195004
|
function writeAskpassScript(code) {
|
|
194877
|
-
const scriptId =
|
|
195005
|
+
const scriptId = randomUUID6();
|
|
194878
195006
|
const scriptName = `askpass-${scriptId}.js`;
|
|
194879
|
-
const scriptPath =
|
|
195007
|
+
const scriptPath = join25(tmpdir3, scriptName);
|
|
194880
195008
|
const content = [
|
|
194881
195009
|
`#!/usr/bin/env node`,
|
|
194882
195010
|
`var a=process.argv[2]||"";`,
|
|
@@ -194965,13 +195093,10 @@ function getShellInstructions(shell, t) {
|
|
|
194965
195093
|
|
|
194966
195094
|
Shell command execution is DISABLED. Do not attempt to run shell commands.`;
|
|
194967
195095
|
case "restricted":
|
|
194968
|
-
return `### Shell commands
|
|
194969
|
-
|
|
194970
|
-
Use the \`${t("shell")}\` MCP tool for all shell command execution. This tool provides a secure environment with filtered credentials. Do NOT use any native shell tool \u2014 it is disabled for security. For long-running processes (dev servers, watchers), use \`shell({ command, background: true })\`. Use \`${t("kill_background")}\` to stop background processes.`;
|
|
194971
195096
|
case "enabled":
|
|
194972
195097
|
return `### Shell commands
|
|
194973
195098
|
|
|
194974
|
-
Use
|
|
195099
|
+
Use the \`${t("shell")}\` MCP tool for all shell command execution.${shell === "restricted" ? " This tool provides a secure environment with filtered credentials. Do NOT use any native shell tool \u2014 it is disabled for security." : ""} For long-running processes (dev servers, watchers), use \`shell({ command, background: true })\`. Use \`${t("kill_background")}\` to stop background processes.`;
|
|
194975
195100
|
default: {
|
|
194976
195101
|
const _exhaustive = shell;
|
|
194977
195102
|
return _exhaustive;
|
|
@@ -195328,7 +195453,7 @@ function resolveInstructions(ctx) {
|
|
|
195328
195453
|
|
|
195329
195454
|
// utils/learnings.ts
|
|
195330
195455
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
195331
|
-
import { dirname as dirname4, join as
|
|
195456
|
+
import { dirname as dirname4, join as join26 } from "node:path";
|
|
195332
195457
|
|
|
195333
195458
|
// utils/learningsTruncate.ts
|
|
195334
195459
|
var MAX_LEARNINGS_LENGTH = 1e5;
|
|
@@ -195346,10 +195471,10 @@ function truncateAtLineBoundary(body, cap) {
|
|
|
195346
195471
|
var LEARNINGS_FILE_NAME = "pullfrog-learnings.md";
|
|
195347
195472
|
var XREPO_LEARNINGS_FILE_NAME = "pullfrog-xrepo-learnings.md";
|
|
195348
195473
|
function learningsFilePath(tmpdir3) {
|
|
195349
|
-
return
|
|
195474
|
+
return join26(tmpdir3, LEARNINGS_FILE_NAME);
|
|
195350
195475
|
}
|
|
195351
195476
|
function xrepoLearningsFilePath(tmpdir3) {
|
|
195352
|
-
return
|
|
195477
|
+
return join26(tmpdir3, XREPO_LEARNINGS_FILE_NAME);
|
|
195353
195478
|
}
|
|
195354
195479
|
async function seedLearningsFile(params) {
|
|
195355
195480
|
const path4 = learningsFilePath(params.tmpdir);
|
|
@@ -195900,7 +196025,9 @@ async function resolveTokens(params) {
|
|
|
195900
196025
|
// commit-status check-runs for branch protection. the app already grants
|
|
195901
196026
|
// checks:write; this scopes the MCP token up to use it.
|
|
195902
196027
|
checks: "write",
|
|
195903
|
-
|
|
196028
|
+
// write (not read) so postReviewCleanup can dispatch the follow-up re-review
|
|
196029
|
+
// for commits pushed while a review was in flight; read 403s it.
|
|
196030
|
+
actions: "write"
|
|
195904
196031
|
};
|
|
195905
196032
|
const mcpToken = await acquireNewToken({
|
|
195906
196033
|
repos: writeRepos,
|
|
@@ -196116,8 +196243,8 @@ async function mintProxyKey(ctx) {
|
|
|
196116
196243
|
try {
|
|
196117
196244
|
const headers = await buildProxyTokenHeaders(ctx);
|
|
196118
196245
|
if (!headers) return null;
|
|
196119
|
-
const response = await
|
|
196120
|
-
async () => {
|
|
196246
|
+
const response = await mutation({
|
|
196247
|
+
run: async () => {
|
|
196121
196248
|
const r = await apiFetch({ path: "/api/proxy-token", method: "POST", headers });
|
|
196122
196249
|
if (r.status >= 500) {
|
|
196123
196250
|
const body = await r.json().catch(() => null);
|
|
@@ -196127,12 +196254,9 @@ async function mintProxyKey(ctx) {
|
|
|
196127
196254
|
}
|
|
196128
196255
|
return r;
|
|
196129
196256
|
},
|
|
196130
|
-
|
|
196131
|
-
|
|
196132
|
-
|
|
196133
|
-
rethrow: (error49) => !(error49 instanceof TransientError)
|
|
196134
|
-
}
|
|
196135
|
-
)();
|
|
196257
|
+
name: "proxy key mint",
|
|
196258
|
+
retry: (error49, attempt) => error49 instanceof TransientError ? delay2([1e3, 2e3], attempt) : -1
|
|
196259
|
+
})();
|
|
196136
196260
|
if (response.status === 402) {
|
|
196137
196261
|
const body = await response.json().catch(() => null);
|
|
196138
196262
|
throw new BillingError(body?.error ?? "insufficient balance", {
|
|
@@ -196165,10 +196289,10 @@ async function buildProxyTokenHeaders(ctx) {
|
|
|
196165
196289
|
const fundingSource = ctx.fundingSource;
|
|
196166
196290
|
if (ctx.oidcCredentials) {
|
|
196167
196291
|
const creds = ctx.oidcCredentials;
|
|
196168
|
-
const oidcToken = await
|
|
196292
|
+
const oidcToken = await query({
|
|
196293
|
+
run: () => fetchIdTokenFromStash(creds),
|
|
196169
196294
|
name: "ID token mint",
|
|
196170
|
-
|
|
196171
|
-
rethrow: (error49) => !isTransientTokenError(error49)
|
|
196295
|
+
retry: (error49, attempt) => isTransientTokenError(error49) ? delay2([1e3, 2e3], attempt) : -1
|
|
196172
196296
|
})();
|
|
196173
196297
|
return {
|
|
196174
196298
|
Authorization: `Bearer ${oidcToken}`,
|
|
@@ -196289,7 +196413,7 @@ async function resolveTrialFallback(ctx) {
|
|
|
196289
196413
|
|
|
196290
196414
|
// utils/prSummary.ts
|
|
196291
196415
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
196292
|
-
import { dirname as dirname5, join as
|
|
196416
|
+
import { dirname as dirname5, join as join27 } from "node:path";
|
|
196293
196417
|
var SUMMARY_FILE_NAME = "pullfrog-summary.md";
|
|
196294
196418
|
var SUMMARY_SCAFFOLD = `# PR summary
|
|
196295
196419
|
|
|
@@ -196299,7 +196423,7 @@ var SUMMARY_SCAFFOLD = `# PR summary
|
|
|
196299
196423
|
var MIN_SNAPSHOT_LENGTH = 60;
|
|
196300
196424
|
var MAX_SNAPSHOT_LENGTH = 32768;
|
|
196301
196425
|
function summaryFilePath(tmpdir3) {
|
|
196302
|
-
return
|
|
196426
|
+
return join27(tmpdir3, SUMMARY_FILE_NAME);
|
|
196303
196427
|
}
|
|
196304
196428
|
async function seedSummaryFile(params) {
|
|
196305
196429
|
const path4 = summaryFilePath(params.tmpdir);
|
|
@@ -196415,109 +196539,6 @@ ${collapsible}` : output;
|
|
|
196415
196539
|
};
|
|
196416
196540
|
}
|
|
196417
196541
|
|
|
196418
|
-
// utils/runContext.ts
|
|
196419
|
-
var defaultSettings = {
|
|
196420
|
-
model: null,
|
|
196421
|
-
effort: null,
|
|
196422
|
-
modes: [],
|
|
196423
|
-
setupScript: null,
|
|
196424
|
-
postCheckoutScript: null,
|
|
196425
|
-
prepushScript: null,
|
|
196426
|
-
stopScript: null,
|
|
196427
|
-
push: "restricted",
|
|
196428
|
-
shell: "restricted",
|
|
196429
|
-
prApproveEnabled: false,
|
|
196430
|
-
reviewDrafts: false,
|
|
196431
|
-
autoMergeEnabled: false,
|
|
196432
|
-
codexAgent: false,
|
|
196433
|
-
signedCommits: false,
|
|
196434
|
-
repoIntelligence: false,
|
|
196435
|
-
progressComments: true,
|
|
196436
|
-
statusChecks: true,
|
|
196437
|
-
approvalCheck: false,
|
|
196438
|
-
modeInstructions: {},
|
|
196439
|
-
learnings: null,
|
|
196440
|
-
learningsHeadings: [],
|
|
196441
|
-
envAllowlist: null,
|
|
196442
|
-
xrepoBrief: null,
|
|
196443
|
-
xrepoLearnings: null,
|
|
196444
|
-
xrepoLearningsHeadings: []
|
|
196445
|
-
};
|
|
196446
|
-
var defaultRunContext = {
|
|
196447
|
-
settings: defaultSettings,
|
|
196448
|
-
apiToken: "",
|
|
196449
|
-
oss: false,
|
|
196450
|
-
plan: "none"
|
|
196451
|
-
};
|
|
196452
|
-
var unknownSecretsRunContext = {
|
|
196453
|
-
...defaultRunContext,
|
|
196454
|
-
secretsUnavailable: true
|
|
196455
|
-
};
|
|
196456
|
-
async function fetchRunContext(params) {
|
|
196457
|
-
const timeoutMs = 3e4;
|
|
196458
|
-
const controller = new AbortController();
|
|
196459
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
196460
|
-
try {
|
|
196461
|
-
const headers = {
|
|
196462
|
-
Authorization: `Bearer ${params.token}`,
|
|
196463
|
-
"X-Pullfrog-Credential-Pools": "1"
|
|
196464
|
-
};
|
|
196465
|
-
if (params.oidcToken) {
|
|
196466
|
-
headers["X-GitHub-OIDC-Token"] = params.oidcToken;
|
|
196467
|
-
}
|
|
196468
|
-
const query = new URLSearchParams();
|
|
196469
|
-
if (params.runType) query.set("type", params.runType);
|
|
196470
|
-
if (params.routedTier) query.set("tier", params.routedTier);
|
|
196471
|
-
const search2 = query.toString();
|
|
196472
|
-
const response = await apiFetch({
|
|
196473
|
-
path: `/api/repo/${params.repoContext.owner}/${params.repoContext.name}/run-context${search2 ? `?${search2}` : ""}`,
|
|
196474
|
-
headers,
|
|
196475
|
-
signal: controller.signal
|
|
196476
|
-
});
|
|
196477
|
-
clearTimeout(timeoutId);
|
|
196478
|
-
if (response.status === 402) {
|
|
196479
|
-
const body = await response.json().catch(() => null);
|
|
196480
|
-
const reason = typeof body === "object" && body !== null && "reason" in body ? body.reason : null;
|
|
196481
|
-
const commercialRefused = reason === "subscription_unpaid" || reason === "subscription_ended" ? reason : "commercial";
|
|
196482
|
-
return { ...defaultRunContext, commercialRefused };
|
|
196483
|
-
}
|
|
196484
|
-
if (!response.ok) {
|
|
196485
|
-
return response.status >= 500 ? unknownSecretsRunContext : defaultRunContext;
|
|
196486
|
-
}
|
|
196487
|
-
const data = await response.json();
|
|
196488
|
-
if (data === null) {
|
|
196489
|
-
return defaultRunContext;
|
|
196490
|
-
}
|
|
196491
|
-
return {
|
|
196492
|
-
settings: {
|
|
196493
|
-
...defaultSettings,
|
|
196494
|
-
...data.settings,
|
|
196495
|
-
modes: data.settings?.modes ?? [],
|
|
196496
|
-
setupScript: data.settings?.setupScript ?? null,
|
|
196497
|
-
postCheckoutScript: data.settings?.postCheckoutScript ?? null,
|
|
196498
|
-
prepushScript: data.settings?.prepushScript ?? null,
|
|
196499
|
-
stopScript: data.settings?.stopScript ?? null,
|
|
196500
|
-
learningsHeadings: data.settings?.learningsHeadings ?? [],
|
|
196501
|
-
xrepoBrief: data.settings?.xrepoBrief ?? null,
|
|
196502
|
-
xrepoLearnings: data.settings?.xrepoLearnings ?? null,
|
|
196503
|
-
xrepoLearningsHeadings: data.settings?.xrepoLearningsHeadings ?? []
|
|
196504
|
-
},
|
|
196505
|
-
apiToken: data.apiToken,
|
|
196506
|
-
oss: data.oss ?? false,
|
|
196507
|
-
plan: data.plan ?? "none",
|
|
196508
|
-
proxyModel: data.proxyModel,
|
|
196509
|
-
dbSecrets: data.dbSecrets,
|
|
196510
|
-
credentialAccess: data.credentialAccess,
|
|
196511
|
-
secretsUnavailable: data.secretsUnavailable,
|
|
196512
|
-
routerUnfunded: data.routerUnfunded,
|
|
196513
|
-
trialFallback: data.trialFallback
|
|
196514
|
-
};
|
|
196515
|
-
} catch {
|
|
196516
|
-
clearTimeout(timeoutId);
|
|
196517
|
-
return unknownSecretsRunContext;
|
|
196518
|
-
}
|
|
196519
|
-
}
|
|
196520
|
-
|
|
196521
196542
|
// utils/runContextData.ts
|
|
196522
196543
|
async function resolveRunContextData(params) {
|
|
196523
196544
|
const actionRef = process.env.GITHUB_ACTION_REF;
|
|
@@ -196527,23 +196548,25 @@ async function resolveRunContextData(params) {
|
|
|
196527
196548
|
const repoContext = parseRepoContext();
|
|
196528
196549
|
let oidcToken;
|
|
196529
196550
|
try {
|
|
196530
|
-
oidcToken = await
|
|
196551
|
+
oidcToken = await query({
|
|
196552
|
+
run: () => mintIdToken(),
|
|
196531
196553
|
name: "OIDC mint",
|
|
196532
|
-
|
|
196554
|
+
retry: process.env.ACTIONS_ID_TOKEN_REQUEST_URL ? [200, 1e3] : []
|
|
196533
196555
|
})();
|
|
196534
196556
|
} catch {
|
|
196535
196557
|
}
|
|
196536
196558
|
const [repoResponse, runContext] = await Promise.all([
|
|
196537
|
-
|
|
196559
|
+
query({
|
|
196560
|
+
run: () => params.octokit.repos.get({ owner: repoContext.owner, repo: repoContext.name }),
|
|
196538
196561
|
name: "repos.get",
|
|
196539
|
-
|
|
196540
|
-
rethrow: (error49) => !isTransientOctokitError(error49)
|
|
196562
|
+
retry: (error49, attempt) => isTransientOctokitError(error49) ? delay2([100, 500], attempt) : -1
|
|
196541
196563
|
})(),
|
|
196542
196564
|
fetchRunContext({
|
|
196543
196565
|
token: params.token,
|
|
196544
196566
|
repoContext,
|
|
196545
196567
|
oidcToken,
|
|
196546
196568
|
runType: params.runType,
|
|
196569
|
+
plainPrompt: params.plainPrompt,
|
|
196547
196570
|
routedTier: params.routedTier
|
|
196548
196571
|
})
|
|
196549
196572
|
]);
|
|
@@ -196669,7 +196692,7 @@ function formatBillingExhaustedBody(diagnostic) {
|
|
|
196669
196692
|
|
|
196670
196693
|
// utils/runErrorRenderer.ts
|
|
196671
196694
|
function isProviderModelNotFoundError(message) {
|
|
196672
|
-
return message
|
|
196695
|
+
return /ProviderModelNotFoundError|\bModel not found: /.test(message);
|
|
196673
196696
|
}
|
|
196674
196697
|
function isContextOverflowError(message) {
|
|
196675
196698
|
return /Prompt is too long/i.test(message) || /Input exceeds context window/i.test(message) || /maximum context length is \d+ tokens/i.test(message) || /Session too large to compact/i.test(message);
|
|
@@ -196766,6 +196789,7 @@ function detectProviderId(message) {
|
|
|
196766
196789
|
if (/requires more credits|Key limit exceeded \(total limit\)|openrouter\.ai/i.test(message)) {
|
|
196767
196790
|
return "openrouter";
|
|
196768
196791
|
}
|
|
196792
|
+
if (/platform\.openai\.com/i.test(message)) return "openai";
|
|
196769
196793
|
return null;
|
|
196770
196794
|
}
|
|
196771
196795
|
var OPENROUTER_PRIVACY_URL = "https://openrouter.ai/settings/privacy";
|
|
@@ -196863,12 +196887,38 @@ function formatByokSetupSummary(input) {
|
|
|
196863
196887
|
].join("\n");
|
|
196864
196888
|
}
|
|
196865
196889
|
function formatProviderModelNotFoundSummary(input) {
|
|
196866
|
-
return `The configured model is
|
|
196890
|
+
return `The configured model is not in OpenCode's catalog. Pick a different model for \`${input.owner}/${input.name}\` where it is set \u2014 the Pullfrog console, the workflow's \`model\` input, or the \`PULLFROG_MODEL\` variable \u2014 or contact support if this persists.
|
|
196867
196891
|
|
|
196868
196892
|
\`\`\`
|
|
196869
196893
|
${input.raw}
|
|
196870
196894
|
\`\`\``;
|
|
196871
196895
|
}
|
|
196896
|
+
function formatProviderUsageLimit(input) {
|
|
196897
|
+
return [
|
|
196898
|
+
"**The provider's usage limit for this account has been reached.**",
|
|
196899
|
+
"",
|
|
196900
|
+
"A subscription window resets on its own, so re-trigger after it does; a limit set on a pay-as-you-go workspace has to be raised. A model on another provider can run in the meantime.",
|
|
196901
|
+
"",
|
|
196902
|
+
`[Model settings \u2192](${getApiUrl()}/console/${input.owner}/${input.name}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
|
|
196903
|
+
"",
|
|
196904
|
+
`\`\`\`
|
|
196905
|
+
${input.raw}
|
|
196906
|
+
\`\`\``
|
|
196907
|
+
].join("\n");
|
|
196908
|
+
}
|
|
196909
|
+
function formatProviderErrorBody(input) {
|
|
196910
|
+
return [
|
|
196911
|
+
"**The model provider returned an error, so this run stopped.**",
|
|
196912
|
+
"",
|
|
196913
|
+
"The error is below. If it names your key, plan or balance, fix that with the provider or pick another model before re-triggering.",
|
|
196914
|
+
"",
|
|
196915
|
+
`[Model settings \u2192](${getApiUrl()}/console/${input.owner}/${input.name}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`,
|
|
196916
|
+
"",
|
|
196917
|
+
`\`\`\`
|
|
196918
|
+
${input.raw}
|
|
196919
|
+
\`\`\``
|
|
196920
|
+
].join("\n");
|
|
196921
|
+
}
|
|
196872
196922
|
function renderRunError(input) {
|
|
196873
196923
|
const billingError = input.routerActive && isRouterKeylimitExhaustedError(input.errorMessage) ? new BillingError(input.errorMessage, { code: "router_keylimit_exhausted" }) : null;
|
|
196874
196924
|
if (billingError) {
|
|
@@ -196884,7 +196934,7 @@ function renderRunError(input) {
|
|
|
196884
196934
|
if (input.errorMessage.includes(ROUTER_UNFUNDED_MARKER)) {
|
|
196885
196935
|
return { summary: input.errorMessage, comment: input.errorMessage };
|
|
196886
196936
|
}
|
|
196887
|
-
if (input.errorMessage.includes(CREDENTIAL_REJECTED_MARKER)) {
|
|
196937
|
+
if (input.errorMessage.includes(CREDENTIAL_REJECTED_MARKER) || input.errorMessage.includes(CREDENTIAL_POOL_REFUSED_MARKER)) {
|
|
196888
196938
|
return { summary: input.errorMessage, comment: input.errorMessage };
|
|
196889
196939
|
}
|
|
196890
196940
|
const isHang = input.errorMessage.startsWith("activity timeout") || input.errorMessage.startsWith("agent still pending");
|
|
@@ -196907,6 +196957,16 @@ ${body}`, comment: body };
|
|
|
196907
196957
|
});
|
|
196908
196958
|
return { summary: `### \u274C Pullfrog failed
|
|
196909
196959
|
|
|
196960
|
+
${body}`, comment: body };
|
|
196961
|
+
}
|
|
196962
|
+
if (isProviderUsageLimit(input.errorMessage)) {
|
|
196963
|
+
const body = formatProviderUsageLimit({
|
|
196964
|
+
owner: input.repo.owner,
|
|
196965
|
+
name: input.repo.name,
|
|
196966
|
+
raw: input.errorMessage
|
|
196967
|
+
});
|
|
196968
|
+
return { summary: `### \u274C Pullfrog failed
|
|
196969
|
+
|
|
196910
196970
|
${body}`, comment: body };
|
|
196911
196971
|
}
|
|
196912
196972
|
if (isProviderMissingCredential(input.errorMessage)) {
|
|
@@ -197001,6 +197061,16 @@ ${hangBody}`,
|
|
|
197001
197061
|
comment: explained ? hangBody : formatMinimalFailureComment(input.repo)
|
|
197002
197062
|
};
|
|
197003
197063
|
}
|
|
197064
|
+
if (input.errorMessage.startsWith("provider error: ")) {
|
|
197065
|
+
const body = formatProviderErrorBody({
|
|
197066
|
+
owner: input.repo.owner,
|
|
197067
|
+
name: input.repo.name,
|
|
197068
|
+
raw: input.errorMessage
|
|
197069
|
+
});
|
|
197070
|
+
return { summary: `### \u274C Pullfrog failed
|
|
197071
|
+
|
|
197072
|
+
${body}`, comment: body };
|
|
197073
|
+
}
|
|
197004
197074
|
const genericBody = formatGenericFailure(input.errorMessage);
|
|
197005
197075
|
return {
|
|
197006
197076
|
summary: `### \u274C Pullfrog failed
|
|
@@ -197080,17 +197150,14 @@ async function autoMergeAfterApprove(ctx) {
|
|
|
197080
197150
|
});
|
|
197081
197151
|
if (hasBlockingHumanReview(reviews)) return skip("human changes requested");
|
|
197082
197152
|
try {
|
|
197083
|
-
await
|
|
197084
|
-
() => ctx.octokit.graphql(ENABLE_AUTO_MERGE, {
|
|
197153
|
+
await mutation({
|
|
197154
|
+
run: () => ctx.octokit.graphql(ENABLE_AUTO_MERGE, {
|
|
197085
197155
|
pullRequestId: pr.data.node_id,
|
|
197086
197156
|
headSha
|
|
197087
197157
|
}),
|
|
197088
|
-
|
|
197089
|
-
|
|
197090
|
-
|
|
197091
|
-
rethrow: (error49) => !isTransientOctokitError(error49)
|
|
197092
|
-
}
|
|
197093
|
-
)();
|
|
197158
|
+
name: "enablePullRequestAutoMerge",
|
|
197159
|
+
retry: (error49, attempt) => isTransientOctokitError(error49) ? delay2([500, 2e3], attempt) : -1
|
|
197160
|
+
})();
|
|
197094
197161
|
log.info(`autoMerge: pr=#${pullNumber} @ ${headSha.slice(0, 7)} \u2192 native auto-merge enabled`);
|
|
197095
197162
|
await comment(
|
|
197096
197163
|
"> \u2705 Approved \u2014 auto-merge enabled; GitHub will merge once required checks pass."
|
|
@@ -197128,7 +197195,17 @@ async function autoMergeAfterApprove(ctx) {
|
|
|
197128
197195
|
var RE_REVIEW_PREAMBLE = "Incrementally re-review the new commits on this pull request. Use the IncrementalReview mode.";
|
|
197129
197196
|
async function postReviewCleanup(ctx) {
|
|
197130
197197
|
const review = ctx.toolState.review;
|
|
197131
|
-
if (!review)
|
|
197198
|
+
if (!review) {
|
|
197199
|
+
const checkoutSha = primaryRepoState(ctx.toolState).checkoutSha;
|
|
197200
|
+
if (ctx.toolState.selectedMode === "IncrementalReview" && checkoutSha) {
|
|
197201
|
+
await patchWorkflowRunFields(ctx, { reviewSkipped: true });
|
|
197202
|
+
await bestEffort(
|
|
197203
|
+
() => dispatchFollowUpReReview(ctx, checkoutSha),
|
|
197204
|
+
"follow-up re-review dispatch"
|
|
197205
|
+
);
|
|
197206
|
+
}
|
|
197207
|
+
return;
|
|
197208
|
+
}
|
|
197132
197209
|
delete ctx.toolState.review;
|
|
197133
197210
|
await bestEffort(() => reportReviewNodeId(ctx, { nodeId: review.nodeId }), "reportReviewNodeId");
|
|
197134
197211
|
if (review.reviewedSha) {
|
|
@@ -197181,20 +197258,17 @@ async function dispatchFollowUpReReview(ctx, reviewedSha) {
|
|
|
197181
197258
|
eventInstructions: RE_REVIEW_PREAMBLE,
|
|
197182
197259
|
event
|
|
197183
197260
|
};
|
|
197184
|
-
await
|
|
197185
|
-
() => ctx.octokit.rest.actions.createWorkflowDispatch({
|
|
197261
|
+
await mutation({
|
|
197262
|
+
run: () => ctx.octokit.rest.actions.createWorkflowDispatch({
|
|
197186
197263
|
owner: ctx.repo.owner,
|
|
197187
197264
|
repo: ctx.repo.name,
|
|
197188
197265
|
workflow_id: getCurrentWorkflowFilename(),
|
|
197189
197266
|
ref: pr.data.base.repo.default_branch,
|
|
197190
197267
|
inputs: { prompt: JSON.stringify(payload) }
|
|
197191
197268
|
}),
|
|
197192
|
-
|
|
197193
|
-
|
|
197194
|
-
|
|
197195
|
-
rethrow: (error49) => !isTransientOctokitError(error49)
|
|
197196
|
-
}
|
|
197197
|
-
)();
|
|
197269
|
+
name: "reReviewDispatch",
|
|
197270
|
+
retry: (error49, attempt) => isTransientOctokitError(error49) ? delay2([500, 2e3], attempt) : -1
|
|
197271
|
+
})();
|
|
197198
197272
|
}
|
|
197199
197273
|
function getCurrentWorkflowFilename() {
|
|
197200
197274
|
const ref = process.env.GITHUB_WORKFLOW_REF ?? "";
|
|
@@ -197204,6 +197278,7 @@ function getCurrentWorkflowFilename() {
|
|
|
197204
197278
|
|
|
197205
197279
|
// utils/runStatusCheck.ts
|
|
197206
197280
|
var RUN_STATUS_CHECK_NAME = "pullfrog";
|
|
197281
|
+
var GITHUB_ACTIONS_APP_SLUG = "github-actions";
|
|
197207
197282
|
var APPROVAL_CHECK_NAME = "pullfrog-approval";
|
|
197208
197283
|
function parseCheckRunId(raw2) {
|
|
197209
197284
|
if (!raw2?.id) return void 0;
|
|
@@ -197257,7 +197332,12 @@ function terminalOutput(params) {
|
|
|
197257
197332
|
const review = params.reviewUrl ? `
|
|
197258
197333
|
|
|
197259
197334
|
[View the review Pullfrog posted \u2192](${params.reviewUrl})` : "";
|
|
197260
|
-
if (params.conclusion === "success")
|
|
197335
|
+
if (params.conclusion === "success") {
|
|
197336
|
+
const note = params.note ? `
|
|
197337
|
+
|
|
197338
|
+
${params.note}` : "";
|
|
197339
|
+
return { title: base.title, summary: base.summary + review + note };
|
|
197340
|
+
}
|
|
197261
197341
|
return {
|
|
197262
197342
|
title: base.title,
|
|
197263
197343
|
summary: base.summary + logsLine(params.detailsUrl) + review + disableCheckLine(params.owner, params.repo)
|
|
@@ -197275,7 +197355,8 @@ async function finalizeRunStatusCheck(params) {
|
|
|
197275
197355
|
owner: params.owner,
|
|
197276
197356
|
repo: params.repo,
|
|
197277
197357
|
detailsUrl: params.detailsUrl,
|
|
197278
|
-
reviewUrl: params.reviewUrl
|
|
197358
|
+
reviewUrl: params.reviewUrl,
|
|
197359
|
+
note: params.note
|
|
197279
197360
|
})
|
|
197280
197361
|
};
|
|
197281
197362
|
if (params.detailsUrl) updateParams.details_url = params.detailsUrl;
|
|
@@ -197294,7 +197375,8 @@ async function createTerminalRunStatusCheck(params) {
|
|
|
197294
197375
|
owner: params.owner,
|
|
197295
197376
|
repo: params.repo,
|
|
197296
197377
|
detailsUrl: params.detailsUrl,
|
|
197297
|
-
reviewUrl: params.reviewUrl
|
|
197378
|
+
reviewUrl: params.reviewUrl,
|
|
197379
|
+
note: params.note
|
|
197298
197380
|
})
|
|
197299
197381
|
};
|
|
197300
197382
|
if (params.detailsUrl) createParams.details_url = params.detailsUrl;
|
|
@@ -197310,6 +197392,8 @@ async function reportStatusChecks(ctx, params) {
|
|
|
197310
197392
|
if (checkRunId === void 0 && !ctx.payload.runStatusCheck && !ctx.payload.approvalCheck) return;
|
|
197311
197393
|
const conclusion = params.runSucceeded ? "success" : "failure";
|
|
197312
197394
|
const detailsUrl = ctx.runId ? `https://github.com/${ctx.repo.owner}/${ctx.repo.name}/actions/runs/${ctx.runId}` : void 0;
|
|
197395
|
+
const approval = ctx.toolState.approval;
|
|
197396
|
+
const note = event.silent && !approval?.url ? ctx.toolState.lastProgressBody : void 0;
|
|
197313
197397
|
if (checkRunId !== void 0) {
|
|
197314
197398
|
await finalizeRunStatusCheck({
|
|
197315
197399
|
octokit: ctx.octokit,
|
|
@@ -197318,11 +197402,12 @@ async function reportStatusChecks(ctx, params) {
|
|
|
197318
197402
|
checkRunId,
|
|
197319
197403
|
conclusion,
|
|
197320
197404
|
detailsUrl,
|
|
197321
|
-
reviewUrl:
|
|
197405
|
+
reviewUrl: approval?.url,
|
|
197406
|
+
note
|
|
197322
197407
|
}).then(() => log.info(`\xBB finalized ${RUN_STATUS_CHECK_NAME} check (${conclusion})`)).catch((err) => log.debug(`status checks: ${RUN_STATUS_CHECK_NAME} finalize failed: ${err}`));
|
|
197323
197408
|
}
|
|
197324
|
-
const
|
|
197325
|
-
const needsApprovalCheck = ctx.payload.approvalCheck && params.runSucceeded && approval;
|
|
197409
|
+
const carriesApproval = !approval && ctx.toolState.selectedMode === "IncrementalReview";
|
|
197410
|
+
const needsApprovalCheck = ctx.payload.approvalCheck && params.runSucceeded && (approval !== void 0 || carriesApproval);
|
|
197326
197411
|
const needsFallbackRunCheck = ctx.payload.runStatusCheck && checkRunId === void 0;
|
|
197327
197412
|
if (!needsApprovalCheck && !needsFallbackRunCheck) return;
|
|
197328
197413
|
let headSha;
|
|
@@ -197345,25 +197430,64 @@ async function reportStatusChecks(ctx, params) {
|
|
|
197345
197430
|
headSha: primaryRepoState(ctx.toolState).checkoutSha ?? headSha,
|
|
197346
197431
|
conclusion,
|
|
197347
197432
|
detailsUrl,
|
|
197348
|
-
reviewUrl:
|
|
197433
|
+
reviewUrl: approval?.url,
|
|
197434
|
+
note
|
|
197349
197435
|
}).then(() => log.info(`\xBB posted ${RUN_STATUS_CHECK_NAME} check (${conclusion})`)).catch((err) => log.debug(`status checks: ${RUN_STATUS_CHECK_NAME} post failed: ${err}`));
|
|
197350
197436
|
}
|
|
197351
|
-
if (!needsApprovalCheck
|
|
197437
|
+
if (!needsApprovalCheck) return;
|
|
197438
|
+
const verdict = approval ? { wouldApprove: approval.wouldApprove, sha: approval.sha ?? headSha, carriedLine: "" } : await carriedApproval(ctx, pullNumber).catch((err) => {
|
|
197439
|
+
log.debug(`status checks: ${APPROVAL_CHECK_NAME} carry-forward failed: ${err}`);
|
|
197440
|
+
return void 0;
|
|
197441
|
+
});
|
|
197442
|
+
if (!verdict) return;
|
|
197352
197443
|
const createParams = {
|
|
197353
197444
|
owner: ctx.repo.owner,
|
|
197354
197445
|
repo: ctx.repo.name,
|
|
197355
197446
|
name: APPROVAL_CHECK_NAME,
|
|
197356
|
-
head_sha:
|
|
197447
|
+
head_sha: verdict.sha,
|
|
197357
197448
|
status: "completed",
|
|
197358
|
-
conclusion:
|
|
197449
|
+
conclusion: verdict.wouldApprove ? "success" : "failure",
|
|
197359
197450
|
output: {
|
|
197360
|
-
title:
|
|
197361
|
-
summary:
|
|
197451
|
+
title: verdict.wouldApprove ? "Pullfrog would approve" : "Pullfrog would not approve",
|
|
197452
|
+
summary: (verdict.wouldApprove ? "Pullfrog has no outstanding review feedback on this PR." : "Pullfrog has outstanding review feedback or requested changes on this PR.") + verdict.carriedLine
|
|
197362
197453
|
}
|
|
197363
197454
|
};
|
|
197364
197455
|
if (detailsUrl) createParams.details_url = detailsUrl;
|
|
197365
197456
|
await ctx.octokit.rest.checks.create(createParams).then(() => log.info(`\xBB posted ${APPROVAL_CHECK_NAME} check`)).catch((err) => log.debug(`status checks: ${APPROVAL_CHECK_NAME} post failed: ${err}`));
|
|
197366
197457
|
}
|
|
197458
|
+
async function carriedApproval(ctx, pullNumber) {
|
|
197459
|
+
const primary = primaryRepoState(ctx.toolState);
|
|
197460
|
+
if (!primary.beforeSha || !primary.checkoutSha) return void 0;
|
|
197461
|
+
if (await latestApprovalConclusion(ctx, primary.checkoutSha) !== void 0) return void 0;
|
|
197462
|
+
const prior = await latestApprovalConclusion(ctx, primary.beforeSha);
|
|
197463
|
+
if (prior === void 0) return void 0;
|
|
197464
|
+
const from = primary.beforeSha.slice(0, 7);
|
|
197465
|
+
if (prior !== "success") {
|
|
197466
|
+
const carriedLine = `
|
|
197467
|
+
|
|
197468
|
+
No review covered this commit, so the verdict on ${from} carries forward.`;
|
|
197469
|
+
return { wouldApprove: false, sha: primary.checkoutSha, carriedLine };
|
|
197470
|
+
}
|
|
197471
|
+
if (ctx.toolState.noReviewNeededSha !== primary.checkoutSha) return void 0;
|
|
197472
|
+
return {
|
|
197473
|
+
wouldApprove: await countOutstandingPullfrogThreads(ctx, pullNumber) === 0,
|
|
197474
|
+
sha: primary.checkoutSha,
|
|
197475
|
+
carriedLine: `
|
|
197476
|
+
|
|
197477
|
+
Pullfrog found nothing to review in the commits since ${from}.`
|
|
197478
|
+
};
|
|
197479
|
+
}
|
|
197480
|
+
async function latestApprovalConclusion(ctx, ref) {
|
|
197481
|
+
const result = await ctx.octokit.rest.checks.listForRef({
|
|
197482
|
+
owner: ctx.repo.owner,
|
|
197483
|
+
repo: ctx.repo.name,
|
|
197484
|
+
ref,
|
|
197485
|
+
check_name: APPROVAL_CHECK_NAME,
|
|
197486
|
+
status: "completed"
|
|
197487
|
+
});
|
|
197488
|
+
const latest = result.data.check_runs.filter((run) => run.app?.slug !== GITHUB_ACTIONS_APP_SLUG).sort((a, b) => (b.completed_at ?? "").localeCompare(a.completed_at ?? ""))[0];
|
|
197489
|
+
return latest?.conclusion ?? void 0;
|
|
197490
|
+
}
|
|
197367
197491
|
|
|
197368
197492
|
// utils/runLifecycle.ts
|
|
197369
197493
|
async function persistRunArtifacts(toolContext) {
|
|
@@ -197702,6 +197826,7 @@ async function main() {
|
|
|
197702
197826
|
octokit: initialOctokit,
|
|
197703
197827
|
token: jobToken,
|
|
197704
197828
|
runType: typeof resolvedPromptInput === "string" ? void 0 : resolvedPromptInput.type,
|
|
197829
|
+
plainPrompt: typeof resolvedPromptInput === "string",
|
|
197705
197830
|
routedTier: typeof resolvedPromptInput === "string" ? void 0 : resolvedPromptInput.routing?.tier
|
|
197706
197831
|
});
|
|
197707
197832
|
timer.checkpoint("runContextData");
|
|
@@ -197756,7 +197881,7 @@ async function main() {
|
|
|
197756
197881
|
const repoDir = payload.cwd;
|
|
197757
197882
|
const preIntrospectionDirty = repoDir ? await dirtyTrackedPaths({ cwd: repoDir }) : null;
|
|
197758
197883
|
const opencodeCliPath = await agents.opencode.install();
|
|
197759
|
-
captureBaselineModels(opencodeCliPath);
|
|
197884
|
+
captureBaselineModels({ cliPath: opencodeCliPath, tmpdir: tmpdir3 });
|
|
197760
197885
|
const injected = [];
|
|
197761
197886
|
if (runContext.dbSecrets) {
|
|
197762
197887
|
for (const [key, value2] of Object.entries(runContext.dbSecrets)) {
|
|
@@ -197773,7 +197898,7 @@ async function main() {
|
|
|
197773
197898
|
await initializeCredentialPool({ ctx: runContext, slug: payload.model, injected });
|
|
197774
197899
|
installCodexAuth();
|
|
197775
197900
|
installXaiAuth();
|
|
197776
|
-
captureAuthorizedModels(opencodeCliPath);
|
|
197901
|
+
captureAuthorizedModels({ cliPath: opencodeCliPath, tmpdir: tmpdir3 });
|
|
197777
197902
|
if (preIntrospectionDirty && repoDir) {
|
|
197778
197903
|
await restoreDirtiedSince({
|
|
197779
197904
|
before: preIntrospectionDirty,
|
|
@@ -197798,7 +197923,7 @@ async function main() {
|
|
|
197798
197923
|
oidc: oidcCredentials
|
|
197799
197924
|
}), true);
|
|
197800
197925
|
wipeRunnerLeakSurface();
|
|
197801
|
-
if (payload.shell === "
|
|
197926
|
+
if (payload.shell !== "disabled" && process.env.CI === "true" && getSandboxMethod() === "none") {
|
|
197802
197927
|
payload.shell = "disabled";
|
|
197803
197928
|
log.warning(
|
|
197804
197929
|
"\xBB shell commands are disabled for this run: this runner provides no PID-namespace isolation (unprivileged unshare, sudo unshare and userns-nested unshare all failed). on a self-hosted Kubernetes/ARC runner, allow user-namespace creation in the pod's seccomp profile \u2014 see https://docs.pullfrog.com/security#self-hosted-runners"
|
|
@@ -197819,6 +197944,7 @@ async function main() {
|
|
|
197819
197944
|
const octokit = createOctokit(tokenRef.mcpToken, getMcpTokenRefresh());
|
|
197820
197945
|
const runInfo = await resolveRun({ octokit });
|
|
197821
197946
|
let toolContext;
|
|
197947
|
+
let succeeded = false;
|
|
197822
197948
|
let progressCallbackDisabled = false;
|
|
197823
197949
|
let todoTracker;
|
|
197824
197950
|
let vertexCredentials;
|
|
@@ -198110,8 +198236,8 @@ ${instructions.user}` : null,
|
|
|
198110
198236
|
log.info(instructions.full);
|
|
198111
198237
|
});
|
|
198112
198238
|
if (agentId === "opencode") {
|
|
198113
|
-
const pluginDir =
|
|
198114
|
-
const hasPlugins =
|
|
198239
|
+
const pluginDir = join28(process.cwd(), ".opencode", "plugin");
|
|
198240
|
+
const hasPlugins = existsSync11(pluginDir) && readdirSync2(pluginDir).some((f) => /\.[jt]sx?$/.test(f));
|
|
198115
198241
|
if (hasPlugins && toolState.dependencyInstallation?.promise) {
|
|
198116
198242
|
log.info(
|
|
198117
198243
|
"\xBB .opencode/plugin/ detected \u2014 awaiting dependency installation before agent start"
|
|
@@ -198236,11 +198362,13 @@ ${instructions.user}` : null,
|
|
|
198236
198362
|
);
|
|
198237
198363
|
}
|
|
198238
198364
|
await finalizeSuccessRun({ toolContext, toolState, result, repo: runContext.repo });
|
|
198239
|
-
|
|
198365
|
+
const outcome = await handleAgentResult({
|
|
198240
198366
|
result,
|
|
198241
198367
|
toolContext,
|
|
198242
198368
|
silent: payload.event.silent ?? false
|
|
198243
198369
|
});
|
|
198370
|
+
succeeded = outcome.success;
|
|
198371
|
+
return outcome;
|
|
198244
198372
|
} catch (_2) {
|
|
198245
198373
|
var _error2 = _2, _hasError2 = true;
|
|
198246
198374
|
} finally {
|
|
@@ -198286,9 +198414,8 @@ ${instructions.user}` : null,
|
|
|
198286
198414
|
if (toolState.model) patch.model = toolState.model;
|
|
198287
198415
|
if (toolState.agent) patch.agent = toolState.agent;
|
|
198288
198416
|
if (toolState.credential) patch.credential = toolState.credential;
|
|
198289
|
-
|
|
198290
|
-
|
|
198291
|
-
}
|
|
198417
|
+
patch.succeeded = succeeded;
|
|
198418
|
+
await patchWorkflowRunFields(toolContext, patch);
|
|
198292
198419
|
}
|
|
198293
198420
|
cleanupVertexCredentials(vertexCredentials);
|
|
198294
198421
|
}
|