pullfrog 0.0.201 → 0.0.202
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/shared.d.ts +65 -1
- package/dist/cli.mjs +2051 -875
- package/dist/index.js +2036 -865
- package/dist/internal.js +8 -6
- package/dist/lifecycle.d.ts +1 -1
- package/dist/mcp/checkout.d.ts +16 -2
- package/dist/mcp/comment.d.ts +1 -0
- package/dist/mcp/geminiSanitizer.d.ts +17 -0
- package/dist/mcp/git.d.ts +8 -2
- package/dist/mcp/review.d.ts +104 -0
- package/dist/mcp/server.d.ts +12 -0
- package/dist/mcp/shared.d.ts +1 -1
- package/dist/modes.d.ts +1 -1
- package/dist/utils/activity.d.ts +4 -0
- package/dist/utils/agent.d.ts +3 -1
- package/dist/utils/diffCoverage.d.ts +62 -0
- package/dist/utils/lifecycle.d.ts +14 -2
- package/dist/utils/log.d.ts +13 -2
- package/dist/utils/patchWorkflowRunFields.d.ts +27 -4
- package/dist/utils/runContext.d.ts +1 -0
- package/dist/utils/secrets.d.ts +9 -2
- package/dist/utils/setup.d.ts +13 -0
- package/dist/utils/subprocess.d.ts +7 -0
- package/dist/utils/time.d.ts +1 -0
- package/dist/utils/todoTracking.d.ts +3 -1
- package/package.json +3 -2
package/dist/cli.mjs
CHANGED
|
@@ -4293,8 +4293,8 @@ var require_util2 = __commonJS({
|
|
|
4293
4293
|
function createDeferredPromise() {
|
|
4294
4294
|
let res;
|
|
4295
4295
|
let rej;
|
|
4296
|
-
const promise2 = new Promise((
|
|
4297
|
-
res =
|
|
4296
|
+
const promise2 = new Promise((resolve3, reject) => {
|
|
4297
|
+
res = resolve3;
|
|
4298
4298
|
rej = reject;
|
|
4299
4299
|
});
|
|
4300
4300
|
return { promise: promise2, resolve: res, reject: rej };
|
|
@@ -5798,8 +5798,8 @@ Content-Type: ${value2.type || "application/octet-stream"}\r
|
|
|
5798
5798
|
});
|
|
5799
5799
|
}
|
|
5800
5800
|
});
|
|
5801
|
-
const busboyResolve = new Promise((
|
|
5802
|
-
busboy.on("finish",
|
|
5801
|
+
const busboyResolve = new Promise((resolve3, reject) => {
|
|
5802
|
+
busboy.on("finish", resolve3);
|
|
5803
5803
|
busboy.on("error", (err) => reject(new TypeError(err)));
|
|
5804
5804
|
});
|
|
5805
5805
|
if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk);
|
|
@@ -6333,9 +6333,9 @@ var require_dispatcher_base = __commonJS({
|
|
|
6333
6333
|
}
|
|
6334
6334
|
close(callback) {
|
|
6335
6335
|
if (callback === void 0) {
|
|
6336
|
-
return new Promise((
|
|
6336
|
+
return new Promise((resolve3, reject) => {
|
|
6337
6337
|
this.close((err, data) => {
|
|
6338
|
-
return err ? reject(err) :
|
|
6338
|
+
return err ? reject(err) : resolve3(data);
|
|
6339
6339
|
});
|
|
6340
6340
|
});
|
|
6341
6341
|
}
|
|
@@ -6373,12 +6373,12 @@ var require_dispatcher_base = __commonJS({
|
|
|
6373
6373
|
err = null;
|
|
6374
6374
|
}
|
|
6375
6375
|
if (callback === void 0) {
|
|
6376
|
-
return new Promise((
|
|
6376
|
+
return new Promise((resolve3, reject) => {
|
|
6377
6377
|
this.destroy(err, (err2, data) => {
|
|
6378
6378
|
return err2 ? (
|
|
6379
6379
|
/* istanbul ignore next: should never error */
|
|
6380
6380
|
reject(err2)
|
|
6381
|
-
) :
|
|
6381
|
+
) : resolve3(data);
|
|
6382
6382
|
});
|
|
6383
6383
|
});
|
|
6384
6384
|
}
|
|
@@ -7438,16 +7438,16 @@ var require_client = __commonJS({
|
|
|
7438
7438
|
return this[kNeedDrain] < 2;
|
|
7439
7439
|
}
|
|
7440
7440
|
async [kClose]() {
|
|
7441
|
-
return new Promise((
|
|
7441
|
+
return new Promise((resolve3) => {
|
|
7442
7442
|
if (!this[kSize]) {
|
|
7443
|
-
|
|
7443
|
+
resolve3(null);
|
|
7444
7444
|
} else {
|
|
7445
|
-
this[kClosedResolve] =
|
|
7445
|
+
this[kClosedResolve] = resolve3;
|
|
7446
7446
|
}
|
|
7447
7447
|
});
|
|
7448
7448
|
}
|
|
7449
7449
|
async [kDestroy](err) {
|
|
7450
|
-
return new Promise((
|
|
7450
|
+
return new Promise((resolve3) => {
|
|
7451
7451
|
const requests = this[kQueue].splice(this[kPendingIdx]);
|
|
7452
7452
|
for (let i = 0; i < requests.length; i++) {
|
|
7453
7453
|
const request2 = requests[i];
|
|
@@ -7458,7 +7458,7 @@ var require_client = __commonJS({
|
|
|
7458
7458
|
this[kClosedResolve]();
|
|
7459
7459
|
this[kClosedResolve] = null;
|
|
7460
7460
|
}
|
|
7461
|
-
|
|
7461
|
+
resolve3();
|
|
7462
7462
|
};
|
|
7463
7463
|
if (this[kHTTP2Session] != null) {
|
|
7464
7464
|
util2.destroy(this[kHTTP2Session], err);
|
|
@@ -8038,7 +8038,7 @@ var require_client = __commonJS({
|
|
|
8038
8038
|
});
|
|
8039
8039
|
}
|
|
8040
8040
|
try {
|
|
8041
|
-
const socket = await new Promise((
|
|
8041
|
+
const socket = await new Promise((resolve3, reject) => {
|
|
8042
8042
|
client[kConnector]({
|
|
8043
8043
|
host,
|
|
8044
8044
|
hostname: hostname4,
|
|
@@ -8050,7 +8050,7 @@ var require_client = __commonJS({
|
|
|
8050
8050
|
if (err) {
|
|
8051
8051
|
reject(err);
|
|
8052
8052
|
} else {
|
|
8053
|
-
|
|
8053
|
+
resolve3(socket2);
|
|
8054
8054
|
}
|
|
8055
8055
|
});
|
|
8056
8056
|
});
|
|
@@ -8674,12 +8674,12 @@ upgrade: ${upgrade}\r
|
|
|
8674
8674
|
cb();
|
|
8675
8675
|
}
|
|
8676
8676
|
}
|
|
8677
|
-
const waitForDrain = () => new Promise((
|
|
8677
|
+
const waitForDrain = () => new Promise((resolve3, reject) => {
|
|
8678
8678
|
assert3(callback === null);
|
|
8679
8679
|
if (socket[kError]) {
|
|
8680
8680
|
reject(socket[kError]);
|
|
8681
8681
|
} else {
|
|
8682
|
-
callback =
|
|
8682
|
+
callback = resolve3;
|
|
8683
8683
|
}
|
|
8684
8684
|
});
|
|
8685
8685
|
if (client[kHTTPConnVersion] === "h2") {
|
|
@@ -9024,8 +9024,8 @@ var require_pool_base = __commonJS({
|
|
|
9024
9024
|
if (this[kQueue].isEmpty()) {
|
|
9025
9025
|
return Promise.all(this[kClients].map((c2) => c2.close()));
|
|
9026
9026
|
} else {
|
|
9027
|
-
return new Promise((
|
|
9028
|
-
this[kClosedResolve] =
|
|
9027
|
+
return new Promise((resolve3) => {
|
|
9028
|
+
this[kClosedResolve] = resolve3;
|
|
9029
9029
|
});
|
|
9030
9030
|
}
|
|
9031
9031
|
}
|
|
@@ -9603,7 +9603,7 @@ var require_readable = __commonJS({
|
|
|
9603
9603
|
if (this.closed) {
|
|
9604
9604
|
return Promise.resolve(null);
|
|
9605
9605
|
}
|
|
9606
|
-
return new Promise((
|
|
9606
|
+
return new Promise((resolve3, reject) => {
|
|
9607
9607
|
const signalListenerCleanup = signal ? util2.addAbortListener(signal, () => {
|
|
9608
9608
|
this.destroy();
|
|
9609
9609
|
}) : noop4;
|
|
@@ -9612,7 +9612,7 @@ var require_readable = __commonJS({
|
|
|
9612
9612
|
if (signal && signal.aborted) {
|
|
9613
9613
|
reject(signal.reason || Object.assign(new Error("The operation was aborted"), { name: "AbortError" }));
|
|
9614
9614
|
} else {
|
|
9615
|
-
|
|
9615
|
+
resolve3(null);
|
|
9616
9616
|
}
|
|
9617
9617
|
}).on("error", noop4).on("data", function(chunk) {
|
|
9618
9618
|
limit -= chunk.length;
|
|
@@ -9634,11 +9634,11 @@ var require_readable = __commonJS({
|
|
|
9634
9634
|
throw new TypeError("unusable");
|
|
9635
9635
|
}
|
|
9636
9636
|
assert3(!stream[kConsume]);
|
|
9637
|
-
return new Promise((
|
|
9637
|
+
return new Promise((resolve3, reject) => {
|
|
9638
9638
|
stream[kConsume] = {
|
|
9639
9639
|
type: type2,
|
|
9640
9640
|
stream,
|
|
9641
|
-
resolve:
|
|
9641
|
+
resolve: resolve3,
|
|
9642
9642
|
reject,
|
|
9643
9643
|
length: 0,
|
|
9644
9644
|
body: []
|
|
@@ -9673,12 +9673,12 @@ var require_readable = __commonJS({
|
|
|
9673
9673
|
}
|
|
9674
9674
|
}
|
|
9675
9675
|
function consumeEnd(consume2) {
|
|
9676
|
-
const { type: type2, body, resolve:
|
|
9676
|
+
const { type: type2, body, resolve: resolve3, stream, length } = consume2;
|
|
9677
9677
|
try {
|
|
9678
9678
|
if (type2 === "text") {
|
|
9679
|
-
|
|
9679
|
+
resolve3(toUSVString(Buffer.concat(body)));
|
|
9680
9680
|
} else if (type2 === "json") {
|
|
9681
|
-
|
|
9681
|
+
resolve3(JSON.parse(Buffer.concat(body)));
|
|
9682
9682
|
} else if (type2 === "arrayBuffer") {
|
|
9683
9683
|
const dst = new Uint8Array(length);
|
|
9684
9684
|
let pos = 0;
|
|
@@ -9686,12 +9686,12 @@ var require_readable = __commonJS({
|
|
|
9686
9686
|
dst.set(buf, pos);
|
|
9687
9687
|
pos += buf.byteLength;
|
|
9688
9688
|
}
|
|
9689
|
-
|
|
9689
|
+
resolve3(dst.buffer);
|
|
9690
9690
|
} else if (type2 === "blob") {
|
|
9691
9691
|
if (!Blob2) {
|
|
9692
9692
|
Blob2 = __require("buffer").Blob;
|
|
9693
9693
|
}
|
|
9694
|
-
|
|
9694
|
+
resolve3(new Blob2(body, { type: stream[kContentType] }));
|
|
9695
9695
|
}
|
|
9696
9696
|
consumeFinish(consume2);
|
|
9697
9697
|
} catch (err) {
|
|
@@ -9946,9 +9946,9 @@ var require_api_request = __commonJS({
|
|
|
9946
9946
|
};
|
|
9947
9947
|
function request2(opts, callback) {
|
|
9948
9948
|
if (callback === void 0) {
|
|
9949
|
-
return new Promise((
|
|
9949
|
+
return new Promise((resolve3, reject) => {
|
|
9950
9950
|
request2.call(this, opts, (err, data) => {
|
|
9951
|
-
return err ? reject(err) :
|
|
9951
|
+
return err ? reject(err) : resolve3(data);
|
|
9952
9952
|
});
|
|
9953
9953
|
});
|
|
9954
9954
|
}
|
|
@@ -10121,9 +10121,9 @@ var require_api_stream = __commonJS({
|
|
|
10121
10121
|
};
|
|
10122
10122
|
function stream(opts, factory, callback) {
|
|
10123
10123
|
if (callback === void 0) {
|
|
10124
|
-
return new Promise((
|
|
10124
|
+
return new Promise((resolve3, reject) => {
|
|
10125
10125
|
stream.call(this, opts, factory, (err, data) => {
|
|
10126
|
-
return err ? reject(err) :
|
|
10126
|
+
return err ? reject(err) : resolve3(data);
|
|
10127
10127
|
});
|
|
10128
10128
|
});
|
|
10129
10129
|
}
|
|
@@ -10404,9 +10404,9 @@ var require_api_upgrade = __commonJS({
|
|
|
10404
10404
|
};
|
|
10405
10405
|
function upgrade(opts, callback) {
|
|
10406
10406
|
if (callback === void 0) {
|
|
10407
|
-
return new Promise((
|
|
10407
|
+
return new Promise((resolve3, reject) => {
|
|
10408
10408
|
upgrade.call(this, opts, (err, data) => {
|
|
10409
|
-
return err ? reject(err) :
|
|
10409
|
+
return err ? reject(err) : resolve3(data);
|
|
10410
10410
|
});
|
|
10411
10411
|
});
|
|
10412
10412
|
}
|
|
@@ -10495,9 +10495,9 @@ var require_api_connect = __commonJS({
|
|
|
10495
10495
|
};
|
|
10496
10496
|
function connect(opts, callback) {
|
|
10497
10497
|
if (callback === void 0) {
|
|
10498
|
-
return new Promise((
|
|
10498
|
+
return new Promise((resolve3, reject) => {
|
|
10499
10499
|
connect.call(this, opts, (err, data) => {
|
|
10500
|
-
return err ? reject(err) :
|
|
10500
|
+
return err ? reject(err) : resolve3(data);
|
|
10501
10501
|
});
|
|
10502
10502
|
});
|
|
10503
10503
|
}
|
|
@@ -14119,7 +14119,7 @@ var require_fetch = __commonJS({
|
|
|
14119
14119
|
async function dispatch({ body }) {
|
|
14120
14120
|
const url4 = requestCurrentURL(request2);
|
|
14121
14121
|
const agent2 = fetchParams.controller.dispatcher;
|
|
14122
|
-
return new Promise((
|
|
14122
|
+
return new Promise((resolve3, reject) => agent2.dispatch(
|
|
14123
14123
|
{
|
|
14124
14124
|
path: url4.pathname + url4.search,
|
|
14125
14125
|
origin: url4.origin,
|
|
@@ -14195,7 +14195,7 @@ var require_fetch = __commonJS({
|
|
|
14195
14195
|
}
|
|
14196
14196
|
}
|
|
14197
14197
|
}
|
|
14198
|
-
|
|
14198
|
+
resolve3({
|
|
14199
14199
|
status,
|
|
14200
14200
|
statusText,
|
|
14201
14201
|
headersList: headers[kHeadersList],
|
|
@@ -14238,7 +14238,7 @@ var require_fetch = __commonJS({
|
|
|
14238
14238
|
const val = headersList[n + 1].toString("latin1");
|
|
14239
14239
|
headers[kHeadersList].append(key, val);
|
|
14240
14240
|
}
|
|
14241
|
-
|
|
14241
|
+
resolve3({
|
|
14242
14242
|
status,
|
|
14243
14243
|
statusText: STATUS_CODES[status],
|
|
14244
14244
|
headersList: headers[kHeadersList],
|
|
@@ -17592,11 +17592,11 @@ var require_lib = __commonJS({
|
|
|
17592
17592
|
};
|
|
17593
17593
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
17594
17594
|
function adopt(value2) {
|
|
17595
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
17596
|
-
|
|
17595
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
17596
|
+
resolve3(value2);
|
|
17597
17597
|
});
|
|
17598
17598
|
}
|
|
17599
|
-
return new (P3 || (P3 = Promise))(function(
|
|
17599
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
17600
17600
|
function fulfilled(value2) {
|
|
17601
17601
|
try {
|
|
17602
17602
|
step(generator.next(value2));
|
|
@@ -17612,7 +17612,7 @@ var require_lib = __commonJS({
|
|
|
17612
17612
|
}
|
|
17613
17613
|
}
|
|
17614
17614
|
function step(result) {
|
|
17615
|
-
result.done ?
|
|
17615
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
17616
17616
|
}
|
|
17617
17617
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
17618
17618
|
});
|
|
@@ -17698,26 +17698,26 @@ var require_lib = __commonJS({
|
|
|
17698
17698
|
}
|
|
17699
17699
|
readBody() {
|
|
17700
17700
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17701
|
-
return new Promise((
|
|
17701
|
+
return new Promise((resolve3) => __awaiter(this, void 0, void 0, function* () {
|
|
17702
17702
|
let output = Buffer.alloc(0);
|
|
17703
17703
|
this.message.on("data", (chunk) => {
|
|
17704
17704
|
output = Buffer.concat([output, chunk]);
|
|
17705
17705
|
});
|
|
17706
17706
|
this.message.on("end", () => {
|
|
17707
|
-
|
|
17707
|
+
resolve3(output.toString());
|
|
17708
17708
|
});
|
|
17709
17709
|
}));
|
|
17710
17710
|
});
|
|
17711
17711
|
}
|
|
17712
17712
|
readBodyBuffer() {
|
|
17713
17713
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17714
|
-
return new Promise((
|
|
17714
|
+
return new Promise((resolve3) => __awaiter(this, void 0, void 0, function* () {
|
|
17715
17715
|
const chunks = [];
|
|
17716
17716
|
this.message.on("data", (chunk) => {
|
|
17717
17717
|
chunks.push(chunk);
|
|
17718
17718
|
});
|
|
17719
17719
|
this.message.on("end", () => {
|
|
17720
|
-
|
|
17720
|
+
resolve3(Buffer.concat(chunks));
|
|
17721
17721
|
});
|
|
17722
17722
|
}));
|
|
17723
17723
|
});
|
|
@@ -17926,14 +17926,14 @@ var require_lib = __commonJS({
|
|
|
17926
17926
|
*/
|
|
17927
17927
|
requestRaw(info3, data) {
|
|
17928
17928
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17929
|
-
return new Promise((
|
|
17929
|
+
return new Promise((resolve3, reject) => {
|
|
17930
17930
|
function callbackForResult(err, res) {
|
|
17931
17931
|
if (err) {
|
|
17932
17932
|
reject(err);
|
|
17933
17933
|
} else if (!res) {
|
|
17934
17934
|
reject(new Error("Unknown error"));
|
|
17935
17935
|
} else {
|
|
17936
|
-
|
|
17936
|
+
resolve3(res);
|
|
17937
17937
|
}
|
|
17938
17938
|
}
|
|
17939
17939
|
this.requestRawWithCallback(info3, data, callbackForResult);
|
|
@@ -18115,12 +18115,12 @@ var require_lib = __commonJS({
|
|
|
18115
18115
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18116
18116
|
retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber);
|
|
18117
18117
|
const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber);
|
|
18118
|
-
return new Promise((
|
|
18118
|
+
return new Promise((resolve3) => setTimeout(() => resolve3(), ms));
|
|
18119
18119
|
});
|
|
18120
18120
|
}
|
|
18121
18121
|
_processResponse(res, options) {
|
|
18122
18122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18123
|
-
return new Promise((
|
|
18123
|
+
return new Promise((resolve3, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
18124
18124
|
const statusCode = res.message.statusCode || 0;
|
|
18125
18125
|
const response = {
|
|
18126
18126
|
statusCode,
|
|
@@ -18128,7 +18128,7 @@ var require_lib = __commonJS({
|
|
|
18128
18128
|
headers: {}
|
|
18129
18129
|
};
|
|
18130
18130
|
if (statusCode === HttpCodes.NotFound) {
|
|
18131
|
-
|
|
18131
|
+
resolve3(response);
|
|
18132
18132
|
}
|
|
18133
18133
|
function dateTimeDeserializer(key, value2) {
|
|
18134
18134
|
if (typeof value2 === "string") {
|
|
@@ -18167,7 +18167,7 @@ var require_lib = __commonJS({
|
|
|
18167
18167
|
err.result = response.result;
|
|
18168
18168
|
reject(err);
|
|
18169
18169
|
} else {
|
|
18170
|
-
|
|
18170
|
+
resolve3(response);
|
|
18171
18171
|
}
|
|
18172
18172
|
}));
|
|
18173
18173
|
});
|
|
@@ -18184,11 +18184,11 @@ var require_auth = __commonJS({
|
|
|
18184
18184
|
"use strict";
|
|
18185
18185
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
18186
18186
|
function adopt(value2) {
|
|
18187
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
18188
|
-
|
|
18187
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
18188
|
+
resolve3(value2);
|
|
18189
18189
|
});
|
|
18190
18190
|
}
|
|
18191
|
-
return new (P3 || (P3 = Promise))(function(
|
|
18191
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
18192
18192
|
function fulfilled(value2) {
|
|
18193
18193
|
try {
|
|
18194
18194
|
step(generator.next(value2));
|
|
@@ -18204,7 +18204,7 @@ var require_auth = __commonJS({
|
|
|
18204
18204
|
}
|
|
18205
18205
|
}
|
|
18206
18206
|
function step(result) {
|
|
18207
|
-
result.done ?
|
|
18207
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
18208
18208
|
}
|
|
18209
18209
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18210
18210
|
});
|
|
@@ -18288,11 +18288,11 @@ var require_oidc_utils = __commonJS({
|
|
|
18288
18288
|
"use strict";
|
|
18289
18289
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
18290
18290
|
function adopt(value2) {
|
|
18291
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
18292
|
-
|
|
18291
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
18292
|
+
resolve3(value2);
|
|
18293
18293
|
});
|
|
18294
18294
|
}
|
|
18295
|
-
return new (P3 || (P3 = Promise))(function(
|
|
18295
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
18296
18296
|
function fulfilled(value2) {
|
|
18297
18297
|
try {
|
|
18298
18298
|
step(generator.next(value2));
|
|
@@ -18308,7 +18308,7 @@ var require_oidc_utils = __commonJS({
|
|
|
18308
18308
|
}
|
|
18309
18309
|
}
|
|
18310
18310
|
function step(result) {
|
|
18311
|
-
result.done ?
|
|
18311
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
18312
18312
|
}
|
|
18313
18313
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18314
18314
|
});
|
|
@@ -18386,11 +18386,11 @@ var require_summary = __commonJS({
|
|
|
18386
18386
|
"use strict";
|
|
18387
18387
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
18388
18388
|
function adopt(value2) {
|
|
18389
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
18390
|
-
|
|
18389
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
18390
|
+
resolve3(value2);
|
|
18391
18391
|
});
|
|
18392
18392
|
}
|
|
18393
|
-
return new (P3 || (P3 = Promise))(function(
|
|
18393
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
18394
18394
|
function fulfilled(value2) {
|
|
18395
18395
|
try {
|
|
18396
18396
|
step(generator.next(value2));
|
|
@@ -18406,7 +18406,7 @@ var require_summary = __commonJS({
|
|
|
18406
18406
|
}
|
|
18407
18407
|
}
|
|
18408
18408
|
function step(result) {
|
|
18409
|
-
result.done ?
|
|
18409
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
18410
18410
|
}
|
|
18411
18411
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18412
18412
|
});
|
|
@@ -18752,11 +18752,11 @@ var require_io_util = __commonJS({
|
|
|
18752
18752
|
};
|
|
18753
18753
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
18754
18754
|
function adopt(value2) {
|
|
18755
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
18756
|
-
|
|
18755
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
18756
|
+
resolve3(value2);
|
|
18757
18757
|
});
|
|
18758
18758
|
}
|
|
18759
|
-
return new (P3 || (P3 = Promise))(function(
|
|
18759
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
18760
18760
|
function fulfilled(value2) {
|
|
18761
18761
|
try {
|
|
18762
18762
|
step(generator.next(value2));
|
|
@@ -18772,7 +18772,7 @@ var require_io_util = __commonJS({
|
|
|
18772
18772
|
}
|
|
18773
18773
|
}
|
|
18774
18774
|
function step(result) {
|
|
18775
|
-
result.done ?
|
|
18775
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
18776
18776
|
}
|
|
18777
18777
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18778
18778
|
});
|
|
@@ -18925,11 +18925,11 @@ var require_io = __commonJS({
|
|
|
18925
18925
|
};
|
|
18926
18926
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
18927
18927
|
function adopt(value2) {
|
|
18928
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
18929
|
-
|
|
18928
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
18929
|
+
resolve3(value2);
|
|
18930
18930
|
});
|
|
18931
18931
|
}
|
|
18932
|
-
return new (P3 || (P3 = Promise))(function(
|
|
18932
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
18933
18933
|
function fulfilled(value2) {
|
|
18934
18934
|
try {
|
|
18935
18935
|
step(generator.next(value2));
|
|
@@ -18945,7 +18945,7 @@ var require_io = __commonJS({
|
|
|
18945
18945
|
}
|
|
18946
18946
|
}
|
|
18947
18947
|
function step(result) {
|
|
18948
|
-
result.done ?
|
|
18948
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
18949
18949
|
}
|
|
18950
18950
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18951
18951
|
});
|
|
@@ -19173,11 +19173,11 @@ var require_toolrunner = __commonJS({
|
|
|
19173
19173
|
};
|
|
19174
19174
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
19175
19175
|
function adopt(value2) {
|
|
19176
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
19177
|
-
|
|
19176
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
19177
|
+
resolve3(value2);
|
|
19178
19178
|
});
|
|
19179
19179
|
}
|
|
19180
|
-
return new (P3 || (P3 = Promise))(function(
|
|
19180
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
19181
19181
|
function fulfilled(value2) {
|
|
19182
19182
|
try {
|
|
19183
19183
|
step(generator.next(value2));
|
|
@@ -19193,7 +19193,7 @@ var require_toolrunner = __commonJS({
|
|
|
19193
19193
|
}
|
|
19194
19194
|
}
|
|
19195
19195
|
function step(result) {
|
|
19196
|
-
result.done ?
|
|
19196
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
19197
19197
|
}
|
|
19198
19198
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19199
19199
|
});
|
|
@@ -19421,7 +19421,7 @@ var require_toolrunner = __commonJS({
|
|
|
19421
19421
|
this.toolPath = path3.resolve(process.cwd(), this.options.cwd || process.cwd(), this.toolPath);
|
|
19422
19422
|
}
|
|
19423
19423
|
this.toolPath = yield io.which(this.toolPath, true);
|
|
19424
|
-
return new Promise((
|
|
19424
|
+
return new Promise((resolve3, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
19425
19425
|
this._debug(`exec tool: ${this.toolPath}`);
|
|
19426
19426
|
this._debug("arguments:");
|
|
19427
19427
|
for (const arg4 of this.args) {
|
|
@@ -19504,7 +19504,7 @@ var require_toolrunner = __commonJS({
|
|
|
19504
19504
|
if (error49) {
|
|
19505
19505
|
reject(error49);
|
|
19506
19506
|
} else {
|
|
19507
|
-
|
|
19507
|
+
resolve3(exitCode);
|
|
19508
19508
|
}
|
|
19509
19509
|
});
|
|
19510
19510
|
if (this.options.input) {
|
|
@@ -19657,11 +19657,11 @@ var require_exec = __commonJS({
|
|
|
19657
19657
|
};
|
|
19658
19658
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
19659
19659
|
function adopt(value2) {
|
|
19660
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
19661
|
-
|
|
19660
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
19661
|
+
resolve3(value2);
|
|
19662
19662
|
});
|
|
19663
19663
|
}
|
|
19664
|
-
return new (P3 || (P3 = Promise))(function(
|
|
19664
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
19665
19665
|
function fulfilled(value2) {
|
|
19666
19666
|
try {
|
|
19667
19667
|
step(generator.next(value2));
|
|
@@ -19677,7 +19677,7 @@ var require_exec = __commonJS({
|
|
|
19677
19677
|
}
|
|
19678
19678
|
}
|
|
19679
19679
|
function step(result) {
|
|
19680
|
-
result.done ?
|
|
19680
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
19681
19681
|
}
|
|
19682
19682
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19683
19683
|
});
|
|
@@ -19768,11 +19768,11 @@ var require_platform = __commonJS({
|
|
|
19768
19768
|
};
|
|
19769
19769
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
19770
19770
|
function adopt(value2) {
|
|
19771
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
19772
|
-
|
|
19771
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
19772
|
+
resolve3(value2);
|
|
19773
19773
|
});
|
|
19774
19774
|
}
|
|
19775
|
-
return new (P3 || (P3 = Promise))(function(
|
|
19775
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
19776
19776
|
function fulfilled(value2) {
|
|
19777
19777
|
try {
|
|
19778
19778
|
step(generator.next(value2));
|
|
@@ -19788,7 +19788,7 @@ var require_platform = __commonJS({
|
|
|
19788
19788
|
}
|
|
19789
19789
|
}
|
|
19790
19790
|
function step(result) {
|
|
19791
|
-
result.done ?
|
|
19791
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
19792
19792
|
}
|
|
19793
19793
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19794
19794
|
});
|
|
@@ -19887,11 +19887,11 @@ var require_core = __commonJS({
|
|
|
19887
19887
|
};
|
|
19888
19888
|
var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P3, generator) {
|
|
19889
19889
|
function adopt(value2) {
|
|
19890
|
-
return value2 instanceof P3 ? value2 : new P3(function(
|
|
19891
|
-
|
|
19890
|
+
return value2 instanceof P3 ? value2 : new P3(function(resolve3) {
|
|
19891
|
+
resolve3(value2);
|
|
19892
19892
|
});
|
|
19893
19893
|
}
|
|
19894
|
-
return new (P3 || (P3 = Promise))(function(
|
|
19894
|
+
return new (P3 || (P3 = Promise))(function(resolve3, reject) {
|
|
19895
19895
|
function fulfilled(value2) {
|
|
19896
19896
|
try {
|
|
19897
19897
|
step(generator.next(value2));
|
|
@@ -19907,7 +19907,7 @@ var require_core = __commonJS({
|
|
|
19907
19907
|
}
|
|
19908
19908
|
}
|
|
19909
19909
|
function step(result) {
|
|
19910
|
-
result.done ?
|
|
19910
|
+
result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
19911
19911
|
}
|
|
19912
19912
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19913
19913
|
});
|
|
@@ -45598,8 +45598,8 @@ var require_resolve = __commonJS({
|
|
|
45598
45598
|
}
|
|
45599
45599
|
return count;
|
|
45600
45600
|
}
|
|
45601
|
-
function getFullPath(resolver, id = "",
|
|
45602
|
-
if (
|
|
45601
|
+
function getFullPath(resolver, id = "", normalize3) {
|
|
45602
|
+
if (normalize3 !== false)
|
|
45603
45603
|
id = normalizeId(id);
|
|
45604
45604
|
const p2 = resolver.parse(id);
|
|
45605
45605
|
return _getFullPath(resolver, p2);
|
|
@@ -46347,7 +46347,7 @@ var require_compile = __commonJS({
|
|
|
46347
46347
|
const schOrFunc = root.refs[ref];
|
|
46348
46348
|
if (schOrFunc)
|
|
46349
46349
|
return schOrFunc;
|
|
46350
|
-
let _sch =
|
|
46350
|
+
let _sch = resolve3.call(this, root, ref);
|
|
46351
46351
|
if (_sch === void 0) {
|
|
46352
46352
|
const schema2 = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
46353
46353
|
const { schemaId } = this.opts;
|
|
@@ -46374,7 +46374,7 @@ var require_compile = __commonJS({
|
|
|
46374
46374
|
function sameSchemaEnv(s1, s2) {
|
|
46375
46375
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
46376
46376
|
}
|
|
46377
|
-
function
|
|
46377
|
+
function resolve3(root, ref) {
|
|
46378
46378
|
let sch;
|
|
46379
46379
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
46380
46380
|
ref = sch;
|
|
@@ -46939,7 +46939,7 @@ var require_fast_uri = __commonJS({
|
|
|
46939
46939
|
"use strict";
|
|
46940
46940
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils4();
|
|
46941
46941
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
46942
|
-
function
|
|
46942
|
+
function normalize3(uri, options) {
|
|
46943
46943
|
if (typeof uri === "string") {
|
|
46944
46944
|
uri = /** @type {T} */
|
|
46945
46945
|
serialize(parse5(uri, options), options);
|
|
@@ -46949,7 +46949,7 @@ var require_fast_uri = __commonJS({
|
|
|
46949
46949
|
}
|
|
46950
46950
|
return uri;
|
|
46951
46951
|
}
|
|
46952
|
-
function
|
|
46952
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
46953
46953
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
46954
46954
|
const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
46955
46955
|
schemelessOptions.skipEscape = true;
|
|
@@ -47175,8 +47175,8 @@ var require_fast_uri = __commonJS({
|
|
|
47175
47175
|
}
|
|
47176
47176
|
var fastUri = {
|
|
47177
47177
|
SCHEMES,
|
|
47178
|
-
normalize:
|
|
47179
|
-
resolve:
|
|
47178
|
+
normalize: normalize3,
|
|
47179
|
+
resolve: resolve3,
|
|
47180
47180
|
resolveComponent,
|
|
47181
47181
|
equal,
|
|
47182
47182
|
serialize,
|
|
@@ -52752,9 +52752,9 @@ var require_dispatcher_base2 = __commonJS({
|
|
|
52752
52752
|
}
|
|
52753
52753
|
close(callback) {
|
|
52754
52754
|
if (callback === void 0) {
|
|
52755
|
-
return new Promise((
|
|
52755
|
+
return new Promise((resolve3, reject) => {
|
|
52756
52756
|
this.close((err, data) => {
|
|
52757
|
-
return err ? reject(err) :
|
|
52757
|
+
return err ? reject(err) : resolve3(data);
|
|
52758
52758
|
});
|
|
52759
52759
|
});
|
|
52760
52760
|
}
|
|
@@ -52792,9 +52792,9 @@ var require_dispatcher_base2 = __commonJS({
|
|
|
52792
52792
|
err = null;
|
|
52793
52793
|
}
|
|
52794
52794
|
if (callback === void 0) {
|
|
52795
|
-
return new Promise((
|
|
52795
|
+
return new Promise((resolve3, reject) => {
|
|
52796
52796
|
this.destroy(err, (err2, data) => {
|
|
52797
|
-
return err2 ? reject(err2) :
|
|
52797
|
+
return err2 ? reject(err2) : resolve3(data);
|
|
52798
52798
|
});
|
|
52799
52799
|
});
|
|
52800
52800
|
}
|
|
@@ -56270,8 +56270,8 @@ var require_promise = __commonJS({
|
|
|
56270
56270
|
function createDeferredPromise() {
|
|
56271
56271
|
let res;
|
|
56272
56272
|
let rej;
|
|
56273
|
-
const promise2 = new Promise((
|
|
56274
|
-
res =
|
|
56273
|
+
const promise2 = new Promise((resolve3, reject) => {
|
|
56274
|
+
res = resolve3;
|
|
56275
56275
|
rej = reject;
|
|
56276
56276
|
});
|
|
56277
56277
|
return { promise: promise2, resolve: res, reject: rej };
|
|
@@ -57569,12 +57569,12 @@ upgrade: ${upgrade}\r
|
|
|
57569
57569
|
cb();
|
|
57570
57570
|
}
|
|
57571
57571
|
}
|
|
57572
|
-
const waitForDrain = () => new Promise((
|
|
57572
|
+
const waitForDrain = () => new Promise((resolve3, reject) => {
|
|
57573
57573
|
assert3(callback === null);
|
|
57574
57574
|
if (socket[kError]) {
|
|
57575
57575
|
reject(socket[kError]);
|
|
57576
57576
|
} else {
|
|
57577
|
-
callback =
|
|
57577
|
+
callback = resolve3;
|
|
57578
57578
|
}
|
|
57579
57579
|
});
|
|
57580
57580
|
socket.on("close", onDrain).on("drain", onDrain);
|
|
@@ -58415,12 +58415,12 @@ var require_client_h2 = __commonJS({
|
|
|
58415
58415
|
cb();
|
|
58416
58416
|
}
|
|
58417
58417
|
}
|
|
58418
|
-
const waitForDrain = () => new Promise((
|
|
58418
|
+
const waitForDrain = () => new Promise((resolve3, reject) => {
|
|
58419
58419
|
assert3(callback === null);
|
|
58420
58420
|
if (socket[kError]) {
|
|
58421
58421
|
reject(socket[kError]);
|
|
58422
58422
|
} else {
|
|
58423
|
-
callback =
|
|
58423
|
+
callback = resolve3;
|
|
58424
58424
|
}
|
|
58425
58425
|
});
|
|
58426
58426
|
h2stream.on("close", onDrain).on("drain", onDrain);
|
|
@@ -58728,16 +58728,16 @@ var require_client2 = __commonJS({
|
|
|
58728
58728
|
return this[kNeedDrain] < 2;
|
|
58729
58729
|
}
|
|
58730
58730
|
[kClose]() {
|
|
58731
|
-
return new Promise((
|
|
58731
|
+
return new Promise((resolve3) => {
|
|
58732
58732
|
if (this[kSize]) {
|
|
58733
|
-
this[kClosedResolve] =
|
|
58733
|
+
this[kClosedResolve] = resolve3;
|
|
58734
58734
|
} else {
|
|
58735
|
-
|
|
58735
|
+
resolve3(null);
|
|
58736
58736
|
}
|
|
58737
58737
|
});
|
|
58738
58738
|
}
|
|
58739
58739
|
[kDestroy](err) {
|
|
58740
|
-
return new Promise((
|
|
58740
|
+
return new Promise((resolve3) => {
|
|
58741
58741
|
const requests = this[kQueue].splice(this[kPendingIdx]);
|
|
58742
58742
|
for (let i = 0; i < requests.length; i++) {
|
|
58743
58743
|
const request2 = requests[i];
|
|
@@ -58748,7 +58748,7 @@ var require_client2 = __commonJS({
|
|
|
58748
58748
|
this[kClosedResolve]();
|
|
58749
58749
|
this[kClosedResolve] = null;
|
|
58750
58750
|
}
|
|
58751
|
-
|
|
58751
|
+
resolve3(null);
|
|
58752
58752
|
};
|
|
58753
58753
|
if (this[kHTTPContext]) {
|
|
58754
58754
|
this[kHTTPContext].destroy(err, callback);
|
|
@@ -59145,8 +59145,8 @@ var require_pool_base2 = __commonJS({
|
|
|
59145
59145
|
}
|
|
59146
59146
|
return Promise.all(closeAll);
|
|
59147
59147
|
} else {
|
|
59148
|
-
return new Promise((
|
|
59149
|
-
this[kClosedResolve] =
|
|
59148
|
+
return new Promise((resolve3) => {
|
|
59149
|
+
this[kClosedResolve] = resolve3;
|
|
59150
59150
|
});
|
|
59151
59151
|
}
|
|
59152
59152
|
}
|
|
@@ -60675,7 +60675,7 @@ var require_readable2 = __commonJS({
|
|
|
60675
60675
|
if (this._readableState.closeEmitted) {
|
|
60676
60676
|
return Promise.resolve(null);
|
|
60677
60677
|
}
|
|
60678
|
-
return new Promise((
|
|
60678
|
+
return new Promise((resolve3, reject) => {
|
|
60679
60679
|
if (this[kContentLength] && this[kContentLength] > limit || this[kBytesRead] > limit) {
|
|
60680
60680
|
this.destroy(new AbortError2());
|
|
60681
60681
|
}
|
|
@@ -60689,11 +60689,11 @@ var require_readable2 = __commonJS({
|
|
|
60689
60689
|
if (signal.aborted) {
|
|
60690
60690
|
reject(signal.reason ?? new AbortError2());
|
|
60691
60691
|
} else {
|
|
60692
|
-
|
|
60692
|
+
resolve3(null);
|
|
60693
60693
|
}
|
|
60694
60694
|
});
|
|
60695
60695
|
} else {
|
|
60696
|
-
this.on("close",
|
|
60696
|
+
this.on("close", resolve3);
|
|
60697
60697
|
}
|
|
60698
60698
|
this.on("error", noop4).on("data", () => {
|
|
60699
60699
|
if (this[kBytesRead] > limit) {
|
|
@@ -60721,7 +60721,7 @@ var require_readable2 = __commonJS({
|
|
|
60721
60721
|
}
|
|
60722
60722
|
function consume(stream, type2) {
|
|
60723
60723
|
assert3(!stream[kConsume]);
|
|
60724
|
-
return new Promise((
|
|
60724
|
+
return new Promise((resolve3, reject) => {
|
|
60725
60725
|
if (isUnusable(stream)) {
|
|
60726
60726
|
const rState = stream._readableState;
|
|
60727
60727
|
if (rState.destroyed && rState.closeEmitted === false) {
|
|
@@ -60736,7 +60736,7 @@ var require_readable2 = __commonJS({
|
|
|
60736
60736
|
stream[kConsume] = {
|
|
60737
60737
|
type: type2,
|
|
60738
60738
|
stream,
|
|
60739
|
-
resolve:
|
|
60739
|
+
resolve: resolve3,
|
|
60740
60740
|
reject,
|
|
60741
60741
|
length: 0,
|
|
60742
60742
|
body: []
|
|
@@ -60810,18 +60810,18 @@ var require_readable2 = __commonJS({
|
|
|
60810
60810
|
return buffer;
|
|
60811
60811
|
}
|
|
60812
60812
|
function consumeEnd(consume2, encoding) {
|
|
60813
|
-
const { type: type2, body, resolve:
|
|
60813
|
+
const { type: type2, body, resolve: resolve3, stream, length } = consume2;
|
|
60814
60814
|
try {
|
|
60815
60815
|
if (type2 === "text") {
|
|
60816
|
-
|
|
60816
|
+
resolve3(chunksDecode(body, length, encoding));
|
|
60817
60817
|
} else if (type2 === "json") {
|
|
60818
|
-
|
|
60818
|
+
resolve3(JSON.parse(chunksDecode(body, length, encoding)));
|
|
60819
60819
|
} else if (type2 === "arrayBuffer") {
|
|
60820
|
-
|
|
60820
|
+
resolve3(chunksConcat(body, length).buffer);
|
|
60821
60821
|
} else if (type2 === "blob") {
|
|
60822
|
-
|
|
60822
|
+
resolve3(new Blob(body, { type: stream[kContentType] }));
|
|
60823
60823
|
} else if (type2 === "bytes") {
|
|
60824
|
-
|
|
60824
|
+
resolve3(chunksConcat(body, length));
|
|
60825
60825
|
}
|
|
60826
60826
|
consumeFinish(consume2);
|
|
60827
60827
|
} catch (err) {
|
|
@@ -61011,9 +61011,9 @@ var require_api_request2 = __commonJS({
|
|
|
61011
61011
|
};
|
|
61012
61012
|
function request2(opts, callback) {
|
|
61013
61013
|
if (callback === void 0) {
|
|
61014
|
-
return new Promise((
|
|
61014
|
+
return new Promise((resolve3, reject) => {
|
|
61015
61015
|
request2.call(this, opts, (err, data) => {
|
|
61016
|
-
return err ? reject(err) :
|
|
61016
|
+
return err ? reject(err) : resolve3(data);
|
|
61017
61017
|
});
|
|
61018
61018
|
});
|
|
61019
61019
|
}
|
|
@@ -61225,9 +61225,9 @@ var require_api_stream2 = __commonJS({
|
|
|
61225
61225
|
};
|
|
61226
61226
|
function stream(opts, factory, callback) {
|
|
61227
61227
|
if (callback === void 0) {
|
|
61228
|
-
return new Promise((
|
|
61228
|
+
return new Promise((resolve3, reject) => {
|
|
61229
61229
|
stream.call(this, opts, factory, (err, data) => {
|
|
61230
|
-
return err ? reject(err) :
|
|
61230
|
+
return err ? reject(err) : resolve3(data);
|
|
61231
61231
|
});
|
|
61232
61232
|
});
|
|
61233
61233
|
}
|
|
@@ -61515,9 +61515,9 @@ var require_api_upgrade2 = __commonJS({
|
|
|
61515
61515
|
};
|
|
61516
61516
|
function upgrade(opts, callback) {
|
|
61517
61517
|
if (callback === void 0) {
|
|
61518
|
-
return new Promise((
|
|
61518
|
+
return new Promise((resolve3, reject) => {
|
|
61519
61519
|
upgrade.call(this, opts, (err, data) => {
|
|
61520
|
-
return err ? reject(err) :
|
|
61520
|
+
return err ? reject(err) : resolve3(data);
|
|
61521
61521
|
});
|
|
61522
61522
|
});
|
|
61523
61523
|
}
|
|
@@ -61610,9 +61610,9 @@ var require_api_connect2 = __commonJS({
|
|
|
61610
61610
|
};
|
|
61611
61611
|
function connect(opts, callback) {
|
|
61612
61612
|
if (callback === void 0) {
|
|
61613
|
-
return new Promise((
|
|
61613
|
+
return new Promise((resolve3, reject) => {
|
|
61614
61614
|
connect.call(this, opts, (err, data) => {
|
|
61615
|
-
return err ? reject(err) :
|
|
61615
|
+
return err ? reject(err) : resolve3(data);
|
|
61616
61616
|
});
|
|
61617
61617
|
});
|
|
61618
61618
|
}
|
|
@@ -62880,7 +62880,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
62880
62880
|
"node_modules/.pnpm/undici@7.22.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
|
|
62881
62881
|
"use strict";
|
|
62882
62882
|
var { writeFile: writeFile2, readFile, mkdir } = __require("node:fs/promises");
|
|
62883
|
-
var { dirname: dirname4, resolve:
|
|
62883
|
+
var { dirname: dirname4, resolve: resolve3 } = __require("node:path");
|
|
62884
62884
|
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
|
|
62885
62885
|
var { InvalidArgumentError, UndiciError } = require_errors4();
|
|
62886
62886
|
var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
|
|
@@ -63081,7 +63081,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63081
63081
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
63082
63082
|
}
|
|
63083
63083
|
try {
|
|
63084
|
-
const data = await readFile(
|
|
63084
|
+
const data = await readFile(resolve3(path3), "utf8");
|
|
63085
63085
|
const parsed2 = JSON.parse(data);
|
|
63086
63086
|
if (Array.isArray(parsed2)) {
|
|
63087
63087
|
this.#snapshots.clear();
|
|
@@ -63110,7 +63110,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
63110
63110
|
if (!path3) {
|
|
63111
63111
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
63112
63112
|
}
|
|
63113
|
-
const resolvedPath =
|
|
63113
|
+
const resolvedPath = resolve3(path3);
|
|
63114
63114
|
await mkdir(dirname4(resolvedPath), { recursive: true });
|
|
63115
63115
|
const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot2]) => ({
|
|
63116
63116
|
hash: hash2,
|
|
@@ -69687,7 +69687,7 @@ var require_fetch2 = __commonJS({
|
|
|
69687
69687
|
function dispatch({ body }) {
|
|
69688
69688
|
const url4 = requestCurrentURL(request2);
|
|
69689
69689
|
const agent2 = fetchParams.controller.dispatcher;
|
|
69690
|
-
return new Promise((
|
|
69690
|
+
return new Promise((resolve3, reject) => agent2.dispatch(
|
|
69691
69691
|
{
|
|
69692
69692
|
path: url4.pathname + url4.search,
|
|
69693
69693
|
origin: url4.origin,
|
|
@@ -69767,7 +69767,7 @@ var require_fetch2 = __commonJS({
|
|
|
69767
69767
|
}
|
|
69768
69768
|
}
|
|
69769
69769
|
const onError = this.onError.bind(this);
|
|
69770
|
-
|
|
69770
|
+
resolve3({
|
|
69771
69771
|
status,
|
|
69772
69772
|
statusText,
|
|
69773
69773
|
headersList,
|
|
@@ -69820,7 +69820,7 @@ var require_fetch2 = __commonJS({
|
|
|
69820
69820
|
headersList.append(headerName, String(value2), true);
|
|
69821
69821
|
}
|
|
69822
69822
|
}
|
|
69823
|
-
|
|
69823
|
+
resolve3({
|
|
69824
69824
|
status,
|
|
69825
69825
|
statusText: STATUS_CODES[status],
|
|
69826
69826
|
headersList,
|
|
@@ -69836,7 +69836,7 @@ var require_fetch2 = __commonJS({
|
|
|
69836
69836
|
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
69837
69837
|
headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString("latin1"), true);
|
|
69838
69838
|
}
|
|
69839
|
-
|
|
69839
|
+
resolve3({
|
|
69840
69840
|
status,
|
|
69841
69841
|
statusText: STATUS_CODES[status],
|
|
69842
69842
|
headersList,
|
|
@@ -98178,8 +98178,8 @@ var require_light = __commonJS({
|
|
|
98178
98178
|
return this.Promise.resolve();
|
|
98179
98179
|
}
|
|
98180
98180
|
yieldLoop(t2 = 0) {
|
|
98181
|
-
return new this.Promise(function(
|
|
98182
|
-
return setTimeout(
|
|
98181
|
+
return new this.Promise(function(resolve3, reject) {
|
|
98182
|
+
return setTimeout(resolve3, t2);
|
|
98183
98183
|
});
|
|
98184
98184
|
}
|
|
98185
98185
|
computePenalty() {
|
|
@@ -98390,15 +98390,15 @@ var require_light = __commonJS({
|
|
|
98390
98390
|
return this._queue.length === 0;
|
|
98391
98391
|
}
|
|
98392
98392
|
async _tryToRun() {
|
|
98393
|
-
var args2, cb, error49, reject,
|
|
98393
|
+
var args2, cb, error49, reject, resolve3, returned, task;
|
|
98394
98394
|
if (this._running < 1 && this._queue.length > 0) {
|
|
98395
98395
|
this._running++;
|
|
98396
|
-
({ task, args: args2, resolve:
|
|
98396
|
+
({ task, args: args2, resolve: resolve3, reject } = this._queue.shift());
|
|
98397
98397
|
cb = await (async function() {
|
|
98398
98398
|
try {
|
|
98399
98399
|
returned = await task(...args2);
|
|
98400
98400
|
return function() {
|
|
98401
|
-
return
|
|
98401
|
+
return resolve3(returned);
|
|
98402
98402
|
};
|
|
98403
98403
|
} catch (error1) {
|
|
98404
98404
|
error49 = error1;
|
|
@@ -98413,13 +98413,13 @@ var require_light = __commonJS({
|
|
|
98413
98413
|
}
|
|
98414
98414
|
}
|
|
98415
98415
|
schedule(task, ...args2) {
|
|
98416
|
-
var promise2, reject,
|
|
98417
|
-
|
|
98416
|
+
var promise2, reject, resolve3;
|
|
98417
|
+
resolve3 = reject = null;
|
|
98418
98418
|
promise2 = new this.Promise(function(_resolve, _reject) {
|
|
98419
|
-
|
|
98419
|
+
resolve3 = _resolve;
|
|
98420
98420
|
return reject = _reject;
|
|
98421
98421
|
});
|
|
98422
|
-
this._queue.push({ task, args: args2, resolve:
|
|
98422
|
+
this._queue.push({ task, args: args2, resolve: resolve3, reject });
|
|
98423
98423
|
this._tryToRun();
|
|
98424
98424
|
return promise2;
|
|
98425
98425
|
}
|
|
@@ -98820,14 +98820,14 @@ var require_light = __commonJS({
|
|
|
98820
98820
|
counts = this._states.counts;
|
|
98821
98821
|
return counts[0] + counts[1] + counts[2] + counts[3] === at2;
|
|
98822
98822
|
};
|
|
98823
|
-
return new this.Promise((
|
|
98823
|
+
return new this.Promise((resolve3, reject) => {
|
|
98824
98824
|
if (finished()) {
|
|
98825
|
-
return
|
|
98825
|
+
return resolve3();
|
|
98826
98826
|
} else {
|
|
98827
98827
|
return this.on("done", () => {
|
|
98828
98828
|
if (finished()) {
|
|
98829
98829
|
this.removeAllListeners("done");
|
|
98830
|
-
return
|
|
98830
|
+
return resolve3();
|
|
98831
98831
|
}
|
|
98832
98832
|
});
|
|
98833
98833
|
}
|
|
@@ -98920,9 +98920,9 @@ var require_light = __commonJS({
|
|
|
98920
98920
|
options = parser$5.load(options, this.jobDefaults);
|
|
98921
98921
|
}
|
|
98922
98922
|
task = (...args3) => {
|
|
98923
|
-
return new this.Promise(function(
|
|
98923
|
+
return new this.Promise(function(resolve3, reject) {
|
|
98924
98924
|
return fn2(...args3, function(...args4) {
|
|
98925
|
-
return (args4[0] != null ? reject :
|
|
98925
|
+
return (args4[0] != null ? reject : resolve3)(args4);
|
|
98926
98926
|
});
|
|
98927
98927
|
});
|
|
98928
98928
|
};
|
|
@@ -105528,10 +105528,10 @@ var BaseScope = class {
|
|
|
105528
105528
|
});
|
|
105529
105529
|
};
|
|
105530
105530
|
lazyResolutions = [];
|
|
105531
|
-
lazilyResolve(
|
|
105531
|
+
lazilyResolve(resolve3, syntheticAlias) {
|
|
105532
105532
|
const node2 = this.node("alias", {
|
|
105533
105533
|
reference: syntheticAlias ?? "synthetic",
|
|
105534
|
-
resolve:
|
|
105534
|
+
resolve: resolve3
|
|
105535
105535
|
}, { prereduced: true });
|
|
105536
105536
|
if (!this.resolved)
|
|
105537
105537
|
this.lazyResolutions.push(node2);
|
|
@@ -107681,6 +107681,81 @@ var core = __toESM(require_core(), 1);
|
|
|
107681
107681
|
var import_table = __toESM(require_src(), 1);
|
|
107682
107682
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
107683
107683
|
|
|
107684
|
+
// agents/shared.ts
|
|
107685
|
+
import { execFileSync } from "node:child_process";
|
|
107686
|
+
var MAX_STDERR_LINES = 20;
|
|
107687
|
+
var MAX_COMMIT_RETRIES = 3;
|
|
107688
|
+
function getGitStatus() {
|
|
107689
|
+
try {
|
|
107690
|
+
return execFileSync("git", ["status", "--porcelain"], {
|
|
107691
|
+
encoding: "utf-8",
|
|
107692
|
+
timeout: 1e4
|
|
107693
|
+
}).trim();
|
|
107694
|
+
} catch {
|
|
107695
|
+
return "";
|
|
107696
|
+
}
|
|
107697
|
+
}
|
|
107698
|
+
function buildCommitPrompt(_agentId, status) {
|
|
107699
|
+
return [
|
|
107700
|
+
`UNCOMMITTED CHANGES \u2014 the working tree is dirty. push all changes to a pull request (new or existing). \`git status\` must be clean before you finish.`,
|
|
107701
|
+
"",
|
|
107702
|
+
"```",
|
|
107703
|
+
status,
|
|
107704
|
+
"```"
|
|
107705
|
+
].join("\n");
|
|
107706
|
+
}
|
|
107707
|
+
var agent = (input) => {
|
|
107708
|
+
return {
|
|
107709
|
+
...input,
|
|
107710
|
+
run: async (ctx) => {
|
|
107711
|
+
log.debug(`\xBB payload: ${JSON.stringify(ctx.payload, null, 2)}`);
|
|
107712
|
+
return input.run(ctx);
|
|
107713
|
+
}
|
|
107714
|
+
};
|
|
107715
|
+
};
|
|
107716
|
+
function formatCostUsd(costUsd) {
|
|
107717
|
+
return costUsd.toFixed(4);
|
|
107718
|
+
}
|
|
107719
|
+
function mergeAgentUsage(a, b) {
|
|
107720
|
+
if (!a && !b) return void 0;
|
|
107721
|
+
if (!a) return { ...b };
|
|
107722
|
+
if (!b) return { ...a };
|
|
107723
|
+
const cacheRead = (a.cacheReadTokens ?? 0) + (b.cacheReadTokens ?? 0);
|
|
107724
|
+
const cacheWrite = (a.cacheWriteTokens ?? 0) + (b.cacheWriteTokens ?? 0);
|
|
107725
|
+
const cost = (a.costUsd ?? 0) + (b.costUsd ?? 0);
|
|
107726
|
+
return {
|
|
107727
|
+
agent: a.agent,
|
|
107728
|
+
inputTokens: a.inputTokens + b.inputTokens,
|
|
107729
|
+
outputTokens: a.outputTokens + b.outputTokens,
|
|
107730
|
+
cacheReadTokens: cacheRead > 0 ? cacheRead : void 0,
|
|
107731
|
+
cacheWriteTokens: cacheWrite > 0 ? cacheWrite : void 0,
|
|
107732
|
+
costUsd: cost > 0 ? cost : void 0
|
|
107733
|
+
};
|
|
107734
|
+
}
|
|
107735
|
+
function logTokenTable(t2) {
|
|
107736
|
+
const total = t2.input + t2.cacheRead + t2.cacheWrite + t2.output;
|
|
107737
|
+
const costUsd = typeof t2.costUsd === "number" && t2.costUsd > 0 ? t2.costUsd : void 0;
|
|
107738
|
+
const headerRow = [
|
|
107739
|
+
{ data: "Input", header: true },
|
|
107740
|
+
{ data: "Cache Read", header: true },
|
|
107741
|
+
{ data: "Cache Write", header: true },
|
|
107742
|
+
{ data: "Output", header: true },
|
|
107743
|
+
{ data: "Total", header: true }
|
|
107744
|
+
];
|
|
107745
|
+
const dataRow = [
|
|
107746
|
+
String(t2.input),
|
|
107747
|
+
String(t2.cacheRead),
|
|
107748
|
+
String(t2.cacheWrite),
|
|
107749
|
+
String(t2.output),
|
|
107750
|
+
String(total)
|
|
107751
|
+
];
|
|
107752
|
+
if (costUsd !== void 0) {
|
|
107753
|
+
headerRow.push({ data: "Cost ($)", header: true });
|
|
107754
|
+
dataRow.push(formatCostUsd(costUsd));
|
|
107755
|
+
}
|
|
107756
|
+
log.table([headerRow, dataRow]);
|
|
107757
|
+
}
|
|
107758
|
+
|
|
107684
107759
|
// utils/globals.ts
|
|
107685
107760
|
import { existsSync } from "node:fs";
|
|
107686
107761
|
var isCloudflareSandbox = !!process.env.CLOUDFLARE_APPLICATION_ID && !!process.env.SANDBOX_VERSION;
|
|
@@ -107877,20 +107952,26 @@ function formatJsonValue(value2) {
|
|
|
107877
107952
|
}
|
|
107878
107953
|
function formatUsageSummary(entries) {
|
|
107879
107954
|
if (entries.length === 0) return "";
|
|
107880
|
-
const header = "| Agent | Input |
|
|
107881
|
-
const separatorRow = "| --- | ---: | ---: | ---: | ---: |";
|
|
107955
|
+
const header = "| Agent | Input | Cache Read | Cache Write | Output | Total | Cost ($) |";
|
|
107956
|
+
const separatorRow = "| --- | ---: | ---: | ---: | ---: | ---: | ---: |";
|
|
107882
107957
|
const fmt = (n) => n.toLocaleString("en-US");
|
|
107958
|
+
const nonCachedInput = (e) => Math.max(0, e.inputTokens - (e.cacheReadTokens ?? 0) - (e.cacheWriteTokens ?? 0));
|
|
107959
|
+
const totalFor = (e) => nonCachedInput(e) + (e.cacheReadTokens ?? 0) + (e.cacheWriteTokens ?? 0) + e.outputTokens;
|
|
107960
|
+
const costCell = (e) => typeof e.costUsd === "number" && e.costUsd > 0 ? formatCostUsd(e.costUsd) : "\u2014";
|
|
107883
107961
|
const rows = entries.map(
|
|
107884
|
-
(e) => `| ${e.agent} | ${fmt(e
|
|
107962
|
+
(e) => `| ${e.agent} | ${fmt(nonCachedInput(e))} | ${fmt(e.cacheReadTokens ?? 0)} | ${fmt(e.cacheWriteTokens ?? 0)} | ${fmt(e.outputTokens)} | ${fmt(totalFor(e))} | ${costCell(e)} |`
|
|
107885
107963
|
);
|
|
107886
107964
|
const totalsRows = [];
|
|
107887
107965
|
if (entries.length > 1) {
|
|
107888
|
-
const totalInput = entries.reduce((sum, e) => sum + e
|
|
107966
|
+
const totalInput = entries.reduce((sum, e) => sum + nonCachedInput(e), 0);
|
|
107889
107967
|
const totalOutput = entries.reduce((sum, e) => sum + e.outputTokens, 0);
|
|
107890
107968
|
const totalCacheRead = entries.reduce((sum, e) => sum + (e.cacheReadTokens ?? 0), 0);
|
|
107891
107969
|
const totalCacheWrite = entries.reduce((sum, e) => sum + (e.cacheWriteTokens ?? 0), 0);
|
|
107970
|
+
const grandTotal = totalInput + totalCacheRead + totalCacheWrite + totalOutput;
|
|
107971
|
+
const totalCostUsd = entries.reduce((sum, e) => sum + (e.costUsd ?? 0), 0);
|
|
107972
|
+
const totalCostCell = totalCostUsd > 0 ? `**${formatCostUsd(totalCostUsd)}**` : "\u2014";
|
|
107892
107973
|
totalsRows.push(
|
|
107893
|
-
`| **Total** | **${fmt(totalInput)}** | **${fmt(
|
|
107974
|
+
`| **Total** | **${fmt(totalInput)}** | **${fmt(totalCacheRead)}** | **${fmt(totalCacheWrite)}** | **${fmt(totalOutput)}** | **${fmt(grandTotal)}** | ${totalCostCell} |`
|
|
107894
107975
|
);
|
|
107895
107976
|
}
|
|
107896
107977
|
return [
|
|
@@ -107933,7 +108014,7 @@ var providers = {
|
|
|
107933
108014
|
models: {
|
|
107934
108015
|
"claude-opus": {
|
|
107935
108016
|
displayName: "Claude Opus",
|
|
107936
|
-
resolve: "anthropic/claude-opus-4-
|
|
108017
|
+
resolve: "anthropic/claude-opus-4-7",
|
|
107937
108018
|
openRouterResolve: "openrouter/anthropic/claude-opus-4.6",
|
|
107938
108019
|
preferred: true
|
|
107939
108020
|
},
|
|
@@ -107961,7 +108042,7 @@ var providers = {
|
|
|
107961
108042
|
},
|
|
107962
108043
|
"gpt-codex-mini": {
|
|
107963
108044
|
displayName: "GPT Codex Mini",
|
|
107964
|
-
resolve: "openai/codex-mini
|
|
108045
|
+
resolve: "openai/gpt-5.1-codex-mini",
|
|
107965
108046
|
openRouterResolve: "openrouter/openai/gpt-5.1-codex-mini"
|
|
107966
108047
|
},
|
|
107967
108048
|
o3: {
|
|
@@ -108051,7 +108132,7 @@ var providers = {
|
|
|
108051
108132
|
},
|
|
108052
108133
|
"claude-opus": {
|
|
108053
108134
|
displayName: "Claude Opus",
|
|
108054
|
-
resolve: "opencode/claude-opus-4-
|
|
108135
|
+
resolve: "opencode/claude-opus-4-7",
|
|
108055
108136
|
openRouterResolve: "openrouter/anthropic/claude-opus-4.6"
|
|
108056
108137
|
},
|
|
108057
108138
|
"claude-sonnet": {
|
|
@@ -108329,22 +108410,35 @@ async function retry(fn2, options = {}) {
|
|
|
108329
108410
|
}
|
|
108330
108411
|
|
|
108331
108412
|
// utils/patchWorkflowRunFields.ts
|
|
108332
|
-
var
|
|
108413
|
+
var STRING_KEYS = [
|
|
108333
108414
|
"prNodeId",
|
|
108334
108415
|
"issueNodeId",
|
|
108335
108416
|
"reviewNodeId",
|
|
108336
108417
|
"planCommentNodeId",
|
|
108337
108418
|
"summaryCommentNodeId"
|
|
108338
108419
|
];
|
|
108420
|
+
var NUMBER_KEYS = [
|
|
108421
|
+
"inputTokens",
|
|
108422
|
+
"outputTokens",
|
|
108423
|
+
"cacheReadTokens",
|
|
108424
|
+
"cacheWriteTokens",
|
|
108425
|
+
"costUsd"
|
|
108426
|
+
];
|
|
108339
108427
|
async function patchWorkflowRunFields(ctx, fields) {
|
|
108340
108428
|
if (ctx.runId === void 0 || !ctx.apiToken) return;
|
|
108341
108429
|
const body = {};
|
|
108342
|
-
for (const key of
|
|
108430
|
+
for (const key of STRING_KEYS) {
|
|
108343
108431
|
const value2 = fields[key];
|
|
108344
108432
|
if (typeof value2 === "string" && value2.length > 0) {
|
|
108345
108433
|
body[key] = value2;
|
|
108346
108434
|
}
|
|
108347
108435
|
}
|
|
108436
|
+
for (const key of NUMBER_KEYS) {
|
|
108437
|
+
const value2 = fields[key];
|
|
108438
|
+
if (typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0) {
|
|
108439
|
+
body[key] = value2;
|
|
108440
|
+
}
|
|
108441
|
+
}
|
|
108348
108442
|
if (Object.keys(body).length === 0) return;
|
|
108349
108443
|
try {
|
|
108350
108444
|
await retry(
|
|
@@ -108371,6 +108465,38 @@ async function patchWorkflowRunFields(ctx, fields) {
|
|
|
108371
108465
|
log.warning(`patchWorkflowRunFields exhausted retries: ${error49}`);
|
|
108372
108466
|
}
|
|
108373
108467
|
}
|
|
108468
|
+
var INT4_MAX = 2147483647;
|
|
108469
|
+
function clampInt(value2, field) {
|
|
108470
|
+
if (value2 > INT4_MAX) {
|
|
108471
|
+
log.warning(
|
|
108472
|
+
`aggregateUsage: ${field}=${value2} exceeds INT4_MAX (${INT4_MAX}) \u2014 clamping so the rest of the usage row still persists.`
|
|
108473
|
+
);
|
|
108474
|
+
return INT4_MAX;
|
|
108475
|
+
}
|
|
108476
|
+
return value2;
|
|
108477
|
+
}
|
|
108478
|
+
function aggregateUsage(entries) {
|
|
108479
|
+
if (entries.length === 0) return {};
|
|
108480
|
+
const sum = entries.reduce(
|
|
108481
|
+
(acc, e) => ({
|
|
108482
|
+
inputTokens: acc.inputTokens + e.inputTokens,
|
|
108483
|
+
outputTokens: acc.outputTokens + e.outputTokens,
|
|
108484
|
+
cacheReadTokens: acc.cacheReadTokens + (e.cacheReadTokens ?? 0),
|
|
108485
|
+
cacheWriteTokens: acc.cacheWriteTokens + (e.cacheWriteTokens ?? 0),
|
|
108486
|
+
costUsd: acc.costUsd + (e.costUsd ?? 0)
|
|
108487
|
+
}),
|
|
108488
|
+
{ inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costUsd: 0 }
|
|
108489
|
+
);
|
|
108490
|
+
const out = {};
|
|
108491
|
+
if (sum.inputTokens > 0) out.inputTokens = clampInt(sum.inputTokens, "inputTokens");
|
|
108492
|
+
if (sum.outputTokens > 0) out.outputTokens = clampInt(sum.outputTokens, "outputTokens");
|
|
108493
|
+
if (sum.cacheReadTokens > 0)
|
|
108494
|
+
out.cacheReadTokens = clampInt(sum.cacheReadTokens, "cacheReadTokens");
|
|
108495
|
+
if (sum.cacheWriteTokens > 0)
|
|
108496
|
+
out.cacheWriteTokens = clampInt(sum.cacheWriteTokens, "cacheWriteTokens");
|
|
108497
|
+
if (sum.costUsd > 0) out.costUsd = sum.costUsd;
|
|
108498
|
+
return out;
|
|
108499
|
+
}
|
|
108374
108500
|
|
|
108375
108501
|
// node_modules/.pnpm/@toon-format+toon@1.4.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
108376
108502
|
var LIST_ITEM_MARKER = "-";
|
|
@@ -108727,6 +108853,126 @@ function resolveOptions(options) {
|
|
|
108727
108853
|
};
|
|
108728
108854
|
}
|
|
108729
108855
|
|
|
108856
|
+
// mcp/geminiSanitizer.ts
|
|
108857
|
+
function parseStringEnumBranch(item) {
|
|
108858
|
+
if (!item || typeof item !== "object") return null;
|
|
108859
|
+
const record3 = item;
|
|
108860
|
+
if (Array.isArray(record3.enum)) {
|
|
108861
|
+
const strings = record3.enum.filter((v) => typeof v === "string");
|
|
108862
|
+
return strings.length === record3.enum.length && strings.length > 0 ? { values: strings } : null;
|
|
108863
|
+
}
|
|
108864
|
+
if (typeof record3.const === "string") {
|
|
108865
|
+
return { values: [record3.const] };
|
|
108866
|
+
}
|
|
108867
|
+
return null;
|
|
108868
|
+
}
|
|
108869
|
+
function collapseStringUnion(branches) {
|
|
108870
|
+
const values = [];
|
|
108871
|
+
for (const item of branches) {
|
|
108872
|
+
const parsed2 = parseStringEnumBranch(item);
|
|
108873
|
+
if (!parsed2) return null;
|
|
108874
|
+
values.push(...parsed2.values);
|
|
108875
|
+
}
|
|
108876
|
+
if (values.length === 0) return null;
|
|
108877
|
+
return { type: "string", enum: [...new Set(values)] };
|
|
108878
|
+
}
|
|
108879
|
+
function sanitizeForGemini(schema2) {
|
|
108880
|
+
if (!schema2 || typeof schema2 !== "object") return schema2;
|
|
108881
|
+
if (Array.isArray(schema2)) return schema2.map(sanitizeForGemini);
|
|
108882
|
+
const source = schema2;
|
|
108883
|
+
if (Array.isArray(source.enum) && typeof source.type !== "string") {
|
|
108884
|
+
const allStrings = source.enum.every((v) => typeof v === "string");
|
|
108885
|
+
if (allStrings) {
|
|
108886
|
+
const result = { type: "string", enum: source.enum };
|
|
108887
|
+
if (typeof source.description === "string") result.description = source.description;
|
|
108888
|
+
return result;
|
|
108889
|
+
}
|
|
108890
|
+
}
|
|
108891
|
+
for (const unionKey of ["anyOf", "oneOf"]) {
|
|
108892
|
+
const branches = source[unionKey];
|
|
108893
|
+
if (Array.isArray(branches) && branches.length > 0) {
|
|
108894
|
+
const collapsed = collapseStringUnion(branches);
|
|
108895
|
+
if (collapsed) {
|
|
108896
|
+
const result = { ...collapsed };
|
|
108897
|
+
if (typeof source.description === "string") result.description = source.description;
|
|
108898
|
+
return result;
|
|
108899
|
+
}
|
|
108900
|
+
}
|
|
108901
|
+
}
|
|
108902
|
+
if (Array.isArray(source.anyOf) || Array.isArray(source.oneOf)) {
|
|
108903
|
+
const result = {};
|
|
108904
|
+
if (Array.isArray(source.anyOf)) result.anyOf = source.anyOf.map(sanitizeForGemini);
|
|
108905
|
+
if (Array.isArray(source.oneOf)) result.oneOf = source.oneOf.map(sanitizeForGemini);
|
|
108906
|
+
return result;
|
|
108907
|
+
}
|
|
108908
|
+
const sanitized = {};
|
|
108909
|
+
for (const [key, value2] of Object.entries(source)) {
|
|
108910
|
+
if (key === "$schema") continue;
|
|
108911
|
+
if (key === "$defs") {
|
|
108912
|
+
sanitized.definitions = sanitizeForGemini(value2);
|
|
108913
|
+
continue;
|
|
108914
|
+
}
|
|
108915
|
+
sanitized[key] = sanitizeForGemini(value2);
|
|
108916
|
+
}
|
|
108917
|
+
return sanitized;
|
|
108918
|
+
}
|
|
108919
|
+
function wrapJsonSchemaProducer(producer) {
|
|
108920
|
+
return new Proxy(producer, {
|
|
108921
|
+
get(target, prop, receiver) {
|
|
108922
|
+
const value2 = Reflect.get(target, prop, receiver);
|
|
108923
|
+
if ((prop === "input" || prop === "output") && typeof value2 === "function") {
|
|
108924
|
+
const fn2 = value2;
|
|
108925
|
+
return (...args2) => sanitizeForGemini(fn2.apply(target, args2));
|
|
108926
|
+
}
|
|
108927
|
+
return value2;
|
|
108928
|
+
}
|
|
108929
|
+
});
|
|
108930
|
+
}
|
|
108931
|
+
function wrapStandard(standard) {
|
|
108932
|
+
return new Proxy(standard, {
|
|
108933
|
+
get(target, prop, receiver) {
|
|
108934
|
+
if (prop === "jsonSchema") {
|
|
108935
|
+
const value2 = Reflect.get(target, prop, receiver);
|
|
108936
|
+
if (value2 && typeof value2 === "object") {
|
|
108937
|
+
return wrapJsonSchemaProducer(value2);
|
|
108938
|
+
}
|
|
108939
|
+
return value2;
|
|
108940
|
+
}
|
|
108941
|
+
return Reflect.get(target, prop, receiver);
|
|
108942
|
+
}
|
|
108943
|
+
});
|
|
108944
|
+
}
|
|
108945
|
+
function wrapSchemaForGemini(schema2) {
|
|
108946
|
+
return new Proxy(schema2, {
|
|
108947
|
+
get(target, prop, receiver) {
|
|
108948
|
+
if (prop === "~standard") {
|
|
108949
|
+
const value2 = Reflect.get(target, prop, receiver);
|
|
108950
|
+
if (value2 && typeof value2 === "object") {
|
|
108951
|
+
return wrapStandard(value2);
|
|
108952
|
+
}
|
|
108953
|
+
return value2;
|
|
108954
|
+
}
|
|
108955
|
+
if (prop === "toJsonSchema") {
|
|
108956
|
+
const method = Reflect.get(target, prop, receiver);
|
|
108957
|
+
if (typeof method === "function") {
|
|
108958
|
+
return () => sanitizeForGemini(method.call(target));
|
|
108959
|
+
}
|
|
108960
|
+
return method;
|
|
108961
|
+
}
|
|
108962
|
+
return Reflect.get(target, prop, receiver);
|
|
108963
|
+
}
|
|
108964
|
+
});
|
|
108965
|
+
}
|
|
108966
|
+
function sanitizeToolForGemini(tool2) {
|
|
108967
|
+
if (!tool2.parameters) return tool2;
|
|
108968
|
+
return { ...tool2, parameters: wrapSchemaForGemini(tool2.parameters) };
|
|
108969
|
+
}
|
|
108970
|
+
function isGeminiRouted(ctx) {
|
|
108971
|
+
const effective = ctx.payload.proxyModel ?? ctx.resolvedModel ?? ctx.payload.model;
|
|
108972
|
+
if (!effective) return false;
|
|
108973
|
+
return effective.toLowerCase().includes("gemini");
|
|
108974
|
+
}
|
|
108975
|
+
|
|
108730
108976
|
// mcp/shared.ts
|
|
108731
108977
|
var tool = (toolDef) => toolDef;
|
|
108732
108978
|
var handleToolSuccess = (data) => {
|
|
@@ -108762,15 +109008,21 @@ var execute = (fn2, toolName) => {
|
|
|
108762
109008
|
};
|
|
108763
109009
|
return _fn;
|
|
108764
109010
|
};
|
|
108765
|
-
var addTools = (
|
|
109011
|
+
var addTools = (ctx, server, tools) => {
|
|
109012
|
+
const shouldSanitize = isGeminiRouted(ctx);
|
|
108766
109013
|
for (const tool2 of tools) {
|
|
108767
|
-
server.addTool(tool2);
|
|
109014
|
+
server.addTool(shouldSanitize ? sanitizeToolForGemini(tool2) : tool2);
|
|
108768
109015
|
}
|
|
108769
109016
|
return server;
|
|
108770
109017
|
};
|
|
108771
109018
|
|
|
108772
109019
|
// mcp/comment.ts
|
|
108773
109020
|
var LEAPING_INTO_ACTION_PREFIX = "Leaping into action";
|
|
109021
|
+
function isLeapingIntoActionCommentBody(body) {
|
|
109022
|
+
const content = stripExistingFooter(body).trimStart();
|
|
109023
|
+
const firstLine = content.split(/\r?\n/, 1)[0]?.trimEnd() ?? "";
|
|
109024
|
+
return new RegExp(`(^|\\s)${LEAPING_INTO_ACTION_PREFIX}(\\.\\.\\.)?$`).test(firstLine);
|
|
109025
|
+
}
|
|
108774
109026
|
function buildCommentFooter(ctx, customParts) {
|
|
108775
109027
|
const runId = ctx.runId;
|
|
108776
109028
|
return buildPullfrogFooter({
|
|
@@ -109014,8 +109266,9 @@ function ReportProgressTool(ctx) {
|
|
|
109014
109266
|
if (!params.target_plan_comment && ctx.toolState.todoTracker) {
|
|
109015
109267
|
ctx.toolState.todoTracker.cancel();
|
|
109016
109268
|
await ctx.toolState.todoTracker.settled();
|
|
109017
|
-
ctx.toolState.todoTracker.
|
|
109018
|
-
|
|
109269
|
+
const collapsible = ctx.toolState.todoTracker.renderCollapsible({
|
|
109270
|
+
completeInProgress: true
|
|
109271
|
+
});
|
|
109019
109272
|
if (collapsible) {
|
|
109020
109273
|
body = `${body}
|
|
109021
109274
|
|
|
@@ -109402,8 +109655,27 @@ import { performance as performance3 } from "node:perf_hooks";
|
|
|
109402
109655
|
|
|
109403
109656
|
// utils/activity.ts
|
|
109404
109657
|
import { performance as performance2 } from "node:perf_hooks";
|
|
109658
|
+
function isMonitorDebugEnabled() {
|
|
109659
|
+
return process.env.ACTIONS_STEP_DEBUG === "true" || process.env.RUNNER_DEBUG === "1" || process.env.LOG_LEVEL === "debug";
|
|
109660
|
+
}
|
|
109405
109661
|
var DEFAULT_ACTIVITY_TIMEOUT_MS = 3e5;
|
|
109406
109662
|
var DEFAULT_ACTIVITY_CHECK_INTERVAL_MS = 5e3;
|
|
109663
|
+
var DEBUG_TS_PREFIX = /^(?:\[\d{4}-\d{2}-\d{2}T[^\]]+\]\s+)?/.source;
|
|
109664
|
+
var ACTIVITY_NOISE_PATTERNS = [
|
|
109665
|
+
new RegExp(`${DEBUG_TS_PREFIX}\\[mcp-proxy\\]`),
|
|
109666
|
+
new RegExp(`${DEBUG_TS_PREFIX}\xBB provider error detected`),
|
|
109667
|
+
new RegExp(`${DEBUG_TS_PREFIX}\\[DEBUG\\]\\s+(?:spawn|process) activity `),
|
|
109668
|
+
/^::debug::(?:spawn|process) activity /
|
|
109669
|
+
];
|
|
109670
|
+
function isActivityNoise(chunk) {
|
|
109671
|
+
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
109672
|
+
if (!text.trim()) return true;
|
|
109673
|
+
return text.split("\n").every((line) => {
|
|
109674
|
+
const trimmed = line.trim();
|
|
109675
|
+
if (!trimmed) return true;
|
|
109676
|
+
return ACTIVITY_NOISE_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
109677
|
+
});
|
|
109678
|
+
}
|
|
109407
109679
|
var _lastActivity = performance2.now();
|
|
109408
109680
|
function markActivity() {
|
|
109409
109681
|
_lastActivity = performance2.now();
|
|
@@ -109413,7 +109685,9 @@ function getIdleMs() {
|
|
|
109413
109685
|
}
|
|
109414
109686
|
function wrapWrite(original, onActivity) {
|
|
109415
109687
|
const wrapped = (chunk, encodingOrCb, cb) => {
|
|
109416
|
-
|
|
109688
|
+
if (!isActivityNoise(chunk)) {
|
|
109689
|
+
onActivity();
|
|
109690
|
+
}
|
|
109417
109691
|
if (typeof encodingOrCb === "function") {
|
|
109418
109692
|
return original(chunk, encodingOrCb);
|
|
109419
109693
|
}
|
|
@@ -109427,10 +109701,15 @@ function startProcessOutputMonitor(ctx) {
|
|
|
109427
109701
|
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
109428
109702
|
process.stdout.write = wrapWrite(originalStdoutWrite, markActivity);
|
|
109429
109703
|
process.stderr.write = wrapWrite(originalStderrWrite, markActivity);
|
|
109430
|
-
|
|
109704
|
+
const debugBypass = (msg) => {
|
|
109705
|
+
if (!isMonitorDebugEnabled()) return;
|
|
109706
|
+
originalStdoutWrite(`[${(/* @__PURE__ */ new Date()).toISOString()}] [DEBUG] ${msg}
|
|
109707
|
+
`);
|
|
109708
|
+
};
|
|
109709
|
+
debugBypass(`process activity monitor started: timeout=${ctx.timeoutMs}ms`);
|
|
109431
109710
|
const intervalId = setInterval(() => {
|
|
109432
109711
|
const idleMs = getIdleMs();
|
|
109433
|
-
|
|
109712
|
+
debugBypass(`process activity check: idle=${idleMs}ms / ${ctx.timeoutMs}ms`);
|
|
109434
109713
|
if (timedOut || idleMs <= ctx.timeoutMs) return;
|
|
109435
109714
|
timedOut = true;
|
|
109436
109715
|
ctx.onTimeout(idleMs);
|
|
@@ -109458,12 +109737,26 @@ function createProcessOutputActivityTimeout(ctx) {
|
|
|
109458
109737
|
if (monitor) {
|
|
109459
109738
|
monitor.stop();
|
|
109460
109739
|
}
|
|
109461
|
-
|
|
109740
|
+
const reject = rejectFn;
|
|
109741
|
+
rejectFn = null;
|
|
109742
|
+
reject(new Error(`activity timeout: no output for ${idleSec}s`));
|
|
109462
109743
|
}
|
|
109463
109744
|
});
|
|
109464
109745
|
return {
|
|
109465
109746
|
promise: promise2,
|
|
109466
|
-
stop
|
|
109747
|
+
// stop() also disarms forceReject so a late safety-net fire can't reject
|
|
109748
|
+
// the promise after the run has already succeeded.
|
|
109749
|
+
stop: () => {
|
|
109750
|
+
monitor?.stop();
|
|
109751
|
+
rejectFn = null;
|
|
109752
|
+
},
|
|
109753
|
+
forceReject: (reason) => {
|
|
109754
|
+
if (!rejectFn) return;
|
|
109755
|
+
monitor?.stop();
|
|
109756
|
+
const reject = rejectFn;
|
|
109757
|
+
rejectFn = null;
|
|
109758
|
+
reject(new Error(reason));
|
|
109759
|
+
}
|
|
109467
109760
|
};
|
|
109468
109761
|
}
|
|
109469
109762
|
|
|
@@ -109493,6 +109786,16 @@ function exitWithSignal(signal) {
|
|
|
109493
109786
|
}
|
|
109494
109787
|
|
|
109495
109788
|
// utils/subprocess.ts
|
|
109789
|
+
var SPAWN_TIMEOUT_CODE = "E_SPAWN_TIMEOUT";
|
|
109790
|
+
var SPAWN_ACTIVITY_TIMEOUT_CODE = "E_SPAWN_ACTIVITY_TIMEOUT";
|
|
109791
|
+
var SpawnTimeoutError = class extends Error {
|
|
109792
|
+
code;
|
|
109793
|
+
constructor(message, code) {
|
|
109794
|
+
super(message);
|
|
109795
|
+
this.name = "SpawnTimeoutError";
|
|
109796
|
+
this.code = code;
|
|
109797
|
+
}
|
|
109798
|
+
};
|
|
109496
109799
|
var activeChildren = /* @__PURE__ */ new Map();
|
|
109497
109800
|
var externalSignalHandler = null;
|
|
109498
109801
|
function trackChild(options) {
|
|
@@ -109538,7 +109841,7 @@ async function spawn(options) {
|
|
|
109538
109841
|
const startTime = performance3.now();
|
|
109539
109842
|
let stdoutBuffer = "";
|
|
109540
109843
|
let stderrBuffer = "";
|
|
109541
|
-
return new Promise((
|
|
109844
|
+
return new Promise((resolve3, reject) => {
|
|
109542
109845
|
const child = nodeSpawn(options.cmd, options.args, {
|
|
109543
109846
|
env: options.env || {
|
|
109544
109847
|
PATH: process.env.PATH || "",
|
|
@@ -109549,15 +109852,17 @@ async function spawn(options) {
|
|
|
109549
109852
|
});
|
|
109550
109853
|
trackChild({ child });
|
|
109551
109854
|
let timeoutId;
|
|
109855
|
+
let sigkillEscalatorId;
|
|
109552
109856
|
let activityCheckIntervalId;
|
|
109553
109857
|
let isTimedOut = false;
|
|
109554
109858
|
let isActivityTimedOut = false;
|
|
109555
109859
|
let lastActivityTime = performance3.now();
|
|
109860
|
+
let killedAtIdleMs;
|
|
109556
109861
|
if (options.timeout) {
|
|
109557
109862
|
timeoutId = setTimeout(() => {
|
|
109558
109863
|
isTimedOut = true;
|
|
109559
109864
|
child.kill("SIGTERM");
|
|
109560
|
-
setTimeout(() => {
|
|
109865
|
+
sigkillEscalatorId = setTimeout(() => {
|
|
109561
109866
|
if (!child.killed) {
|
|
109562
109867
|
child.kill("SIGKILL");
|
|
109563
109868
|
}
|
|
@@ -109575,12 +109880,20 @@ async function spawn(options) {
|
|
|
109575
109880
|
);
|
|
109576
109881
|
if (idleMs > activityTimeoutMs) {
|
|
109577
109882
|
isActivityTimedOut = true;
|
|
109883
|
+
killedAtIdleMs = idleMs;
|
|
109578
109884
|
const idleSec = Math.round(idleMs / 1e3);
|
|
109579
109885
|
log.info(
|
|
109580
109886
|
`no output for ${idleSec}s from pid=${child.pid} (${options.cmd}), killing process`
|
|
109581
109887
|
);
|
|
109582
109888
|
child.kill("SIGKILL");
|
|
109583
109889
|
clearInterval(activityCheckIntervalId);
|
|
109890
|
+
try {
|
|
109891
|
+
options.onActivityTimeout?.();
|
|
109892
|
+
} catch (err) {
|
|
109893
|
+
log.debug(
|
|
109894
|
+
`spawn onActivityTimeout handler threw: ${err instanceof Error ? err.message : String(err)}`
|
|
109895
|
+
);
|
|
109896
|
+
}
|
|
109584
109897
|
}
|
|
109585
109898
|
}, DEFAULT_ACTIVITY_CHECK_INTERVAL_MS);
|
|
109586
109899
|
}
|
|
@@ -109602,24 +109915,41 @@ async function spawn(options) {
|
|
|
109602
109915
|
options.onStderr?.(chunk);
|
|
109603
109916
|
});
|
|
109604
109917
|
}
|
|
109605
|
-
child.on("close", (exitCode) => {
|
|
109918
|
+
child.on("close", (exitCode, signal) => {
|
|
109606
109919
|
const durationMs = performance3.now() - startTime;
|
|
109607
109920
|
untrackChild(child);
|
|
109608
109921
|
if (timeoutId) clearTimeout(timeoutId);
|
|
109922
|
+
if (sigkillEscalatorId) clearTimeout(sigkillEscalatorId);
|
|
109609
109923
|
if (activityCheckIntervalId) clearInterval(activityCheckIntervalId);
|
|
109610
109924
|
if (isTimedOut) {
|
|
109611
|
-
reject(
|
|
109925
|
+
reject(
|
|
109926
|
+
new SpawnTimeoutError(`process timed out after ${options.timeout}ms`, SPAWN_TIMEOUT_CODE)
|
|
109927
|
+
);
|
|
109612
109928
|
return;
|
|
109613
109929
|
}
|
|
109614
109930
|
if (isActivityTimedOut) {
|
|
109615
|
-
const
|
|
109616
|
-
|
|
109931
|
+
const idleMs = killedAtIdleMs ?? performance3.now() - lastActivityTime;
|
|
109932
|
+
const idleSec = Math.round(idleMs / 1e3);
|
|
109933
|
+
reject(
|
|
109934
|
+
new SpawnTimeoutError(
|
|
109935
|
+
`activity timeout: no output for ${idleSec}s`,
|
|
109936
|
+
SPAWN_ACTIVITY_TIMEOUT_CODE
|
|
109937
|
+
)
|
|
109938
|
+
);
|
|
109617
109939
|
return;
|
|
109618
109940
|
}
|
|
109619
|
-
|
|
109941
|
+
let resolvedExitCode = exitCode ?? 0;
|
|
109942
|
+
let resolvedStderr = stderrBuffer;
|
|
109943
|
+
if (exitCode === null && signal) {
|
|
109944
|
+
const killMsg = `[spawn] ${options.cmd}: killed by signal ${signal}`;
|
|
109945
|
+
resolvedStderr = resolvedStderr ? `${resolvedStderr}
|
|
109946
|
+
${killMsg}` : killMsg;
|
|
109947
|
+
resolvedExitCode = 1;
|
|
109948
|
+
}
|
|
109949
|
+
resolve3({
|
|
109620
109950
|
stdout: stdoutBuffer,
|
|
109621
|
-
stderr:
|
|
109622
|
-
exitCode:
|
|
109951
|
+
stderr: resolvedStderr,
|
|
109952
|
+
exitCode: resolvedExitCode,
|
|
109623
109953
|
durationMs
|
|
109624
109954
|
});
|
|
109625
109955
|
});
|
|
@@ -109627,9 +109957,13 @@ async function spawn(options) {
|
|
|
109627
109957
|
const durationMs = performance3.now() - startTime;
|
|
109628
109958
|
untrackChild(child);
|
|
109629
109959
|
if (timeoutId) clearTimeout(timeoutId);
|
|
109960
|
+
if (sigkillEscalatorId) clearTimeout(sigkillEscalatorId);
|
|
109630
109961
|
if (activityCheckIntervalId) clearInterval(activityCheckIntervalId);
|
|
109631
|
-
|
|
109632
|
-
|
|
109962
|
+
const errMsg = `[spawn] ${options.cmd}: ${error49.message}`;
|
|
109963
|
+
console.error(errMsg);
|
|
109964
|
+
stderrBuffer = stderrBuffer ? `${stderrBuffer}
|
|
109965
|
+
${errMsg}` : errMsg;
|
|
109966
|
+
resolve3({
|
|
109633
109967
|
stdout: stdoutBuffer,
|
|
109634
109968
|
stderr: stderrBuffer,
|
|
109635
109969
|
exitCode: 1,
|
|
@@ -114396,7 +114730,7 @@ var Protocol = class {
|
|
|
114396
114730
|
return;
|
|
114397
114731
|
}
|
|
114398
114732
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
114399
|
-
await new Promise((
|
|
114733
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
114400
114734
|
options?.signal?.throwIfAborted();
|
|
114401
114735
|
}
|
|
114402
114736
|
} catch (error49) {
|
|
@@ -114413,7 +114747,7 @@ var Protocol = class {
|
|
|
114413
114747
|
*/
|
|
114414
114748
|
request(request2, resultSchema, options) {
|
|
114415
114749
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
114416
|
-
return new Promise((
|
|
114750
|
+
return new Promise((resolve3, reject) => {
|
|
114417
114751
|
const earlyReject = (error49) => {
|
|
114418
114752
|
reject(error49);
|
|
114419
114753
|
};
|
|
@@ -114491,7 +114825,7 @@ var Protocol = class {
|
|
|
114491
114825
|
if (!parseResult.success) {
|
|
114492
114826
|
reject(parseResult.error);
|
|
114493
114827
|
} else {
|
|
114494
|
-
|
|
114828
|
+
resolve3(parseResult.data);
|
|
114495
114829
|
}
|
|
114496
114830
|
} catch (error49) {
|
|
114497
114831
|
reject(error49);
|
|
@@ -114752,12 +115086,12 @@ var Protocol = class {
|
|
|
114752
115086
|
}
|
|
114753
115087
|
} catch {
|
|
114754
115088
|
}
|
|
114755
|
-
return new Promise((
|
|
115089
|
+
return new Promise((resolve3, reject) => {
|
|
114756
115090
|
if (signal.aborted) {
|
|
114757
115091
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
114758
115092
|
return;
|
|
114759
115093
|
}
|
|
114760
|
-
const timeoutId = setTimeout(
|
|
115094
|
+
const timeoutId = setTimeout(resolve3, interval);
|
|
114761
115095
|
signal.addEventListener("abort", () => {
|
|
114762
115096
|
clearTimeout(timeoutId);
|
|
114763
115097
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -115627,12 +115961,12 @@ var StdioServerTransport = class {
|
|
|
115627
115961
|
this.onclose?.();
|
|
115628
115962
|
}
|
|
115629
115963
|
send(message) {
|
|
115630
|
-
return new Promise((
|
|
115964
|
+
return new Promise((resolve3) => {
|
|
115631
115965
|
const json4 = serializeMessage(message);
|
|
115632
115966
|
if (this._stdout.write(json4)) {
|
|
115633
|
-
|
|
115967
|
+
resolve3();
|
|
115634
115968
|
} else {
|
|
115635
|
-
this._stdout.once("drain",
|
|
115969
|
+
this._stdout.once("drain", resolve3);
|
|
115636
115970
|
}
|
|
115637
115971
|
});
|
|
115638
115972
|
}
|
|
@@ -136660,12 +136994,12 @@ var require_schemes2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
136660
136994
|
var require_fast_uri2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
136661
136995
|
const { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils5();
|
|
136662
136996
|
const { SCHEMES, getSchemeHandler } = require_schemes2();
|
|
136663
|
-
function
|
|
136997
|
+
function normalize3(uri$2, options) {
|
|
136664
136998
|
if (typeof uri$2 === "string") uri$2 = serialize(parse5(uri$2, options), options);
|
|
136665
136999
|
else if (typeof uri$2 === "object") uri$2 = parse5(serialize(uri$2, options), options);
|
|
136666
137000
|
return uri$2;
|
|
136667
137001
|
}
|
|
136668
|
-
function
|
|
137002
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
136669
137003
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
136670
137004
|
const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
136671
137005
|
schemelessOptions.skipEscape = true;
|
|
@@ -136838,8 +137172,8 @@ var require_fast_uri2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
136838
137172
|
}
|
|
136839
137173
|
const fastUri = {
|
|
136840
137174
|
SCHEMES,
|
|
136841
|
-
normalize:
|
|
136842
|
-
resolve:
|
|
137175
|
+
normalize: normalize3,
|
|
137176
|
+
resolve: resolve3,
|
|
136843
137177
|
resolveComponent,
|
|
136844
137178
|
equal: equal$1,
|
|
136845
137179
|
serialize,
|
|
@@ -140427,7 +140761,7 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
|
|
|
140427
140761
|
new Error(`Connection is in ${this.#connectionState} state`)
|
|
140428
140762
|
);
|
|
140429
140763
|
}
|
|
140430
|
-
return new Promise((
|
|
140764
|
+
return new Promise((resolve3, reject) => {
|
|
140431
140765
|
const timeout = setTimeout(() => {
|
|
140432
140766
|
reject(
|
|
140433
140767
|
new Error(
|
|
@@ -140437,7 +140771,7 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
|
|
|
140437
140771
|
}, 5e3);
|
|
140438
140772
|
this.once("ready", () => {
|
|
140439
140773
|
clearTimeout(timeout);
|
|
140440
|
-
|
|
140774
|
+
resolve3();
|
|
140441
140775
|
});
|
|
140442
140776
|
this.once("error", (event) => {
|
|
140443
140777
|
clearTimeout(timeout);
|
|
@@ -140884,7 +141218,7 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
|
|
|
140884
141218
|
}
|
|
140885
141219
|
});
|
|
140886
141220
|
if (this.#needsEventLoopFlush) {
|
|
140887
|
-
await new Promise((
|
|
141221
|
+
await new Promise((resolve3) => setImmediate(resolve3));
|
|
140888
141222
|
}
|
|
140889
141223
|
} catch (progressError) {
|
|
140890
141224
|
this.#logger.warn(
|
|
@@ -140942,7 +141276,7 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
|
|
|
140942
141276
|
}
|
|
140943
141277
|
});
|
|
140944
141278
|
if (this.#needsEventLoopFlush) {
|
|
140945
|
-
await new Promise((
|
|
141279
|
+
await new Promise((resolve3) => setImmediate(resolve3));
|
|
140946
141280
|
}
|
|
140947
141281
|
} catch (streamError) {
|
|
140948
141282
|
this.#logger.warn(
|
|
@@ -141955,7 +142289,7 @@ function formatMcpToolRef(agentId, toolName) {
|
|
|
141955
142289
|
}
|
|
141956
142290
|
|
|
141957
142291
|
// utils/browser.ts
|
|
141958
|
-
import { execFileSync, spawnSync } from "node:child_process";
|
|
142292
|
+
import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
|
|
141959
142293
|
import { existsSync as existsSync4 } from "node:fs";
|
|
141960
142294
|
import { dirname } from "node:path";
|
|
141961
142295
|
|
|
@@ -141970,12 +142304,77 @@ var SENSITIVE_PATTERNS = [
|
|
|
141970
142304
|
function isSensitiveEnvName(key) {
|
|
141971
142305
|
return SENSITIVE_PATTERNS.some((p2) => p2.test(key));
|
|
141972
142306
|
}
|
|
142307
|
+
var SAFE_ENV_PREFIXES = ["GITHUB_", "RUNNER_", "JAVA_HOME_", "GOROOT_"];
|
|
142308
|
+
var SAFE_ENV_NAMES = /* @__PURE__ */ new Set([
|
|
142309
|
+
// system
|
|
142310
|
+
"CI",
|
|
142311
|
+
"HOME",
|
|
142312
|
+
"LANG",
|
|
142313
|
+
"LOGNAME",
|
|
142314
|
+
"PATH",
|
|
142315
|
+
"SHELL",
|
|
142316
|
+
"SHLVL",
|
|
142317
|
+
"TERM",
|
|
142318
|
+
"TMPDIR",
|
|
142319
|
+
"TZ",
|
|
142320
|
+
"USER",
|
|
142321
|
+
"XDG_CONFIG_HOME",
|
|
142322
|
+
"XDG_RUNTIME_DIR",
|
|
142323
|
+
"DEBIAN_FRONTEND",
|
|
142324
|
+
// runner image toolchain
|
|
142325
|
+
"ACCEPT_EULA",
|
|
142326
|
+
"AGENT_TOOLSDIRECTORY",
|
|
142327
|
+
"ANDROID_HOME",
|
|
142328
|
+
"ANDROID_NDK",
|
|
142329
|
+
"ANDROID_NDK_HOME",
|
|
142330
|
+
"ANDROID_NDK_LATEST_HOME",
|
|
142331
|
+
"ANDROID_NDK_ROOT",
|
|
142332
|
+
"ANDROID_SDK_ROOT",
|
|
142333
|
+
"ANT_HOME",
|
|
142334
|
+
"AZURE_EXTENSION_DIR",
|
|
142335
|
+
"BOOTSTRAP_HASKELL_NONINTERACTIVE",
|
|
142336
|
+
"CHROME_BIN",
|
|
142337
|
+
"CHROMEWEBDRIVER",
|
|
142338
|
+
"CONDA",
|
|
142339
|
+
"DOTNET_MULTILEVEL_LOOKUP",
|
|
142340
|
+
"DOTNET_NOLOGO",
|
|
142341
|
+
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",
|
|
142342
|
+
"EDGEWEBDRIVER",
|
|
142343
|
+
"GECKOWEBDRIVER",
|
|
142344
|
+
"GHCUP_INSTALL_BASE_PREFIX",
|
|
142345
|
+
"GRADLE_HOME",
|
|
142346
|
+
"JAVA_HOME",
|
|
142347
|
+
"HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS",
|
|
142348
|
+
"HOMEBREW_NO_AUTO_UPDATE",
|
|
142349
|
+
"ImageOS",
|
|
142350
|
+
"ImageVersion",
|
|
142351
|
+
"NVM_DIR",
|
|
142352
|
+
"PIPX_BIN_DIR",
|
|
142353
|
+
"PIPX_HOME",
|
|
142354
|
+
"PSModulePath",
|
|
142355
|
+
"SELENIUM_JAR_PATH",
|
|
142356
|
+
"SGX_AESM_ADDR",
|
|
142357
|
+
"SWIFT_PATH",
|
|
142358
|
+
"VCPKG_INSTALLATION_ROOT"
|
|
142359
|
+
]);
|
|
142360
|
+
var _userAllowlist = null;
|
|
142361
|
+
function setEnvAllowlist(raw2) {
|
|
142362
|
+
const names = raw2.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
142363
|
+
_userAllowlist = new Set(names);
|
|
142364
|
+
}
|
|
142365
|
+
function isSafeEnvVar(key) {
|
|
142366
|
+
if (SAFE_ENV_NAMES.has(key)) return true;
|
|
142367
|
+
return SAFE_ENV_PREFIXES.some((p2) => key.startsWith(p2));
|
|
142368
|
+
}
|
|
141973
142369
|
function filterEnv() {
|
|
141974
142370
|
const filtered = {};
|
|
141975
142371
|
for (const [key, value2] of Object.entries(process.env)) {
|
|
141976
142372
|
if (value2 === void 0) continue;
|
|
141977
|
-
|
|
141978
|
-
|
|
142373
|
+
const userAllowed = _userAllowlist?.has(key) ?? false;
|
|
142374
|
+
if (isSensitiveEnvName(key) && !userAllowed) continue;
|
|
142375
|
+
if (isSafeEnvVar(key) || userAllowed) {
|
|
142376
|
+
filtered[key] = value2;
|
|
142377
|
+
}
|
|
141979
142378
|
}
|
|
141980
142379
|
return filtered;
|
|
141981
142380
|
}
|
|
@@ -141995,7 +142394,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
141995
142394
|
// package.json
|
|
141996
142395
|
var package_default = {
|
|
141997
142396
|
name: "pullfrog",
|
|
141998
|
-
version: "0.0.
|
|
142397
|
+
version: "0.0.202",
|
|
141999
142398
|
type: "module",
|
|
142000
142399
|
bin: {
|
|
142001
142400
|
pullfrog: "dist/cli.mjs",
|
|
@@ -142007,6 +142406,7 @@ var package_default = {
|
|
|
142007
142406
|
],
|
|
142008
142407
|
scripts: {
|
|
142009
142408
|
test: "vitest",
|
|
142409
|
+
"test:catalog": "vitest run --config vitest.main.config.ts",
|
|
142010
142410
|
typecheck: "tsc --noEmit",
|
|
142011
142411
|
build: "node esbuild.config.js && tsc -p tsconfig.exports.json",
|
|
142012
142412
|
"check:entrypoints": "node scripts/check-entrypoint-imports.ts",
|
|
@@ -142019,7 +142419,7 @@ var package_default = {
|
|
|
142019
142419
|
},
|
|
142020
142420
|
devDependencies: {
|
|
142021
142421
|
"@actions/core": "^1.11.1",
|
|
142022
|
-
"@anthropic-ai/claude-code": "2.1.
|
|
142422
|
+
"@anthropic-ai/claude-code": "2.1.112",
|
|
142023
142423
|
"@ark/fs": "0.56.0",
|
|
142024
142424
|
"@ark/util": "0.56.0",
|
|
142025
142425
|
"@clack/prompts": "^1.2.0",
|
|
@@ -142143,7 +142543,7 @@ function ensureBrowserDaemon(toolState) {
|
|
|
142143
142543
|
log.info("agent-browser installed");
|
|
142144
142544
|
let binDir;
|
|
142145
142545
|
try {
|
|
142146
|
-
const binPath =
|
|
142546
|
+
const binPath = execFileSync2("which", ["agent-browser"], { encoding: "utf-8" }).trim();
|
|
142147
142547
|
binDir = dirname(binPath);
|
|
142148
142548
|
log.info(`agent-browser binary: ${binPath}`);
|
|
142149
142549
|
} catch {
|
|
@@ -142190,9 +142590,271 @@ function closeBrowserDaemon(toolState) {
|
|
|
142190
142590
|
}
|
|
142191
142591
|
|
|
142192
142592
|
// mcp/checkout.ts
|
|
142593
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
142193
142594
|
import { writeFileSync } from "node:fs";
|
|
142194
142595
|
import { join as join3 } from "node:path";
|
|
142195
142596
|
|
|
142597
|
+
// utils/diffCoverage.ts
|
|
142598
|
+
import { isAbsolute, normalize as normalize2, resolve } from "node:path";
|
|
142599
|
+
function countLines(params) {
|
|
142600
|
+
const content = params.content;
|
|
142601
|
+
if (content.length === 0) return 0;
|
|
142602
|
+
return content.split("\n").length;
|
|
142603
|
+
}
|
|
142604
|
+
function parseDiffTocEntries(params) {
|
|
142605
|
+
const lines = params.toc.split("\n");
|
|
142606
|
+
const entries = [];
|
|
142607
|
+
for (const line of lines) {
|
|
142608
|
+
const match3 = line.match(/^- (.+) (?:→|->) lines (\d+)-(\d+)(?: · diff-[0-9a-f]+)?$/);
|
|
142609
|
+
if (!match3) continue;
|
|
142610
|
+
const startLine = Number.parseInt(match3[2], 10);
|
|
142611
|
+
const endLine = Number.parseInt(match3[3], 10);
|
|
142612
|
+
if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) continue;
|
|
142613
|
+
entries.push({ filename: match3[1], startLine, endLine });
|
|
142614
|
+
}
|
|
142615
|
+
return entries;
|
|
142616
|
+
}
|
|
142617
|
+
function createDiffCoverageState(params) {
|
|
142618
|
+
return {
|
|
142619
|
+
diffPath: params.diffPath,
|
|
142620
|
+
totalLines: params.totalLines,
|
|
142621
|
+
tocEntries: parseDiffTocEntries({ toc: params.toc }),
|
|
142622
|
+
coveredRanges: [],
|
|
142623
|
+
coveragePreflightRan: false
|
|
142624
|
+
};
|
|
142625
|
+
}
|
|
142626
|
+
function recordDiffReadFromToolUse(params) {
|
|
142627
|
+
const state = params.state;
|
|
142628
|
+
if (!state) return false;
|
|
142629
|
+
if (!isReadTool(params.toolName)) return false;
|
|
142630
|
+
const readTarget = extractReadTarget({ input: params.input });
|
|
142631
|
+
if (!readTarget) return false;
|
|
142632
|
+
const normalizedReadPath = normalizePath({ path: readTarget.path, cwd: params.cwd });
|
|
142633
|
+
const normalizedDiffPath = normalize2(state.diffPath);
|
|
142634
|
+
if (normalizedReadPath !== normalizedDiffPath) return false;
|
|
142635
|
+
const range2 = resolveReadRange({
|
|
142636
|
+
totalLines: state.totalLines,
|
|
142637
|
+
offset: readTarget.offset,
|
|
142638
|
+
limit: readTarget.limit,
|
|
142639
|
+
startLine: readTarget.startLine,
|
|
142640
|
+
endLine: readTarget.endLine,
|
|
142641
|
+
offsetBase: resolveOffsetBase({ toolName: params.toolName })
|
|
142642
|
+
});
|
|
142643
|
+
if (!range2) return false;
|
|
142644
|
+
state.coveredRanges = mergeRanges({ ranges: state.coveredRanges, nextRange: range2 });
|
|
142645
|
+
return true;
|
|
142646
|
+
}
|
|
142647
|
+
function getDiffCoverageBreakdown(params) {
|
|
142648
|
+
const state = params.state;
|
|
142649
|
+
const coveredRanges = mergeRangesList({ ranges: state.coveredRanges });
|
|
142650
|
+
const unreadRanges = invertRanges({ totalLines: state.totalLines, coveredRanges });
|
|
142651
|
+
const coveredLines = countLinesInRanges({ ranges: coveredRanges });
|
|
142652
|
+
const unreadLines = Math.max(0, state.totalLines - coveredLines);
|
|
142653
|
+
const coveragePercent = state.totalLines ? Number((coveredLines / state.totalLines * 100).toFixed(2)) : 100;
|
|
142654
|
+
const files = [];
|
|
142655
|
+
for (const entry of state.tocEntries) {
|
|
142656
|
+
const fileRange = { startLine: entry.startLine, endLine: entry.endLine };
|
|
142657
|
+
const coveredInFile = intersectRangesWithRange({ ranges: coveredRanges, target: fileRange });
|
|
142658
|
+
const unreadInFile = intersectRangesWithRange({ ranges: unreadRanges, target: fileRange });
|
|
142659
|
+
const totalFileLines = Math.max(0, entry.endLine - entry.startLine + 1);
|
|
142660
|
+
const fileCoveredLines = countLinesInRanges({ ranges: coveredInFile });
|
|
142661
|
+
files.push({
|
|
142662
|
+
filename: entry.filename,
|
|
142663
|
+
startLine: entry.startLine,
|
|
142664
|
+
endLine: entry.endLine,
|
|
142665
|
+
totalLines: totalFileLines,
|
|
142666
|
+
coveredLines: fileCoveredLines,
|
|
142667
|
+
coveredRanges: coveredInFile,
|
|
142668
|
+
unreadRanges: unreadInFile
|
|
142669
|
+
});
|
|
142670
|
+
}
|
|
142671
|
+
return {
|
|
142672
|
+
totalLines: state.totalLines,
|
|
142673
|
+
coveredLines,
|
|
142674
|
+
unreadLines,
|
|
142675
|
+
coveragePercent,
|
|
142676
|
+
coveredRanges,
|
|
142677
|
+
unreadRanges,
|
|
142678
|
+
files
|
|
142679
|
+
};
|
|
142680
|
+
}
|
|
142681
|
+
function renderDiffCoverageBreakdown(params) {
|
|
142682
|
+
const breakdown = params.breakdown;
|
|
142683
|
+
const lines = [];
|
|
142684
|
+
lines.push(`diff coverage report for \`${params.diffPath}\``);
|
|
142685
|
+
lines.push(
|
|
142686
|
+
`overall: ${breakdown.coveredLines}/${breakdown.totalLines} lines read (${breakdown.coveragePercent}%), unread: ${breakdown.unreadLines}`
|
|
142687
|
+
);
|
|
142688
|
+
lines.push(`covered ranges: ${formatRanges({ ranges: breakdown.coveredRanges })}`);
|
|
142689
|
+
lines.push(`unread ranges: ${formatRanges({ ranges: breakdown.unreadRanges })}`);
|
|
142690
|
+
lines.push("");
|
|
142691
|
+
lines.push("per-file TOC coverage:");
|
|
142692
|
+
for (const file2 of breakdown.files) {
|
|
142693
|
+
const filePercent = file2.totalLines ? Number((file2.coveredLines / file2.totalLines * 100).toFixed(2)) : 100;
|
|
142694
|
+
lines.push(
|
|
142695
|
+
`- ${file2.filename} (toc lines ${file2.startLine}-${file2.endLine}): ${file2.coveredLines}/${file2.totalLines} lines read (${filePercent}%)`
|
|
142696
|
+
);
|
|
142697
|
+
lines.push(` read: ${formatRanges({ ranges: file2.coveredRanges })}`);
|
|
142698
|
+
lines.push(` unread: ${formatRanges({ ranges: file2.unreadRanges })}`);
|
|
142699
|
+
}
|
|
142700
|
+
return lines.join("\n");
|
|
142701
|
+
}
|
|
142702
|
+
function resolveOffsetBase(params) {
|
|
142703
|
+
const lower2 = params.toolName.toLowerCase();
|
|
142704
|
+
if (lower2 === "readfile" || lower2.endsWith(".readfile")) {
|
|
142705
|
+
return "one";
|
|
142706
|
+
}
|
|
142707
|
+
return "zero";
|
|
142708
|
+
}
|
|
142709
|
+
function isReadTool(toolName) {
|
|
142710
|
+
const lower2 = toolName.toLowerCase();
|
|
142711
|
+
if (lower2 === "read" || lower2 === "readfile") return true;
|
|
142712
|
+
if (lower2.endsWith(".read") || lower2.endsWith(".readfile")) return true;
|
|
142713
|
+
return false;
|
|
142714
|
+
}
|
|
142715
|
+
function extractReadTarget(params) {
|
|
142716
|
+
const inputRecord = asRecord(params.input);
|
|
142717
|
+
if (!inputRecord) return null;
|
|
142718
|
+
const direct = extractReadTargetFromRecord({ record: inputRecord });
|
|
142719
|
+
if (direct) return direct;
|
|
142720
|
+
const nestedCandidates = [inputRecord.args, inputRecord.params, inputRecord.input];
|
|
142721
|
+
for (const candidate of nestedCandidates) {
|
|
142722
|
+
const nestedRecord = asRecord(candidate);
|
|
142723
|
+
if (!nestedRecord) continue;
|
|
142724
|
+
const nested = extractReadTargetFromRecord({ record: nestedRecord });
|
|
142725
|
+
if (nested) return nested;
|
|
142726
|
+
}
|
|
142727
|
+
return null;
|
|
142728
|
+
}
|
|
142729
|
+
function extractReadTargetFromRecord(params) {
|
|
142730
|
+
const record3 = params.record;
|
|
142731
|
+
const pathValue = readString({ value: record3.path }) ?? readString({ value: record3.file_path }) ?? readString({ value: record3.filePath }) ?? readString({ value: record3.filepath }) ?? readString({ value: record3.file }) ?? readString({ value: record3.target_file });
|
|
142732
|
+
if (!pathValue) return null;
|
|
142733
|
+
const offset = readNumber({ value: record3.offset });
|
|
142734
|
+
const limit = readNumber({ value: record3.limit });
|
|
142735
|
+
const startLine = readNumber({ value: record3.start_line }) ?? readNumber({ value: record3.startLine }) ?? readNumber({ value: record3.line_start });
|
|
142736
|
+
const endLine = readNumber({ value: record3.end_line }) ?? readNumber({ value: record3.endLine }) ?? readNumber({ value: record3.line_end });
|
|
142737
|
+
return { path: pathValue, offset, limit, startLine, endLine };
|
|
142738
|
+
}
|
|
142739
|
+
function resolveReadRange(params) {
|
|
142740
|
+
const totalLines = params.totalLines;
|
|
142741
|
+
if (totalLines <= 0) return null;
|
|
142742
|
+
if (params.startLine !== void 0 || params.endLine !== void 0) {
|
|
142743
|
+
const rawStart = params.startLine ?? 1;
|
|
142744
|
+
const rawEnd = params.endLine ?? totalLines;
|
|
142745
|
+
const startLine2 = clampLine({ value: rawStart, totalLines });
|
|
142746
|
+
const endLine2 = clampLine({ value: rawEnd, totalLines });
|
|
142747
|
+
if (endLine2 < startLine2) return null;
|
|
142748
|
+
return { startLine: startLine2, endLine: endLine2 };
|
|
142749
|
+
}
|
|
142750
|
+
let startLine = 1;
|
|
142751
|
+
if (params.offset !== void 0) {
|
|
142752
|
+
if (params.offset >= 0) {
|
|
142753
|
+
const normalizedOffset = params.offsetBase === "zero" ? params.offset + 1 : params.offset === 0 ? 1 : params.offset;
|
|
142754
|
+
startLine = clampLine({ value: normalizedOffset, totalLines });
|
|
142755
|
+
} else {
|
|
142756
|
+
startLine = clampLine({ value: totalLines + params.offset + 1, totalLines });
|
|
142757
|
+
}
|
|
142758
|
+
}
|
|
142759
|
+
let endLine = totalLines;
|
|
142760
|
+
if (params.limit !== void 0) {
|
|
142761
|
+
if (params.limit <= 0) return null;
|
|
142762
|
+
endLine = clampLine({ value: startLine + params.limit - 1, totalLines });
|
|
142763
|
+
}
|
|
142764
|
+
if (endLine < startLine) return null;
|
|
142765
|
+
return { startLine, endLine };
|
|
142766
|
+
}
|
|
142767
|
+
function normalizePath(params) {
|
|
142768
|
+
if (isAbsolute(params.path)) return normalize2(params.path);
|
|
142769
|
+
return normalize2(resolve(params.cwd, params.path));
|
|
142770
|
+
}
|
|
142771
|
+
function mergeRanges(params) {
|
|
142772
|
+
return mergeRangesList({ ranges: [...params.ranges, params.nextRange] });
|
|
142773
|
+
}
|
|
142774
|
+
function mergeRangesList(params) {
|
|
142775
|
+
if (params.ranges.length === 0) return [];
|
|
142776
|
+
const sorted = [...params.ranges].sort((a, b) => a.startLine - b.startLine);
|
|
142777
|
+
const merged = [];
|
|
142778
|
+
for (const range2 of sorted) {
|
|
142779
|
+
const last = merged[merged.length - 1];
|
|
142780
|
+
if (!last) {
|
|
142781
|
+
merged.push({ startLine: range2.startLine, endLine: range2.endLine });
|
|
142782
|
+
continue;
|
|
142783
|
+
}
|
|
142784
|
+
if (range2.startLine <= last.endLine + 1) {
|
|
142785
|
+
if (range2.endLine > last.endLine) {
|
|
142786
|
+
last.endLine = range2.endLine;
|
|
142787
|
+
}
|
|
142788
|
+
continue;
|
|
142789
|
+
}
|
|
142790
|
+
merged.push({ startLine: range2.startLine, endLine: range2.endLine });
|
|
142791
|
+
}
|
|
142792
|
+
return merged;
|
|
142793
|
+
}
|
|
142794
|
+
function invertRanges(params) {
|
|
142795
|
+
if (params.totalLines <= 0) return [];
|
|
142796
|
+
if (params.coveredRanges.length === 0) {
|
|
142797
|
+
return [{ startLine: 1, endLine: params.totalLines }];
|
|
142798
|
+
}
|
|
142799
|
+
const unread = [];
|
|
142800
|
+
let cursor = 1;
|
|
142801
|
+
for (const range2 of params.coveredRanges) {
|
|
142802
|
+
if (cursor < range2.startLine) {
|
|
142803
|
+
unread.push({ startLine: cursor, endLine: range2.startLine - 1 });
|
|
142804
|
+
}
|
|
142805
|
+
cursor = Math.max(cursor, range2.endLine + 1);
|
|
142806
|
+
}
|
|
142807
|
+
if (cursor <= params.totalLines) {
|
|
142808
|
+
unread.push({ startLine: cursor, endLine: params.totalLines });
|
|
142809
|
+
}
|
|
142810
|
+
return unread;
|
|
142811
|
+
}
|
|
142812
|
+
function intersectRangesWithRange(params) {
|
|
142813
|
+
const intersections = [];
|
|
142814
|
+
for (const range2 of params.ranges) {
|
|
142815
|
+
if (range2.endLine < params.target.startLine) continue;
|
|
142816
|
+
if (range2.startLine > params.target.endLine) continue;
|
|
142817
|
+
const startLine = Math.max(range2.startLine, params.target.startLine);
|
|
142818
|
+
const endLine = Math.min(range2.endLine, params.target.endLine);
|
|
142819
|
+
if (endLine >= startLine) {
|
|
142820
|
+
intersections.push({ startLine, endLine });
|
|
142821
|
+
}
|
|
142822
|
+
}
|
|
142823
|
+
return intersections;
|
|
142824
|
+
}
|
|
142825
|
+
function countLinesInRanges(params) {
|
|
142826
|
+
let total = 0;
|
|
142827
|
+
for (const range2 of params.ranges) {
|
|
142828
|
+
total += range2.endLine - range2.startLine + 1;
|
|
142829
|
+
}
|
|
142830
|
+
return total;
|
|
142831
|
+
}
|
|
142832
|
+
function formatRanges(params) {
|
|
142833
|
+
if (params.ranges.length === 0) return "none";
|
|
142834
|
+
return params.ranges.map((range2) => `${range2.startLine}-${range2.endLine}`).join(", ");
|
|
142835
|
+
}
|
|
142836
|
+
function clampLine(params) {
|
|
142837
|
+
if (params.value < 1) return 1;
|
|
142838
|
+
if (params.value > params.totalLines) return params.totalLines;
|
|
142839
|
+
return params.value;
|
|
142840
|
+
}
|
|
142841
|
+
function asRecord(value2) {
|
|
142842
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return null;
|
|
142843
|
+
return Object.fromEntries(Object.entries(value2));
|
|
142844
|
+
}
|
|
142845
|
+
function readString(params) {
|
|
142846
|
+
if (typeof params.value === "string") return params.value;
|
|
142847
|
+
return void 0;
|
|
142848
|
+
}
|
|
142849
|
+
function readNumber(params) {
|
|
142850
|
+
if (typeof params.value === "number" && Number.isFinite(params.value)) return params.value;
|
|
142851
|
+
if (typeof params.value === "string") {
|
|
142852
|
+
const parsed2 = Number.parseInt(params.value, 10);
|
|
142853
|
+
if (Number.isFinite(parsed2)) return parsed2;
|
|
142854
|
+
}
|
|
142855
|
+
return void 0;
|
|
142856
|
+
}
|
|
142857
|
+
|
|
142196
142858
|
// utils/gitAuth.ts
|
|
142197
142859
|
import { execSync } from "node:child_process";
|
|
142198
142860
|
import { createHash } from "node:crypto";
|
|
@@ -142206,7 +142868,7 @@ function resolveGit() {
|
|
|
142206
142868
|
const resolvedPath = realpathSync(whichPath);
|
|
142207
142869
|
const sha256 = hashFile(resolvedPath);
|
|
142208
142870
|
gitBinary = { path: resolvedPath, sha256 };
|
|
142209
|
-
log.
|
|
142871
|
+
log.debug(`\xBB git binary: ${resolvedPath} (sha256: ${sha256.slice(0, 12)}...)`);
|
|
142210
142872
|
}
|
|
142211
142873
|
function verifyGitBinary() {
|
|
142212
142874
|
if (!gitBinary) {
|
|
@@ -142285,29 +142947,43 @@ async function $git(subcommand, args2, options) {
|
|
|
142285
142947
|
}
|
|
142286
142948
|
|
|
142287
142949
|
// lifecycle.ts
|
|
142288
|
-
var LIFECYCLE_HOOK_TIMEOUT_MS =
|
|
142950
|
+
var LIFECYCLE_HOOK_TIMEOUT_MS = 6e5;
|
|
142289
142951
|
|
|
142290
142952
|
// utils/lifecycle.ts
|
|
142291
142953
|
async function executeLifecycleHook(params) {
|
|
142292
|
-
if (!params.script) return;
|
|
142954
|
+
if (!params.script) return {};
|
|
142293
142955
|
log.info(`\xBB executing ${params.event} lifecycle hook...`);
|
|
142294
|
-
|
|
142295
|
-
|
|
142296
|
-
|
|
142297
|
-
|
|
142298
|
-
|
|
142299
|
-
|
|
142300
|
-
|
|
142301
|
-
|
|
142302
|
-
|
|
142303
|
-
|
|
142304
|
-
|
|
142305
|
-
|
|
142306
|
-
|
|
142307
|
-
${output}
|
|
142308
|
-
|
|
142956
|
+
try {
|
|
142957
|
+
const result = await spawn({
|
|
142958
|
+
cmd: "bash",
|
|
142959
|
+
args: ["-c", params.script],
|
|
142960
|
+
env: process.env,
|
|
142961
|
+
timeout: LIFECYCLE_HOOK_TIMEOUT_MS,
|
|
142962
|
+
activityTimeout: 0,
|
|
142963
|
+
onStdout: (chunk) => process.stdout.write(chunk),
|
|
142964
|
+
onStderr: (chunk) => process.stderr.write(chunk)
|
|
142965
|
+
});
|
|
142966
|
+
if (result.exitCode !== 0) {
|
|
142967
|
+
const output = (result.stderr || result.stdout).trim();
|
|
142968
|
+
return {
|
|
142969
|
+
warning: `lifecycle hook '${params.event}' failed with exit code ${result.exitCode}. output: ${output || "(empty)"}. retry the operation if the failure looks flaky (network blips, transient rate limits). do NOT retry if the script is broken (missing commands, syntax errors) or the error is persistent.`
|
|
142970
|
+
};
|
|
142971
|
+
}
|
|
142972
|
+
log.info(`\xBB ${params.event} lifecycle hook completed successfully`);
|
|
142973
|
+
return {};
|
|
142974
|
+
} catch (err) {
|
|
142975
|
+
const isTimeout = err instanceof SpawnTimeoutError && (err.code === SPAWN_TIMEOUT_CODE || err.code === SPAWN_ACTIVITY_TIMEOUT_CODE);
|
|
142976
|
+
if (isTimeout) {
|
|
142977
|
+
const minutes = Math.round(LIFECYCLE_HOOK_TIMEOUT_MS / 6e4);
|
|
142978
|
+
return {
|
|
142979
|
+
warning: `lifecycle hook '${params.event}' timed out after ${minutes}min. do NOT retry \u2014 the script is likely hung or doing too much work. ask the repo owner to simplify the hook (e.g. move long-running work out of the hook, add caching, or split it).`
|
|
142980
|
+
};
|
|
142981
|
+
}
|
|
142982
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
142983
|
+
return {
|
|
142984
|
+
warning: `lifecycle hook '${params.event}' failed to spawn: ${msg}. this is likely a transient failure \u2014 retry the operation.`
|
|
142985
|
+
};
|
|
142309
142986
|
}
|
|
142310
|
-
log.info(`\xBB ${params.event} lifecycle hook completed successfully`);
|
|
142311
142987
|
}
|
|
142312
142988
|
|
|
142313
142989
|
// utils/shell.ts
|
|
@@ -142457,6 +143133,787 @@ function postProcessRangeDiff(raw2, contextLines = 3) {
|
|
|
142457
143133
|
return hasChanges ? out : null;
|
|
142458
143134
|
}
|
|
142459
143135
|
|
|
143136
|
+
// mcp/git.ts
|
|
143137
|
+
function getPushDestination(branch, storedDest) {
|
|
143138
|
+
if (storedDest && storedDest.localBranch === branch) {
|
|
143139
|
+
log.debug(`using stored push destination: ${storedDest.remoteName}/${storedDest.remoteBranch}`);
|
|
143140
|
+
const url4 = $("git", ["remote", "get-url", "--push", storedDest.remoteName], {
|
|
143141
|
+
log: false
|
|
143142
|
+
}).trim();
|
|
143143
|
+
return { remoteName: storedDest.remoteName, remoteBranch: storedDest.remoteBranch, url: url4 };
|
|
143144
|
+
}
|
|
143145
|
+
try {
|
|
143146
|
+
const pushRemote = $("git", ["config", `branch.${branch}.pushRemote`], { log: false }).trim();
|
|
143147
|
+
const merge4 = $("git", ["config", `branch.${branch}.merge`], { log: false }).trim();
|
|
143148
|
+
const remoteBranch = merge4.replace(/^refs\/heads\//, "");
|
|
143149
|
+
const url4 = $("git", ["remote", "get-url", "--push", pushRemote], { log: false }).trim();
|
|
143150
|
+
return { remoteName: pushRemote, remoteBranch, url: url4 };
|
|
143151
|
+
} catch {
|
|
143152
|
+
log.debug(`no push config for ${branch}, falling back to origin/${branch}`);
|
|
143153
|
+
const url4 = $("git", ["remote", "get-url", "--push", "origin"], { log: false }).trim();
|
|
143154
|
+
return { remoteName: "origin", remoteBranch: branch, url: url4 };
|
|
143155
|
+
}
|
|
143156
|
+
}
|
|
143157
|
+
function normalizeUrl(url4) {
|
|
143158
|
+
return url4.replace(/\.git$/, "").toLowerCase();
|
|
143159
|
+
}
|
|
143160
|
+
function rejectIfLeadingDash(value2, kind) {
|
|
143161
|
+
if (value2.startsWith("-")) {
|
|
143162
|
+
throw new Error(`Blocked: ${kind} '${value2}' starts with '-' \u2014 git could parse it as a flag.`);
|
|
143163
|
+
}
|
|
143164
|
+
}
|
|
143165
|
+
var SYMBOLIC_REFS = /* @__PURE__ */ new Set(["HEAD", "FETCH_HEAD", "ORIG_HEAD", "MERGE_HEAD"]);
|
|
143166
|
+
function rejectSpecialRef(value2, kind) {
|
|
143167
|
+
rejectIfLeadingDash(value2, kind);
|
|
143168
|
+
if (value2.startsWith("refs/")) {
|
|
143169
|
+
throw new Error(
|
|
143170
|
+
`Blocked: ${kind} '${value2}' is a fully-qualified ref path. Use a bare branch name (e.g. 'feature/foo' or 'main'), not a 'refs/heads/...' form.`
|
|
143171
|
+
);
|
|
143172
|
+
}
|
|
143173
|
+
if (SYMBOLIC_REFS.has(value2)) {
|
|
143174
|
+
throw new Error(
|
|
143175
|
+
`Blocked: ${kind} '${value2}' is a git symbolic ref, not a branch name. Pass the resolved branch name (e.g. 'main'), or omit branchName to push the current branch.`
|
|
143176
|
+
);
|
|
143177
|
+
}
|
|
143178
|
+
const BAD = /[:+^~?*[\\\s]/;
|
|
143179
|
+
const badMatch = value2.match(BAD);
|
|
143180
|
+
if (badMatch) {
|
|
143181
|
+
throw new Error(
|
|
143182
|
+
`Blocked: ${kind} '${value2}' contains '${badMatch[0]}', which git interprets as refspec/revision syntax, not as part of a branch name.`
|
|
143183
|
+
);
|
|
143184
|
+
}
|
|
143185
|
+
}
|
|
143186
|
+
function validateTagName(tag) {
|
|
143187
|
+
rejectIfLeadingDash(tag, "tag");
|
|
143188
|
+
if (!/^[A-Za-z0-9._/-]+$/.test(tag)) {
|
|
143189
|
+
throw new Error(
|
|
143190
|
+
`Blocked: tag '${tag}' contains characters that could be parsed as a refspec or flag. Tags must match [A-Za-z0-9._/-]+.`
|
|
143191
|
+
);
|
|
143192
|
+
}
|
|
143193
|
+
}
|
|
143194
|
+
function validatePushDestination(ctx, branch) {
|
|
143195
|
+
const pushUrl = ctx.toolState.pushUrl;
|
|
143196
|
+
if (!pushUrl) throw new Error("pushUrl not set - setupGit must run before push_branch");
|
|
143197
|
+
const dest = getPushDestination(branch, ctx.toolState.pushDest);
|
|
143198
|
+
if (normalizeUrl(dest.url) !== normalizeUrl(pushUrl)) {
|
|
143199
|
+
throw new Error(
|
|
143200
|
+
`Push blocked: destination does not match expected repository.
|
|
143201
|
+
Expected: ${pushUrl}
|
|
143202
|
+
Actual: ${dest.url}
|
|
143203
|
+
Git configuration may have been tampered with.`
|
|
143204
|
+
);
|
|
143205
|
+
}
|
|
143206
|
+
return dest;
|
|
143207
|
+
}
|
|
143208
|
+
var PushBranch = type({
|
|
143209
|
+
branchName: type.string.describe("The branch name to push (defaults to current branch)").optional(),
|
|
143210
|
+
force: type.boolean.describe("Force push (use with caution)").default(false)
|
|
143211
|
+
});
|
|
143212
|
+
function PushBranchTool(ctx) {
|
|
143213
|
+
const defaultBranch = ctx.repo.data.default_branch || "main";
|
|
143214
|
+
const pushPermission = ctx.payload.push;
|
|
143215
|
+
return tool({
|
|
143216
|
+
name: "push_branch",
|
|
143217
|
+
description: "Push the current branch to the remote repository. Omit branchName to push the current branch (recommended). If specifying branchName, use the LOCAL branch name (e.g., 'pr-1'), not the remote branch name. The correct remote and remote branch are determined automatically from branch config set by checkout_pr. Requires a clean working tree. Runs the repository prepush hook (if configured) before the network push \u2014 hook failure means tests/lint or similar in that script failed, not necessarily a Pullfrog timeout. Never force push unless explicitly requested. Pushes to the default branch are blocked in restricted mode.",
|
|
143218
|
+
parameters: PushBranch,
|
|
143219
|
+
execute: execute(async ({ branchName, force }) => {
|
|
143220
|
+
if (pushPermission === "disabled") {
|
|
143221
|
+
throw new Error("Push is disabled. This repository is configured for read-only access.");
|
|
143222
|
+
}
|
|
143223
|
+
const branch = branchName || $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false });
|
|
143224
|
+
rejectSpecialRef(branch, "branch");
|
|
143225
|
+
const status = $("git", ["status", "--porcelain"], { log: false });
|
|
143226
|
+
if (status) {
|
|
143227
|
+
throw new Error(
|
|
143228
|
+
`push blocked: working tree is not clean (tracked changes and/or untracked files). commit, discard, or remove stray artifacts before pushing.
|
|
143229
|
+
|
|
143230
|
+
git status:
|
|
143231
|
+
${status}`
|
|
143232
|
+
);
|
|
143233
|
+
}
|
|
143234
|
+
const pushDest = validatePushDestination(ctx, branch);
|
|
143235
|
+
if (pushPermission === "restricted" && pushDest.remoteBranch === defaultBranch) {
|
|
143236
|
+
throw new Error(
|
|
143237
|
+
`Push blocked: cannot push directly to default branch '${pushDest.remoteBranch}'. Create a feature branch and open a PR instead.`
|
|
143238
|
+
);
|
|
143239
|
+
}
|
|
143240
|
+
const refspec = branch === pushDest.remoteBranch ? branch : `${branch}:${pushDest.remoteBranch}`;
|
|
143241
|
+
const pushArgs = force ? ["--force", "-u", pushDest.remoteName, refspec] : ["-u", pushDest.remoteName, refspec];
|
|
143242
|
+
const prepushHook = await executeLifecycleHook({
|
|
143243
|
+
event: "prepush",
|
|
143244
|
+
script: ctx.prepushScript
|
|
143245
|
+
});
|
|
143246
|
+
if (prepushHook.warning) {
|
|
143247
|
+
throw new Error(prepushHook.warning);
|
|
143248
|
+
}
|
|
143249
|
+
const postHookStatus = $("git", ["status", "--porcelain"], { log: false });
|
|
143250
|
+
if (postHookStatus) {
|
|
143251
|
+
throw new Error(
|
|
143252
|
+
`push blocked: the prepush hook modified the working tree. those changes are not included in the push. commit or discard them (or change the hook to not mutate tracked files) before retrying.
|
|
143253
|
+
|
|
143254
|
+
git status:
|
|
143255
|
+
${postHookStatus}`
|
|
143256
|
+
);
|
|
143257
|
+
}
|
|
143258
|
+
log.debug(`pushing ${branch} to ${pushDest.remoteName}/${pushDest.remoteBranch}`);
|
|
143259
|
+
if (force) {
|
|
143260
|
+
log.warning(`force pushing - this will overwrite remote history`);
|
|
143261
|
+
}
|
|
143262
|
+
try {
|
|
143263
|
+
await $git("push", pushArgs, {
|
|
143264
|
+
token: ctx.gitToken
|
|
143265
|
+
});
|
|
143266
|
+
} catch (err) {
|
|
143267
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
143268
|
+
if (msg.includes("fetch first") || msg.includes("non-fast-forward")) {
|
|
143269
|
+
const integrateStep = ctx.payload.shell === "disabled" ? `2. use the git tool to merge the remote branch into yours: git({ command: "merge", args: ["origin/${pushDest.remoteBranch}"] })` : `2. use the git tool to rebase or merge your changes on top: git({ command: "merge", args: ["origin/${pushDest.remoteBranch}"] }) (or 'rebase')`;
|
|
143270
|
+
throw new Error(
|
|
143271
|
+
`push rejected: the remote branch '${pushDest.remoteBranch}' has new commits you don't have locally.
|
|
143272
|
+
|
|
143273
|
+
to resolve this:
|
|
143274
|
+
1. use git_fetch to fetch the remote branch: git_fetch({ ref: "${pushDest.remoteBranch}" })
|
|
143275
|
+
${integrateStep}
|
|
143276
|
+
3. resolve any merge conflicts if needed
|
|
143277
|
+
4. retry push_branch`
|
|
143278
|
+
);
|
|
143279
|
+
}
|
|
143280
|
+
throw err;
|
|
143281
|
+
}
|
|
143282
|
+
return {
|
|
143283
|
+
success: true,
|
|
143284
|
+
branch,
|
|
143285
|
+
remoteBranch: pushDest.remoteBranch,
|
|
143286
|
+
remote: pushDest.remoteName,
|
|
143287
|
+
force,
|
|
143288
|
+
message: `successfully pushed ${branch} to ${pushDest.remoteName}/${pushDest.remoteBranch}`
|
|
143289
|
+
};
|
|
143290
|
+
})
|
|
143291
|
+
});
|
|
143292
|
+
}
|
|
143293
|
+
var AUTH_REQUIRED_REDIRECT = {
|
|
143294
|
+
push: "use the push_branch tool instead \u2014 it handles authentication and permission checks.",
|
|
143295
|
+
fetch: "use the git_fetch tool instead \u2014 it handles authentication.",
|
|
143296
|
+
pull: "use git_fetch to fetch the remote ref, then call this git tool with command 'merge' locally.",
|
|
143297
|
+
clone: "the repository is already cloned. use checkout_pr for PR branches."
|
|
143298
|
+
};
|
|
143299
|
+
var NOSHELL_BLOCKED_SUBCOMMANDS = {
|
|
143300
|
+
config: "Blocked: git config can set up filter drivers or hooks that execute arbitrary code.",
|
|
143301
|
+
submodule: "Blocked: git submodule can reference malicious repositories and execute code on update.",
|
|
143302
|
+
"update-index": "Blocked: git update-index can modify index entries in ways that bypass file protections.",
|
|
143303
|
+
"filter-branch": "Blocked: git filter-branch executes arbitrary code on repository history.",
|
|
143304
|
+
replace: "Blocked: git replace can redirect object lookups.",
|
|
143305
|
+
// subcommands that accept --exec or similar flags for arbitrary code execution
|
|
143306
|
+
rebase: "Blocked: git rebase --exec can execute arbitrary shell commands. Use 'merge' instead to integrate remote changes.",
|
|
143307
|
+
bisect: "Blocked: git bisect run can execute arbitrary shell commands. Bisect by hand (bisect start/good/bad/reset) is not available through this tool either \u2014 ask the user to run the bisect if needed.",
|
|
143308
|
+
// difftool/mergetool exist to shell out to external diff/merge programs.
|
|
143309
|
+
// both accept `--extcmd` / `-x` (difftool) or configured tool commands
|
|
143310
|
+
// (mergetool) that run arbitrary code. NOSHELL_BLOCKED_ARGS catches the
|
|
143311
|
+
// long `--extcmd` form, but not the `-x` short form — and globally blocking
|
|
143312
|
+
// `-x` would false-positive on `git cherry-pick -x`. block the subcommands
|
|
143313
|
+
// wholesale instead; neither has a meaningful use in an automated agent
|
|
143314
|
+
// workflow (agents use `git diff` / `git show` for diffs and resolve
|
|
143315
|
+
// conflicts via file edits, not a TUI merge tool).
|
|
143316
|
+
difftool: "Blocked: git difftool runs an external diff program via --extcmd/-x or configured tool and can execute arbitrary shell commands. Use 'diff' (or 'show' for single commits) to inspect changes \u2014 those output directly and don't invoke an external tool.",
|
|
143317
|
+
mergetool: "Blocked: git mergetool runs an external merge program configured via mergetool.<name>.cmd and can execute arbitrary shell commands. Resolve conflicts by editing the files directly (conflict markers are written into the working tree) and then commit."
|
|
143318
|
+
};
|
|
143319
|
+
var NOSHELL_BLOCKED_ARGS = ["--exec", "--extcmd", "--upload-pack", "--receive-pack"];
|
|
143320
|
+
var COLLAPSE_THRESHOLD = 200;
|
|
143321
|
+
var subcommandPattern = regex("^[a-z][a-z0-9-]*$");
|
|
143322
|
+
var Git = type({
|
|
143323
|
+
command: type(subcommandPattern).describe("Git command (e.g., 'status', 'log', 'diff')"),
|
|
143324
|
+
args: type.string.array().describe("Additional arguments for the git command").optional()
|
|
143325
|
+
});
|
|
143326
|
+
function GitTool(ctx) {
|
|
143327
|
+
return tool({
|
|
143328
|
+
name: "git",
|
|
143329
|
+
description: "Run git commands. For push/fetch, use the dedicated MCP tools (push_branch, git_fetch). git pull is not available \u2014 use git_fetch then this tool with command 'merge'.",
|
|
143330
|
+
parameters: Git,
|
|
143331
|
+
execute: execute(async (params) => {
|
|
143332
|
+
const command = params.command;
|
|
143333
|
+
const args2 = params.args ?? [];
|
|
143334
|
+
const redirect = AUTH_REQUIRED_REDIRECT[command];
|
|
143335
|
+
if (redirect) {
|
|
143336
|
+
throw new Error(`git ${command} is not available through this tool \u2014 ${redirect}`);
|
|
143337
|
+
}
|
|
143338
|
+
if (ctx.payload.shell === "disabled") {
|
|
143339
|
+
const blocked = NOSHELL_BLOCKED_SUBCOMMANDS[command];
|
|
143340
|
+
if (blocked) {
|
|
143341
|
+
throw new Error(blocked);
|
|
143342
|
+
}
|
|
143343
|
+
for (const arg4 of args2) {
|
|
143344
|
+
const isBlocked = NOSHELL_BLOCKED_ARGS.some(
|
|
143345
|
+
(flag) => arg4 === flag || arg4.startsWith(flag + "=")
|
|
143346
|
+
);
|
|
143347
|
+
if (isBlocked) {
|
|
143348
|
+
throw new Error(
|
|
143349
|
+
`Blocked: '${arg4}' flag can execute arbitrary code and is not allowed.`
|
|
143350
|
+
);
|
|
143351
|
+
}
|
|
143352
|
+
}
|
|
143353
|
+
}
|
|
143354
|
+
const output = $("git", [command, ...args2], { log: false });
|
|
143355
|
+
const lineCount = output.split("\n").length;
|
|
143356
|
+
if (lineCount > COLLAPSE_THRESHOLD) {
|
|
143357
|
+
log.group(`git ${command} output (${lineCount} lines)`, () => {
|
|
143358
|
+
log.info(output);
|
|
143359
|
+
});
|
|
143360
|
+
} else if (output) {
|
|
143361
|
+
log.info(output);
|
|
143362
|
+
}
|
|
143363
|
+
return { success: true, output };
|
|
143364
|
+
})
|
|
143365
|
+
});
|
|
143366
|
+
}
|
|
143367
|
+
var GitFetch = type({
|
|
143368
|
+
ref: type.string.describe("Ref to fetch: branch name, tag, or 'pull/N/head' for PRs"),
|
|
143369
|
+
depth: type.number.describe("Fetch depth (for shallow clones)").optional()
|
|
143370
|
+
});
|
|
143371
|
+
function GitFetchTool(ctx) {
|
|
143372
|
+
return tool({
|
|
143373
|
+
name: "git_fetch",
|
|
143374
|
+
description: "Fetch refs from remote repository. Use this instead of git fetch directly.",
|
|
143375
|
+
parameters: GitFetch,
|
|
143376
|
+
execute: execute(async (params) => {
|
|
143377
|
+
rejectIfLeadingDash(params.ref, "ref");
|
|
143378
|
+
const fetchArgs = ["--no-tags", "origin", params.ref];
|
|
143379
|
+
if (params.depth !== void 0) {
|
|
143380
|
+
fetchArgs.push(`--depth=${params.depth}`);
|
|
143381
|
+
}
|
|
143382
|
+
await $git("fetch", fetchArgs, {
|
|
143383
|
+
token: ctx.gitToken
|
|
143384
|
+
});
|
|
143385
|
+
return { success: true, ref: params.ref };
|
|
143386
|
+
})
|
|
143387
|
+
});
|
|
143388
|
+
}
|
|
143389
|
+
var DeleteBranch = type({
|
|
143390
|
+
branchName: type.string.describe("Remote branch to delete")
|
|
143391
|
+
});
|
|
143392
|
+
function DeleteBranchTool(ctx) {
|
|
143393
|
+
const pushPermission = ctx.payload.push;
|
|
143394
|
+
const defaultBranch = ctx.repo.data.default_branch || "main";
|
|
143395
|
+
return tool({
|
|
143396
|
+
name: "delete_branch",
|
|
143397
|
+
description: "Delete a remote branch. Requires push: enabled permission. Deletion of the repository's default branch is always blocked regardless of permission mode.",
|
|
143398
|
+
parameters: DeleteBranch,
|
|
143399
|
+
execute: execute(async (params) => {
|
|
143400
|
+
if (pushPermission !== "enabled") {
|
|
143401
|
+
throw new Error(
|
|
143402
|
+
"Branch deletion requires push: enabled permission. Current mode only allows pushing to non-protected branches."
|
|
143403
|
+
);
|
|
143404
|
+
}
|
|
143405
|
+
rejectSpecialRef(params.branchName, "branchName");
|
|
143406
|
+
if (params.branchName === defaultBranch) {
|
|
143407
|
+
throw new Error(
|
|
143408
|
+
`Blocked: cannot delete the default branch '${defaultBranch}'. If you really need to delete or rename it, do it manually via the repository settings.`
|
|
143409
|
+
);
|
|
143410
|
+
}
|
|
143411
|
+
await $git("push", ["origin", "--delete", `refs/heads/${params.branchName}`], {
|
|
143412
|
+
token: ctx.gitToken
|
|
143413
|
+
});
|
|
143414
|
+
return { success: true, deleted: params.branchName };
|
|
143415
|
+
})
|
|
143416
|
+
});
|
|
143417
|
+
}
|
|
143418
|
+
var PushTags = type({
|
|
143419
|
+
tag: type.string.describe("Tag name to push"),
|
|
143420
|
+
force: type.boolean.describe("Force push the tag").default(false)
|
|
143421
|
+
});
|
|
143422
|
+
function PushTagsTool(ctx) {
|
|
143423
|
+
const pushPermission = ctx.payload.push;
|
|
143424
|
+
return tool({
|
|
143425
|
+
name: "push_tags",
|
|
143426
|
+
description: "Push a tag to remote. Requires push: enabled permission.",
|
|
143427
|
+
parameters: PushTags,
|
|
143428
|
+
execute: execute(async (params) => {
|
|
143429
|
+
if (pushPermission !== "enabled") {
|
|
143430
|
+
throw new Error(
|
|
143431
|
+
"Tag pushing requires push: enabled permission. Current mode only allows pushing branches."
|
|
143432
|
+
);
|
|
143433
|
+
}
|
|
143434
|
+
validateTagName(params.tag);
|
|
143435
|
+
const pushArgs = [...params.force ? ["-f"] : [], "origin", `refs/tags/${params.tag}`];
|
|
143436
|
+
await $git("push", pushArgs, {
|
|
143437
|
+
token: ctx.gitToken
|
|
143438
|
+
});
|
|
143439
|
+
return { success: true, tag: params.tag };
|
|
143440
|
+
})
|
|
143441
|
+
});
|
|
143442
|
+
}
|
|
143443
|
+
|
|
143444
|
+
// mcp/review.ts
|
|
143445
|
+
function getHttpStatus(err) {
|
|
143446
|
+
if (typeof err !== "object" || err === null) return void 0;
|
|
143447
|
+
const status = err.status;
|
|
143448
|
+
return typeof status === "number" ? status : void 0;
|
|
143449
|
+
}
|
|
143450
|
+
function commentableLinesForFile(patch) {
|
|
143451
|
+
const right = /* @__PURE__ */ new Set();
|
|
143452
|
+
const left = /* @__PURE__ */ new Set();
|
|
143453
|
+
if (!patch) return { RIGHT: right, LEFT: left };
|
|
143454
|
+
let oldLine = 0;
|
|
143455
|
+
let newLine = 0;
|
|
143456
|
+
for (const line of patch.split("\n")) {
|
|
143457
|
+
const hunk = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
143458
|
+
if (hunk) {
|
|
143459
|
+
oldLine = parseInt(hunk[1], 10);
|
|
143460
|
+
newLine = parseInt(hunk[2], 10);
|
|
143461
|
+
continue;
|
|
143462
|
+
}
|
|
143463
|
+
const changeType = line[0];
|
|
143464
|
+
if (changeType === "+") {
|
|
143465
|
+
right.add(newLine);
|
|
143466
|
+
newLine++;
|
|
143467
|
+
} else if (changeType === "-") {
|
|
143468
|
+
left.add(oldLine);
|
|
143469
|
+
oldLine++;
|
|
143470
|
+
} else if (changeType === " ") {
|
|
143471
|
+
right.add(newLine);
|
|
143472
|
+
left.add(oldLine);
|
|
143473
|
+
newLine++;
|
|
143474
|
+
oldLine++;
|
|
143475
|
+
}
|
|
143476
|
+
}
|
|
143477
|
+
return { RIGHT: right, LEFT: left };
|
|
143478
|
+
}
|
|
143479
|
+
async function buildCommentableMap(ctx, pullNumber) {
|
|
143480
|
+
const cached4 = ctx.toolState.commentableLinesByFile;
|
|
143481
|
+
const cachedFor = ctx.toolState.commentableLinesPullNumber;
|
|
143482
|
+
const cachedSha = ctx.toolState.commentableLinesCheckoutSha;
|
|
143483
|
+
const currentSha = ctx.toolState.checkoutSha;
|
|
143484
|
+
if (cached4 && cachedFor === pullNumber && cachedSha && cachedSha === currentSha) return cached4;
|
|
143485
|
+
const files = await ctx.octokit.paginate(ctx.octokit.rest.pulls.listFiles, {
|
|
143486
|
+
owner: ctx.repo.owner,
|
|
143487
|
+
repo: ctx.repo.name,
|
|
143488
|
+
pull_number: pullNumber,
|
|
143489
|
+
per_page: 100
|
|
143490
|
+
});
|
|
143491
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
143492
|
+
for (const file2 of files) {
|
|
143493
|
+
map2.set(file2.filename, commentableLinesForFile(file2.patch));
|
|
143494
|
+
}
|
|
143495
|
+
return map2;
|
|
143496
|
+
}
|
|
143497
|
+
function validateInlineComments(comments, map2) {
|
|
143498
|
+
const valid = [];
|
|
143499
|
+
const dropped = [];
|
|
143500
|
+
for (const c2 of comments) {
|
|
143501
|
+
const side = c2.side === "LEFT" ? "LEFT" : "RIGHT";
|
|
143502
|
+
const line = c2.line ?? 0;
|
|
143503
|
+
const startLine = c2.start_line ?? line;
|
|
143504
|
+
const lines = map2.get(c2.path);
|
|
143505
|
+
const record3 = (reason) => {
|
|
143506
|
+
const entry = { path: c2.path, line, side, reason };
|
|
143507
|
+
if (c2.start_line != null) entry.startLine = c2.start_line;
|
|
143508
|
+
dropped.push(entry);
|
|
143509
|
+
};
|
|
143510
|
+
if (!lines) {
|
|
143511
|
+
record3(`file not in PR diff`);
|
|
143512
|
+
continue;
|
|
143513
|
+
}
|
|
143514
|
+
if (lines.LEFT.size === 0 && lines.RIGHT.size === 0) {
|
|
143515
|
+
record3(`file has no textual diff (binary, pure rename, or mode change)`);
|
|
143516
|
+
continue;
|
|
143517
|
+
}
|
|
143518
|
+
const anchors = lines[side];
|
|
143519
|
+
if (!anchors.has(line)) {
|
|
143520
|
+
record3(`line ${line} (${side}) is not inside a diff hunk`);
|
|
143521
|
+
continue;
|
|
143522
|
+
}
|
|
143523
|
+
if (c2.start_line != null && c2.start_line > line) {
|
|
143524
|
+
record3(
|
|
143525
|
+
`start_line ${c2.start_line} is after line ${line} \u2014 ranges must satisfy start_line <= line`
|
|
143526
|
+
);
|
|
143527
|
+
continue;
|
|
143528
|
+
}
|
|
143529
|
+
if (startLine !== line && !anchors.has(startLine)) {
|
|
143530
|
+
record3(`start_line ${startLine} (${side}) is not inside a diff hunk`);
|
|
143531
|
+
continue;
|
|
143532
|
+
}
|
|
143533
|
+
valid.push(c2);
|
|
143534
|
+
}
|
|
143535
|
+
return { valid, dropped };
|
|
143536
|
+
}
|
|
143537
|
+
var MAX_DROPPED_COMMENT_LINES = 50;
|
|
143538
|
+
function reviewSkipDecision(params) {
|
|
143539
|
+
if (params.body || params.hasComments) return null;
|
|
143540
|
+
if (!params.approved) {
|
|
143541
|
+
return {
|
|
143542
|
+
kind: "no-issues",
|
|
143543
|
+
reason: "no issues found \u2014 nothing to post"
|
|
143544
|
+
};
|
|
143545
|
+
}
|
|
143546
|
+
if (!params.prApproveEnabled) {
|
|
143547
|
+
return {
|
|
143548
|
+
kind: "empty-downgraded-approve",
|
|
143549
|
+
reason: "approve requested but prApproveEnabled is disabled; no feedback body or comments to post as a COMMENT review instead"
|
|
143550
|
+
};
|
|
143551
|
+
}
|
|
143552
|
+
return null;
|
|
143553
|
+
}
|
|
143554
|
+
function formatDroppedCommentsNote(dropped) {
|
|
143555
|
+
const renderEntry = (d3) => {
|
|
143556
|
+
const range2 = d3.startLine != null && d3.startLine !== d3.line ? `${d3.startLine}-${d3.line}` : `${d3.line}`;
|
|
143557
|
+
return `- \`${d3.path}:${range2}\` (${d3.side}) \u2014 ${d3.reason}`;
|
|
143558
|
+
};
|
|
143559
|
+
const shown = dropped.slice(0, MAX_DROPPED_COMMENT_LINES).map(renderEntry);
|
|
143560
|
+
const remainder = dropped.length - shown.length;
|
|
143561
|
+
if (remainder > 0) shown.push(`- \u2026and ${remainder} more dropped comment(s) not shown`);
|
|
143562
|
+
return `
|
|
143563
|
+
|
|
143564
|
+
---
|
|
143565
|
+
|
|
143566
|
+
**Note:** ${dropped.length} inline comment(s) dropped because they did not anchor to lines inside the PR diff:
|
|
143567
|
+
` + shown.join("\n");
|
|
143568
|
+
}
|
|
143569
|
+
var CreatePullRequestReview = type({
|
|
143570
|
+
pull_number: type.number.describe("The pull request number to review"),
|
|
143571
|
+
body: type.string.describe(
|
|
143572
|
+
"1-2 sentence high-level summary with urgency level, critical callouts, and feedback about code outside the diff. Specific feedback on diff lines goes in 'comments' array."
|
|
143573
|
+
).optional(),
|
|
143574
|
+
approved: type.boolean.describe(
|
|
143575
|
+
"Set to true to submit as an approval. ONLY when the review contains no actionable feedback \u2014 neither inline comments nor actionable content in the body. Defaults to false (comment-only review). Rejections are not supported."
|
|
143576
|
+
).optional(),
|
|
143577
|
+
commit_id: type.string.describe("Optional SHA of the commit being reviewed. Defaults to latest.").optional(),
|
|
143578
|
+
comments: type({
|
|
143579
|
+
path: type.string.describe(
|
|
143580
|
+
"The file path to comment on (relative to repo root). Must be a file that appears in the PR diff."
|
|
143581
|
+
),
|
|
143582
|
+
line: type.number.describe(
|
|
143583
|
+
"Line number to comment on. For multi-line ranges, this is the end line. Use NEW column from diff format."
|
|
143584
|
+
),
|
|
143585
|
+
side: type.enumerated("LEFT", "RIGHT").describe(
|
|
143586
|
+
"Side of the diff: LEFT (old code, lines starting with -) or RIGHT (new code, lines starting with + or unchanged). Defaults to RIGHT."
|
|
143587
|
+
).optional(),
|
|
143588
|
+
body: type.string.describe("Explanatory comment text (optional if suggestion is provided)").optional(),
|
|
143589
|
+
suggestion: type.string.describe(
|
|
143590
|
+
"Full replacement code for the line range [start_line, line]. MUST preserve the exact indentation of the original code."
|
|
143591
|
+
).optional(),
|
|
143592
|
+
start_line: type.number.describe(
|
|
143593
|
+
"Start line for multi-line comment ranges. Omit for single-line comments. The range [start_line, line] defines which lines a suggestion replaces."
|
|
143594
|
+
).optional()
|
|
143595
|
+
}).array().describe(
|
|
143596
|
+
"Inline comments on lines within diff hunks. Feedback about code outside the diff goes in 'body' instead."
|
|
143597
|
+
).optional()
|
|
143598
|
+
});
|
|
143599
|
+
function CreatePullRequestReviewTool(ctx) {
|
|
143600
|
+
return tool({
|
|
143601
|
+
name: "create_pull_request_review",
|
|
143602
|
+
description: `Submit a review for an existing pull request. Each call creates a permanent, visible review on the PR \u2014 NEVER submit test or diagnostic reviews. Reviews with no body AND no comments are silently skipped (nothing to post). IMPORTANT: 95%+ of feedback should be in 'comments' array with file paths and line numbers. Only use 'body' for a 1-2 sentence summary with urgency and critical callouts. Use 'suggestion' to propose replacement code - MUST preserve exact indentation of original code. The first submission may error once with a one-time diff-coverage nudge listing unread TOC regions \u2014 retry with the same arguments and the pre-flight will not block again. Example replacing lines 42-44 (3 lines) with 5 lines: { path: 'src/api.ts', start_line: 42, line: 44, suggestion: ' const result = await fetch(url);\\n if (!result.ok) {\\n log.error(result.status);\\n throw new Error("request failed");\\n }' } CONSTRAINT: Inline comments can ONLY target files and lines that appear in the PR diff. Comments anchored outside a diff hunk are dropped automatically (with a note appended to the review body) \u2014 the rest of the review still posts.`,
|
|
143603
|
+
parameters: CreatePullRequestReview,
|
|
143604
|
+
execute: execute(async ({ pull_number, body, approved, commit_id, comments = [] }) => {
|
|
143605
|
+
if (body) body = fixDoubleEscapedString(body);
|
|
143606
|
+
ctx.toolState.issueNumber = pull_number;
|
|
143607
|
+
const skip = reviewSkipDecision({
|
|
143608
|
+
approved: approved ?? false,
|
|
143609
|
+
body,
|
|
143610
|
+
hasComments: comments.length > 0,
|
|
143611
|
+
prApproveEnabled: ctx.prApproveEnabled
|
|
143612
|
+
});
|
|
143613
|
+
if (skip) {
|
|
143614
|
+
log.info(`skipping review submission: ${skip.reason}`);
|
|
143615
|
+
return { success: true, skipped: true, reason: skip.reason };
|
|
143616
|
+
}
|
|
143617
|
+
let event = approved ? "APPROVE" : "COMMENT";
|
|
143618
|
+
if (event === "APPROVE" && !ctx.prApproveEnabled) {
|
|
143619
|
+
log.info("prApproveEnabled is disabled \u2014 downgrading APPROVE to COMMENT");
|
|
143620
|
+
event = "COMMENT";
|
|
143621
|
+
}
|
|
143622
|
+
const params = {
|
|
143623
|
+
owner: ctx.repo.owner,
|
|
143624
|
+
repo: ctx.repo.name,
|
|
143625
|
+
pull_number,
|
|
143626
|
+
event
|
|
143627
|
+
};
|
|
143628
|
+
let latestHeadSha;
|
|
143629
|
+
if (commit_id) {
|
|
143630
|
+
params.commit_id = commit_id;
|
|
143631
|
+
} else {
|
|
143632
|
+
const pr = await ctx.octokit.rest.pulls.get({
|
|
143633
|
+
owner: ctx.repo.owner,
|
|
143634
|
+
repo: ctx.repo.name,
|
|
143635
|
+
pull_number
|
|
143636
|
+
});
|
|
143637
|
+
latestHeadSha = pr.data.head.sha;
|
|
143638
|
+
params.commit_id = ctx.toolState.checkoutSha ?? latestHeadSha;
|
|
143639
|
+
if (ctx.toolState.checkoutSha && latestHeadSha !== ctx.toolState.checkoutSha) {
|
|
143640
|
+
log.info(
|
|
143641
|
+
`anchoring review to checkout ${ctx.toolState.checkoutSha.slice(0, 7)} (HEAD is now ${latestHeadSha.slice(0, 7)})`
|
|
143642
|
+
);
|
|
143643
|
+
}
|
|
143644
|
+
}
|
|
143645
|
+
runDiffCoveragePreflight({ ctx });
|
|
143646
|
+
const reviewComments = comments.map((comment) => {
|
|
143647
|
+
let commentBody = fixDoubleEscapedString(comment.body || "");
|
|
143648
|
+
if (comment.suggestion !== void 0) {
|
|
143649
|
+
const suggestionBlock = "```suggestion\n" + comment.suggestion + "\n```";
|
|
143650
|
+
commentBody = commentBody ? commentBody + "\n\n" + suggestionBlock : suggestionBlock;
|
|
143651
|
+
}
|
|
143652
|
+
const side = comment.side || "RIGHT";
|
|
143653
|
+
const reviewComment = {
|
|
143654
|
+
path: comment.path,
|
|
143655
|
+
line: comment.line,
|
|
143656
|
+
body: commentBody,
|
|
143657
|
+
side
|
|
143658
|
+
};
|
|
143659
|
+
if (comment.start_line != null && comment.start_line !== comment.line) {
|
|
143660
|
+
reviewComment.start_line = comment.start_line;
|
|
143661
|
+
reviewComment.start_side = side;
|
|
143662
|
+
}
|
|
143663
|
+
return reviewComment;
|
|
143664
|
+
});
|
|
143665
|
+
let droppedComments = [];
|
|
143666
|
+
if (reviewComments.length > 0) {
|
|
143667
|
+
const commentableMap = await buildCommentableMap(ctx, pull_number);
|
|
143668
|
+
const validation = validateInlineComments(reviewComments, commentableMap);
|
|
143669
|
+
droppedComments = validation.dropped;
|
|
143670
|
+
if (droppedComments.length > 0) {
|
|
143671
|
+
log.info(
|
|
143672
|
+
`dropping ${droppedComments.length}/${reviewComments.length} inline comment(s) that do not anchor to PR diff lines`
|
|
143673
|
+
);
|
|
143674
|
+
}
|
|
143675
|
+
params.comments = validation.valid;
|
|
143676
|
+
}
|
|
143677
|
+
if (droppedComments.length > 0) {
|
|
143678
|
+
const note = formatDroppedCommentsNote(droppedComments);
|
|
143679
|
+
body = body ? body + note : note.replace(/^\n\n/, "");
|
|
143680
|
+
}
|
|
143681
|
+
if (!approved && !body && !params.comments?.length) {
|
|
143682
|
+
log.info("review has no body and all inline comments were dropped \u2014 skipping submission");
|
|
143683
|
+
return {
|
|
143684
|
+
success: true,
|
|
143685
|
+
skipped: true,
|
|
143686
|
+
reason: "all inline comments were invalid \u2014 nothing to post",
|
|
143687
|
+
droppedComments
|
|
143688
|
+
};
|
|
143689
|
+
}
|
|
143690
|
+
let result;
|
|
143691
|
+
try {
|
|
143692
|
+
result = body ? await createAndSubmitWithFooter(ctx, params, {
|
|
143693
|
+
body,
|
|
143694
|
+
approved: approved ?? false,
|
|
143695
|
+
hasComments: (params.comments?.length ?? 0) > 0
|
|
143696
|
+
}) : await createReviewWithStrandedRecovery(ctx, params);
|
|
143697
|
+
} catch (err) {
|
|
143698
|
+
if (getHttpStatus(err) !== 422 || !params.comments?.length) throw err;
|
|
143699
|
+
const details = params.comments.map((c2) => {
|
|
143700
|
+
const line = c2.line ?? 0;
|
|
143701
|
+
const startLine = c2.start_line ?? line;
|
|
143702
|
+
const range2 = startLine !== line ? `${startLine}-${line}` : `${line}`;
|
|
143703
|
+
return `${c2.path}:${range2} (${c2.side ?? "RIGHT"})`;
|
|
143704
|
+
});
|
|
143705
|
+
const rawMsg = err instanceof Error ? err.message : String(err);
|
|
143706
|
+
const checkoutRef = formatMcpToolRef(ctx.agentId, "checkout_pr");
|
|
143707
|
+
throw new Error(
|
|
143708
|
+
`GitHub rejected the review with 422 even after pre-validation. Likely causes (check "GitHub said" below to narrow down): (1) new commits pushed after pre-validation \u2014 call \`${checkoutRef}\` again to refresh the diff snapshot, then resubmit; (2) the review body exceeded GitHub's ~65KB limit \u2014 shorten it and retry; (3) a \`suggestion\` block is malformed (missing backticks, extra backticks, or wrong indentation) \u2014 inspect the affected comments below. If none apply, move the failing comments into the review body as text so the rest still posts. Affected comments: ${details.join(", ")}. GitHub said: ${rawMsg}`,
|
|
143709
|
+
{ cause: err }
|
|
143710
|
+
);
|
|
143711
|
+
}
|
|
143712
|
+
log.debug(`createReview response: ${JSON.stringify(result.data)}`);
|
|
143713
|
+
if (!result.data.id) {
|
|
143714
|
+
throw new Error(`createReview returned invalid data: ${JSON.stringify(result.data)}`);
|
|
143715
|
+
}
|
|
143716
|
+
const reviewId = result.data.id;
|
|
143717
|
+
const reviewNodeId = result.data.node_id;
|
|
143718
|
+
const actuallyReviewedSha = ctx.toolState.checkoutSha ?? params.commit_id;
|
|
143719
|
+
ctx.toolState.review = {
|
|
143720
|
+
id: reviewId,
|
|
143721
|
+
nodeId: reviewNodeId,
|
|
143722
|
+
reviewedSha: actuallyReviewedSha
|
|
143723
|
+
};
|
|
143724
|
+
if (ctx.toolState.checkoutSha && latestHeadSha && latestHeadSha !== ctx.toolState.checkoutSha) {
|
|
143725
|
+
const fromSha = ctx.toolState.checkoutSha;
|
|
143726
|
+
const toSha = latestHeadSha;
|
|
143727
|
+
ctx.toolState.beforeSha = fromSha;
|
|
143728
|
+
ctx.toolState.checkoutSha = toSha;
|
|
143729
|
+
log.info(
|
|
143730
|
+
`new commits detected during review: ${fromSha.slice(0, 7)}..${toSha.slice(0, 7)}`
|
|
143731
|
+
);
|
|
143732
|
+
return {
|
|
143733
|
+
success: true,
|
|
143734
|
+
reviewId,
|
|
143735
|
+
html_url: result.data.html_url,
|
|
143736
|
+
state: result.data.state,
|
|
143737
|
+
user: result.data.user?.login,
|
|
143738
|
+
submitted_at: result.data.submitted_at,
|
|
143739
|
+
droppedComments: droppedComments.length > 0 ? droppedComments : void 0,
|
|
143740
|
+
newCommits: {
|
|
143741
|
+
from: fromSha,
|
|
143742
|
+
to: toSha,
|
|
143743
|
+
instructions: `new commits were pushed while you were reviewing. call \`${formatMcpToolRef(ctx.agentId, "checkout_pr")}\` again to fetch the latest version \u2014 it will compute the incremental diff automatically. submit another review covering only the new changes. do not repeat feedback from your previous review.`
|
|
143744
|
+
}
|
|
143745
|
+
};
|
|
143746
|
+
}
|
|
143747
|
+
return {
|
|
143748
|
+
success: true,
|
|
143749
|
+
reviewId,
|
|
143750
|
+
html_url: result.data.html_url,
|
|
143751
|
+
state: result.data.state,
|
|
143752
|
+
user: result.data.user?.login,
|
|
143753
|
+
submitted_at: result.data.submitted_at,
|
|
143754
|
+
droppedComments: droppedComments.length > 0 ? droppedComments : void 0
|
|
143755
|
+
};
|
|
143756
|
+
})
|
|
143757
|
+
});
|
|
143758
|
+
}
|
|
143759
|
+
function runDiffCoveragePreflight(params) {
|
|
143760
|
+
const coverageState = params.ctx.toolState.diffCoverage;
|
|
143761
|
+
if (!coverageState) {
|
|
143762
|
+
log.debug("diff coverage pre-flight skipped: no diffCoverage state present in toolState");
|
|
143763
|
+
return;
|
|
143764
|
+
}
|
|
143765
|
+
if (coverageState.coveragePreflightRan) {
|
|
143766
|
+
log.debug("diff coverage pre-flight skipped: already ran in this session");
|
|
143767
|
+
return;
|
|
143768
|
+
}
|
|
143769
|
+
coverageState.coveragePreflightRan = true;
|
|
143770
|
+
log.debug(
|
|
143771
|
+
`diff coverage pre-flight start: diffPath=${coverageState.diffPath}, totalLines=${coverageState.totalLines}, tocEntries=${coverageState.tocEntries.length}, coveredRanges=${coverageState.coveredRanges.length}`
|
|
143772
|
+
);
|
|
143773
|
+
const breakdown = getDiffCoverageBreakdown({ state: coverageState });
|
|
143774
|
+
const unread = [];
|
|
143775
|
+
let unreadLines = 0;
|
|
143776
|
+
for (const file2 of breakdown.files) {
|
|
143777
|
+
if (file2.unreadRanges.length === 0) continue;
|
|
143778
|
+
const rangesText = file2.unreadRanges.map((range2) => `${range2.startLine}-${range2.endLine}`).join(", ");
|
|
143779
|
+
const fileUnreadLines = countLinesInRanges({ ranges: file2.unreadRanges });
|
|
143780
|
+
unread.push({ path: file2.filename, ranges: rangesText, unreadLines: fileUnreadLines });
|
|
143781
|
+
unreadLines += fileUnreadLines;
|
|
143782
|
+
}
|
|
143783
|
+
coverageState.lastBreakdown = renderDiffCoverageBreakdown({
|
|
143784
|
+
diffPath: coverageState.diffPath,
|
|
143785
|
+
breakdown
|
|
143786
|
+
});
|
|
143787
|
+
log.debug(
|
|
143788
|
+
`diff coverage pre-flight breakdown: coveredLines=${breakdown.coveredLines}, unreadLines=${unreadLines}`
|
|
143789
|
+
);
|
|
143790
|
+
if (unreadLines === 0) {
|
|
143791
|
+
log.debug("diff coverage pre-flight passed: no unread regions");
|
|
143792
|
+
return;
|
|
143793
|
+
}
|
|
143794
|
+
log.info(
|
|
143795
|
+
`diff coverage pre-flight nudge: unread lines=${unreadLines}, unread files=${unread.length}`
|
|
143796
|
+
);
|
|
143797
|
+
const unreadText = unread.map((entry) => `- ${entry.path} (${entry.unreadLines} lines, ${entry.ranges})`).join("\n");
|
|
143798
|
+
throw new Error(
|
|
143799
|
+
`diff coverage pre-flight: some TOC regions were not read before review submission. this is a one-time nudge \u2014 optionally read the ranges below from ${coverageState.diffPath}, then call create_pull_request_review again with the same arguments. this pre-flight will not block again in this review session.
|
|
143800
|
+
|
|
143801
|
+
unread TOC regions:
|
|
143802
|
+
${unreadText}
|
|
143803
|
+
|
|
143804
|
+
${coverageState.lastBreakdown}`
|
|
143805
|
+
);
|
|
143806
|
+
}
|
|
143807
|
+
async function clearStrandedPendingReview(ctx, params) {
|
|
143808
|
+
const originalErr = params.originalErr;
|
|
143809
|
+
const msg = originalErr instanceof Error ? originalErr.message.toLowerCase() : "";
|
|
143810
|
+
if (getHttpStatus(originalErr) !== 422 || !msg.includes("pending review")) throw originalErr;
|
|
143811
|
+
const reviews = await ctx.octokit.paginate(ctx.octokit.rest.pulls.listReviews, {
|
|
143812
|
+
owner: params.owner,
|
|
143813
|
+
repo: params.repo,
|
|
143814
|
+
pull_number: params.pull_number,
|
|
143815
|
+
per_page: 100
|
|
143816
|
+
}).catch((listErr) => {
|
|
143817
|
+
log.info(
|
|
143818
|
+
`\xBB listReviews failed during pending-review cleanup, surfacing original 422: ${listErr instanceof Error ? listErr.message : String(listErr)}`
|
|
143819
|
+
);
|
|
143820
|
+
throw originalErr;
|
|
143821
|
+
});
|
|
143822
|
+
const leftover = reviews.find((r) => r.state === "PENDING");
|
|
143823
|
+
if (!leftover?.id) throw originalErr;
|
|
143824
|
+
log.info(
|
|
143825
|
+
`\xBB clearing leftover pending review ${leftover.id} (likely stranded by a killed prior run)`
|
|
143826
|
+
);
|
|
143827
|
+
try {
|
|
143828
|
+
await ctx.octokit.rest.pulls.deletePendingReview({
|
|
143829
|
+
owner: params.owner,
|
|
143830
|
+
repo: params.repo,
|
|
143831
|
+
pull_number: params.pull_number,
|
|
143832
|
+
review_id: leftover.id
|
|
143833
|
+
});
|
|
143834
|
+
} catch (cleanupErr) {
|
|
143835
|
+
const cleanupStatus = getHttpStatus(cleanupErr);
|
|
143836
|
+
if (cleanupStatus !== 404 && cleanupStatus !== 422) throw cleanupErr;
|
|
143837
|
+
log.debug(`\xBB delete of leftover pending ${leftover.id} no-op (status ${cleanupStatus})`);
|
|
143838
|
+
}
|
|
143839
|
+
}
|
|
143840
|
+
async function createReviewWithStrandedRecovery(ctx, params) {
|
|
143841
|
+
try {
|
|
143842
|
+
return await ctx.octokit.rest.pulls.createReview(params);
|
|
143843
|
+
} catch (err) {
|
|
143844
|
+
await clearStrandedPendingReview(ctx, {
|
|
143845
|
+
owner: params.owner,
|
|
143846
|
+
repo: params.repo,
|
|
143847
|
+
pull_number: params.pull_number,
|
|
143848
|
+
originalErr: err
|
|
143849
|
+
});
|
|
143850
|
+
return await ctx.octokit.rest.pulls.createReview(params);
|
|
143851
|
+
}
|
|
143852
|
+
}
|
|
143853
|
+
async function createAndSubmitWithFooter(ctx, params, opts) {
|
|
143854
|
+
const { event: _2, ...pendingParams } = params;
|
|
143855
|
+
let pending;
|
|
143856
|
+
try {
|
|
143857
|
+
pending = await ctx.octokit.rest.pulls.createReview(pendingParams);
|
|
143858
|
+
} catch (err) {
|
|
143859
|
+
await clearStrandedPendingReview(ctx, {
|
|
143860
|
+
owner: params.owner,
|
|
143861
|
+
repo: params.repo,
|
|
143862
|
+
pull_number: params.pull_number,
|
|
143863
|
+
originalErr: err
|
|
143864
|
+
});
|
|
143865
|
+
pending = await ctx.octokit.rest.pulls.createReview(pendingParams);
|
|
143866
|
+
}
|
|
143867
|
+
if (!pending.data.id) {
|
|
143868
|
+
throw new Error(`createReview returned invalid data: ${JSON.stringify(pending.data)}`);
|
|
143869
|
+
}
|
|
143870
|
+
try {
|
|
143871
|
+
const customParts = [];
|
|
143872
|
+
if (!opts.approved) {
|
|
143873
|
+
const apiUrl = getApiUrl();
|
|
143874
|
+
if (opts.hasComments) {
|
|
143875
|
+
const fixAllUrl = `${apiUrl}/trigger/${ctx.repo.owner}/${ctx.repo.name}/${params.pull_number}?action=fix&review_id=${pending.data.id}`;
|
|
143876
|
+
const fixApprovedUrl = `${apiUrl}/trigger/${ctx.repo.owner}/${ctx.repo.name}/${params.pull_number}?action=fix-approved&review_id=${pending.data.id}`;
|
|
143877
|
+
customParts.push(`[Fix all \u2794](${fixAllUrl})`, `[Fix \u{1F44D}s \u2794](${fixApprovedUrl})`);
|
|
143878
|
+
} else {
|
|
143879
|
+
const fixUrl = `${apiUrl}/trigger/${ctx.repo.owner}/${ctx.repo.name}/${params.pull_number}?action=fix&review_id=${pending.data.id}`;
|
|
143880
|
+
customParts.push(`[Fix it \u2794](${fixUrl})`);
|
|
143881
|
+
}
|
|
143882
|
+
}
|
|
143883
|
+
const footer = buildPullfrogFooter({
|
|
143884
|
+
workflowRun: ctx.runId ? { owner: ctx.repo.owner, repo: ctx.repo.name, runId: ctx.runId, jobId: ctx.jobId } : void 0,
|
|
143885
|
+
customParts,
|
|
143886
|
+
model: ctx.toolState.model
|
|
143887
|
+
});
|
|
143888
|
+
return await ctx.octokit.rest.pulls.submitReview({
|
|
143889
|
+
owner: params.owner,
|
|
143890
|
+
repo: params.repo,
|
|
143891
|
+
pull_number: params.pull_number,
|
|
143892
|
+
review_id: pending.data.id,
|
|
143893
|
+
event: params.event,
|
|
143894
|
+
body: opts.body + footer
|
|
143895
|
+
});
|
|
143896
|
+
} catch (err) {
|
|
143897
|
+
try {
|
|
143898
|
+
await ctx.octokit.rest.pulls.deletePendingReview({
|
|
143899
|
+
owner: params.owner,
|
|
143900
|
+
repo: params.repo,
|
|
143901
|
+
pull_number: params.pull_number,
|
|
143902
|
+
review_id: pending.data.id
|
|
143903
|
+
});
|
|
143904
|
+
log.debug(`\xBB deleted leftover pending review ${pending.data.id} after failure`);
|
|
143905
|
+
} catch (cleanupErr) {
|
|
143906
|
+
log.debug(
|
|
143907
|
+
`\xBB failed to delete pending review ${pending.data.id}: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`
|
|
143908
|
+
);
|
|
143909
|
+
}
|
|
143910
|
+
throw err;
|
|
143911
|
+
}
|
|
143912
|
+
}
|
|
143913
|
+
async function reportReviewNodeId(ctx, params) {
|
|
143914
|
+
await patchWorkflowRunFields(ctx, { reviewNodeId: params.nodeId });
|
|
143915
|
+
}
|
|
143916
|
+
|
|
142460
143917
|
// mcp/checkout.ts
|
|
142461
143918
|
function formatFilesWithLineNumbers(files) {
|
|
142462
143919
|
const output = [];
|
|
@@ -142523,7 +143980,10 @@ function formatFilesWithLineNumbers(files) {
|
|
|
142523
143980
|
}
|
|
142524
143981
|
const tocLines = [`## Files (${files.length})`];
|
|
142525
143982
|
for (const entry of tocEntries) {
|
|
142526
|
-
|
|
143983
|
+
const anchor = createHash2("sha256").update(entry.filename).digest("hex");
|
|
143984
|
+
tocLines.push(
|
|
143985
|
+
`- ${entry.filename} \u2192 lines ${entry.startLine}-${entry.endLine} \xB7 diff-${anchor}`
|
|
143986
|
+
);
|
|
142527
143987
|
}
|
|
142528
143988
|
tocLines.push("");
|
|
142529
143989
|
tocLines.push("---");
|
|
@@ -142545,7 +144005,7 @@ async function fetchAndFormatPrDiff(ctx, pullNumber) {
|
|
|
142545
144005
|
pull_number: pullNumber,
|
|
142546
144006
|
per_page: 100
|
|
142547
144007
|
});
|
|
142548
|
-
return formatFilesWithLineNumbers(files);
|
|
144008
|
+
return { ...formatFilesWithLineNumbers(files), files };
|
|
142549
144009
|
}
|
|
142550
144010
|
async function createTempBranch(params) {
|
|
142551
144011
|
const response = await params.octokit.rest.git.createRef({
|
|
@@ -142612,6 +144072,8 @@ async function ensureBeforeShaReachable(params) {
|
|
|
142612
144072
|
async function checkoutPrBranch(pr, params) {
|
|
142613
144073
|
const { octokit, owner, name, gitToken, toolState, beforeSha } = params;
|
|
142614
144074
|
log.info(`\xBB checking out PR #${pr.number}...`);
|
|
144075
|
+
rejectIfLeadingDash(pr.baseRef, "PR base ref");
|
|
144076
|
+
rejectIfLeadingDash(pr.headRef, "PR head ref");
|
|
142615
144077
|
const isFork = pr.headRepoFullName !== pr.baseRepoFullName;
|
|
142616
144078
|
const localBranch = `pr-${pr.number}`;
|
|
142617
144079
|
const isShallow = $("git", ["rev-parse", "--is-shallow-repository"], { log: false }).trim() === "true";
|
|
@@ -142622,7 +144084,7 @@ async function checkoutPrBranch(pr, params) {
|
|
|
142622
144084
|
if (!alreadyOnBranch) {
|
|
142623
144085
|
$("git", ["checkout", "-B", pr.baseRef, `origin/${pr.baseRef}`], { log: false });
|
|
142624
144086
|
log.debug(`\xBB fetching PR #${pr.number} (${localBranch})...`);
|
|
142625
|
-
await $git("fetch", ["--no-tags", "origin",
|
|
144087
|
+
await $git("fetch", ["--no-tags", "origin", `+pull/${pr.number}/head:${localBranch}`], {
|
|
142626
144088
|
token: gitToken
|
|
142627
144089
|
});
|
|
142628
144090
|
$("git", ["checkout", localBranch], { log: false });
|
|
@@ -142705,10 +144167,11 @@ async function checkoutPrBranch(pr, params) {
|
|
|
142705
144167
|
remoteBranch: pr.headRef,
|
|
142706
144168
|
localBranch
|
|
142707
144169
|
};
|
|
142708
|
-
await executeLifecycleHook({
|
|
144170
|
+
const postCheckoutHook = await executeLifecycleHook({
|
|
142709
144171
|
event: "post-checkout",
|
|
142710
144172
|
script: params.postCheckoutScript
|
|
142711
144173
|
});
|
|
144174
|
+
return { hookWarning: postCheckoutHook.warning };
|
|
142712
144175
|
}
|
|
142713
144176
|
function CheckoutPrTool(ctx) {
|
|
142714
144177
|
return tool({
|
|
@@ -142734,7 +144197,7 @@ function CheckoutPrTool(ctx) {
|
|
|
142734
144197
|
baseRepoFullName: prResponse.data.base.repo.full_name,
|
|
142735
144198
|
maintainerCanModify: prResponse.data.maintainer_can_modify
|
|
142736
144199
|
};
|
|
142737
|
-
await checkoutPrBranch(pr, {
|
|
144200
|
+
const checkoutResult = await checkoutPrBranch(pr, {
|
|
142738
144201
|
octokit: ctx.octokit,
|
|
142739
144202
|
owner: ctx.repo.owner,
|
|
142740
144203
|
name: ctx.repo.name,
|
|
@@ -142777,11 +144240,49 @@ ${diffPreview}`);
|
|
|
142777
144240
|
const diffPath = join3(tempDir, `pr-${pull_number}-${headShort}.diff`);
|
|
142778
144241
|
writeFileSync(diffPath, formatResult.content);
|
|
142779
144242
|
log.debug(`wrote diff to ${diffPath} (${formatResult.content.length} bytes)`);
|
|
144243
|
+
ctx.toolState.diffCoverage = createDiffCoverageState({
|
|
144244
|
+
diffPath,
|
|
144245
|
+
totalLines: countLines({ content: formatResult.content }),
|
|
144246
|
+
toc: formatResult.toc
|
|
144247
|
+
});
|
|
144248
|
+
log.debug(
|
|
144249
|
+
`\xBB diff coverage initialized: diffPath=${diffPath}, totalLines=${ctx.toolState.diffCoverage.totalLines}, tocEntries=${ctx.toolState.diffCoverage.tocEntries.length}`
|
|
144250
|
+
);
|
|
144251
|
+
const cached4 = /* @__PURE__ */ new Map();
|
|
144252
|
+
for (const file2 of formatResult.files) {
|
|
144253
|
+
cached4.set(file2.filename, commentableLinesForFile(file2.patch));
|
|
144254
|
+
}
|
|
144255
|
+
ctx.toolState.commentableLinesByFile = cached4;
|
|
144256
|
+
ctx.toolState.commentableLinesPullNumber = pull_number;
|
|
144257
|
+
ctx.toolState.commentableLinesCheckoutSha = ctx.toolState.checkoutSha;
|
|
142780
144258
|
const incrementalInstructions = incrementalDiffPath ? ` IMPORTANT: incrementalDiffPath contains ONLY the changes since the last reviewed version (computed via range-diff). you MUST read incrementalDiffPath FIRST to understand what changed, then use diffPath for full PR context. do NOT skip the incremental diff.` : "";
|
|
144259
|
+
const COMMIT_LOG_MAX = 200;
|
|
144260
|
+
const baseRange = `origin/${pr.baseRef}..HEAD`;
|
|
144261
|
+
let commitCount = 0;
|
|
144262
|
+
let commitLog = "";
|
|
144263
|
+
let commitLogUnavailable = false;
|
|
144264
|
+
try {
|
|
144265
|
+
commitCount = parseInt(
|
|
144266
|
+
$("git", ["rev-list", "--count", baseRange], { log: false }).trim() || "0",
|
|
144267
|
+
10
|
|
144268
|
+
);
|
|
144269
|
+
commitLog = $("git", ["log", "--oneline", `--max-count=${COMMIT_LOG_MAX}`, baseRange], {
|
|
144270
|
+
log: false
|
|
144271
|
+
});
|
|
144272
|
+
} catch (err) {
|
|
144273
|
+
commitLogUnavailable = true;
|
|
144274
|
+
log.debug(
|
|
144275
|
+
`\xBB unable to compute commit metadata for ${baseRange}: ${err instanceof Error ? err.message : String(err)}`
|
|
144276
|
+
);
|
|
144277
|
+
}
|
|
144278
|
+
const commitLogTruncated = commitCount > COMMIT_LOG_MAX;
|
|
144279
|
+
const hookWarningInstructions = checkoutResult.hookWarning ? ` HOOK WARNING: the post-checkout lifecycle hook reported a non-fatal failure (see hookWarning). decide whether to retry based on the guidance in that field before proceeding.` : "";
|
|
144280
|
+
const commitLogInstructions = commitLogUnavailable ? ` NOTE: commit metadata is partial (base ref unreachable, likely a shallow fetch). commitCount/commitLog may be 0/empty or incomplete; treat them as "unknown" rather than "no commits", and use \`git log\` directly if you need the full history.` : commitLogTruncated ? ` NOTE: commitLog was capped at ${COMMIT_LOG_MAX} entries out of ${commitCount} commits; use \`git log\` directly if you need the full history.` : "";
|
|
142781
144281
|
return {
|
|
142782
144282
|
success: true,
|
|
142783
144283
|
number: prResponse.data.number,
|
|
142784
144284
|
title: prResponse.data.title,
|
|
144285
|
+
body: prResponse.data.body,
|
|
142785
144286
|
base: pr.baseRef,
|
|
142786
144287
|
localBranch: `pr-${pull_number}`,
|
|
142787
144288
|
remoteBranch: `refs/heads/${pr.headRef}`,
|
|
@@ -142792,7 +144293,12 @@ ${diffPreview}`);
|
|
|
142792
144293
|
diffPath,
|
|
142793
144294
|
incrementalDiffPath,
|
|
142794
144295
|
toc: formatResult.toc,
|
|
142795
|
-
|
|
144296
|
+
commitCount,
|
|
144297
|
+
commitLog,
|
|
144298
|
+
commitLogTruncated,
|
|
144299
|
+
commitLogUnavailable,
|
|
144300
|
+
hookWarning: checkoutResult.hookWarning,
|
|
144301
|
+
instructions: `the diff file at diffPath contains a table of contents (TOC) at the top listing every changed file with its line range. use the TOC line ranges as your checklist and read specific files from the diff instead of reading the entire file. for example, if the TOC says "src/foo.ts \u2192 lines 5-42", read lines 5-42 from diffPath to see that file's changes. review files selectively based on relevance rather than reading everything sequentially. to inspect the PR's changed files, use diffPath \u2014 do NOT run \`git diff <base>..<head>\` to re-derive what's already in diffPath. the formatted diff with line numbers is authoritative. \`git log\` and \`git diff --stat\` are fine for commit-range overview, and \`git diff\` / \`git diff --cached\` are fine for inspecting *your own* uncommitted changes \u2014 but PR review content MUST come from diffPath. before your review is submitted, a one-time coverage pre-flight may error listing unread TOC regions. retry the same create_pull_request_review call to proceed \u2014 optionally after reading the listed ranges. the pre-flight will not block again this session. the local branch is 'localBranch' (pr-{number}), not the remote branch name. when pushing, omit branchName to use the current branch. do not use remoteBranch as a local branch name.` + incrementalInstructions + hookWarningInstructions + commitLogInstructions
|
|
142796
144302
|
};
|
|
142797
144303
|
})
|
|
142798
144304
|
});
|
|
@@ -143020,244 +144526,6 @@ function CommitInfoTool(ctx) {
|
|
|
143020
144526
|
});
|
|
143021
144527
|
}
|
|
143022
144528
|
|
|
143023
|
-
// mcp/git.ts
|
|
143024
|
-
function getPushDestination(branch, storedDest) {
|
|
143025
|
-
if (storedDest && storedDest.localBranch === branch) {
|
|
143026
|
-
log.debug(`using stored push destination: ${storedDest.remoteName}/${storedDest.remoteBranch}`);
|
|
143027
|
-
const url4 = $("git", ["remote", "get-url", "--push", storedDest.remoteName], {
|
|
143028
|
-
log: false
|
|
143029
|
-
}).trim();
|
|
143030
|
-
return { remoteName: storedDest.remoteName, remoteBranch: storedDest.remoteBranch, url: url4 };
|
|
143031
|
-
}
|
|
143032
|
-
try {
|
|
143033
|
-
const pushRemote = $("git", ["config", `branch.${branch}.pushRemote`], { log: false }).trim();
|
|
143034
|
-
const merge4 = $("git", ["config", `branch.${branch}.merge`], { log: false }).trim();
|
|
143035
|
-
const remoteBranch = merge4.replace(/^refs\/heads\//, "");
|
|
143036
|
-
const url4 = $("git", ["remote", "get-url", "--push", pushRemote], { log: false }).trim();
|
|
143037
|
-
return { remoteName: pushRemote, remoteBranch, url: url4 };
|
|
143038
|
-
} catch {
|
|
143039
|
-
log.debug(`no push config for ${branch}, falling back to origin/${branch}`);
|
|
143040
|
-
const url4 = $("git", ["remote", "get-url", "--push", "origin"], { log: false }).trim();
|
|
143041
|
-
return { remoteName: "origin", remoteBranch: branch, url: url4 };
|
|
143042
|
-
}
|
|
143043
|
-
}
|
|
143044
|
-
function normalizeUrl(url4) {
|
|
143045
|
-
return url4.replace(/\.git$/, "").toLowerCase();
|
|
143046
|
-
}
|
|
143047
|
-
function validatePushDestination(ctx, branch) {
|
|
143048
|
-
const pushUrl = ctx.toolState.pushUrl;
|
|
143049
|
-
if (!pushUrl) throw new Error("pushUrl not set - setupGit must run before push_branch");
|
|
143050
|
-
const dest = getPushDestination(branch, ctx.toolState.pushDest);
|
|
143051
|
-
if (normalizeUrl(dest.url) !== normalizeUrl(pushUrl)) {
|
|
143052
|
-
throw new Error(
|
|
143053
|
-
`Push blocked: destination does not match expected repository.
|
|
143054
|
-
Expected: ${pushUrl}
|
|
143055
|
-
Actual: ${dest.url}
|
|
143056
|
-
Git configuration may have been tampered with.`
|
|
143057
|
-
);
|
|
143058
|
-
}
|
|
143059
|
-
return dest;
|
|
143060
|
-
}
|
|
143061
|
-
var PushBranch = type({
|
|
143062
|
-
branchName: type.string.describe("The branch name to push (defaults to current branch)").optional(),
|
|
143063
|
-
force: type.boolean.describe("Force push (use with caution)").default(false)
|
|
143064
|
-
});
|
|
143065
|
-
function PushBranchTool(ctx) {
|
|
143066
|
-
const defaultBranch = ctx.repo.data.default_branch || "main";
|
|
143067
|
-
const pushPermission = ctx.payload.push;
|
|
143068
|
-
return tool({
|
|
143069
|
-
name: "push_branch",
|
|
143070
|
-
description: "Push the current branch to the remote repository. Omit branchName to push the current branch (recommended). If specifying branchName, use the LOCAL branch name (e.g., 'pr-1'), not the remote branch name. The correct remote and remote branch are determined automatically from branch config set by checkout_pr. Requires a clean working tree. Runs the repository prepush hook (if configured) before the network push \u2014 hook failure means tests/lint or similar in that script failed, not necessarily a Pullfrog timeout. Never force push unless explicitly requested. Pushes to the default branch are blocked in restricted mode.",
|
|
143071
|
-
parameters: PushBranch,
|
|
143072
|
-
execute: execute(async ({ branchName, force }) => {
|
|
143073
|
-
if (pushPermission === "disabled") {
|
|
143074
|
-
throw new Error("Push is disabled. This repository is configured for read-only access.");
|
|
143075
|
-
}
|
|
143076
|
-
const branch = branchName || $("git", ["rev-parse", "--abbrev-ref", "HEAD"], { log: false });
|
|
143077
|
-
const status = $("git", ["status", "--porcelain"], { log: false });
|
|
143078
|
-
if (status) {
|
|
143079
|
-
throw new Error(
|
|
143080
|
-
`push blocked: working tree is not clean (tracked changes and/or untracked files). commit, discard, or remove stray artifacts before pushing.
|
|
143081
|
-
|
|
143082
|
-
git status:
|
|
143083
|
-
${status}`
|
|
143084
|
-
);
|
|
143085
|
-
}
|
|
143086
|
-
const pushDest = validatePushDestination(ctx, branch);
|
|
143087
|
-
if (pushPermission === "restricted" && pushDest.remoteBranch === defaultBranch) {
|
|
143088
|
-
throw new Error(
|
|
143089
|
-
`Push blocked: cannot push directly to default branch '${pushDest.remoteBranch}'. Create a feature branch and open a PR instead.`
|
|
143090
|
-
);
|
|
143091
|
-
}
|
|
143092
|
-
const refspec = branch === pushDest.remoteBranch ? branch : `${branch}:${pushDest.remoteBranch}`;
|
|
143093
|
-
const pushArgs = force ? ["--force", "-u", pushDest.remoteName, refspec] : ["-u", pushDest.remoteName, refspec];
|
|
143094
|
-
await executeLifecycleHook({ event: "prepush", script: ctx.prepushScript });
|
|
143095
|
-
log.debug(`pushing ${branch} to ${pushDest.remoteName}/${pushDest.remoteBranch}`);
|
|
143096
|
-
if (force) {
|
|
143097
|
-
log.warning(`force pushing - this will overwrite remote history`);
|
|
143098
|
-
}
|
|
143099
|
-
try {
|
|
143100
|
-
await $git("push", pushArgs, {
|
|
143101
|
-
token: ctx.gitToken
|
|
143102
|
-
});
|
|
143103
|
-
} catch (err) {
|
|
143104
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
143105
|
-
if (msg.includes("fetch first") || msg.includes("non-fast-forward")) {
|
|
143106
|
-
throw new Error(
|
|
143107
|
-
`push rejected: the remote branch '${pushDest.remoteBranch}' has new commits you don't have locally.
|
|
143108
|
-
|
|
143109
|
-
to resolve this:
|
|
143110
|
-
1. use git_fetch to fetch the remote branch: git_fetch({ ref: "${pushDest.remoteBranch}" })
|
|
143111
|
-
2. use the git tool to rebase your changes: git({ subcommand: "rebase", args: ["origin/${pushDest.remoteBranch}"] })
|
|
143112
|
-
3. resolve any merge conflicts if needed
|
|
143113
|
-
4. retry push_branch`
|
|
143114
|
-
);
|
|
143115
|
-
}
|
|
143116
|
-
throw err;
|
|
143117
|
-
}
|
|
143118
|
-
return {
|
|
143119
|
-
success: true,
|
|
143120
|
-
branch,
|
|
143121
|
-
remoteBranch: pushDest.remoteBranch,
|
|
143122
|
-
remote: pushDest.remoteName,
|
|
143123
|
-
force,
|
|
143124
|
-
message: `successfully pushed ${branch} to ${pushDest.remoteName}/${pushDest.remoteBranch}`
|
|
143125
|
-
};
|
|
143126
|
-
})
|
|
143127
|
-
});
|
|
143128
|
-
}
|
|
143129
|
-
var AUTH_REQUIRED_REDIRECT = {
|
|
143130
|
-
push: "use the push_branch tool instead \u2014 it handles authentication and permission checks.",
|
|
143131
|
-
fetch: "use the git_fetch tool instead \u2014 it handles authentication.",
|
|
143132
|
-
pull: "use git_fetch to fetch the remote ref, then use this git tool with subcommand 'merge' or 'rebase' locally.",
|
|
143133
|
-
clone: "the repository is already cloned. use checkout_pr for PR branches."
|
|
143134
|
-
};
|
|
143135
|
-
var NOSHELL_BLOCKED_SUBCOMMANDS = {
|
|
143136
|
-
config: "Blocked: git config can set up filter drivers or hooks that execute arbitrary code.",
|
|
143137
|
-
submodule: "Blocked: git submodule can reference malicious repositories and execute code on update.",
|
|
143138
|
-
"update-index": "Blocked: git update-index can modify index entries in ways that bypass file protections.",
|
|
143139
|
-
"filter-branch": "Blocked: git filter-branch executes arbitrary code on repository history.",
|
|
143140
|
-
replace: "Blocked: git replace can redirect object lookups.",
|
|
143141
|
-
// subcommands that accept --exec or similar flags for arbitrary code execution
|
|
143142
|
-
rebase: "Blocked: git rebase --exec can execute arbitrary shell commands.",
|
|
143143
|
-
bisect: "Blocked: git bisect run can execute arbitrary shell commands."
|
|
143144
|
-
};
|
|
143145
|
-
var NOSHELL_BLOCKED_ARGS = ["--exec", "--extcmd", "--upload-pack", "--receive-pack"];
|
|
143146
|
-
var COLLAPSE_THRESHOLD = 200;
|
|
143147
|
-
var subcommandPattern = regex("^[a-z][a-z0-9-]*$");
|
|
143148
|
-
var Git = type({
|
|
143149
|
-
subcommand: type(subcommandPattern).describe("Git subcommand (e.g., 'status', 'log', 'diff')"),
|
|
143150
|
-
args: type.string.array().describe("Additional arguments for the git command").optional()
|
|
143151
|
-
});
|
|
143152
|
-
function GitTool(ctx) {
|
|
143153
|
-
return tool({
|
|
143154
|
-
name: "git",
|
|
143155
|
-
description: "Run git commands. For push/fetch/pull, use the dedicated MCP tools instead (push_branch, git_fetch).",
|
|
143156
|
-
parameters: Git,
|
|
143157
|
-
execute: execute(async (params) => {
|
|
143158
|
-
const subcommand = params.subcommand;
|
|
143159
|
-
const args2 = params.args ?? [];
|
|
143160
|
-
const redirect = AUTH_REQUIRED_REDIRECT[subcommand];
|
|
143161
|
-
if (redirect) {
|
|
143162
|
-
throw new Error(`git ${subcommand} is not available through this tool \u2014 ${redirect}`);
|
|
143163
|
-
}
|
|
143164
|
-
if (ctx.payload.shell === "disabled") {
|
|
143165
|
-
const blocked = NOSHELL_BLOCKED_SUBCOMMANDS[subcommand];
|
|
143166
|
-
if (blocked) {
|
|
143167
|
-
throw new Error(blocked);
|
|
143168
|
-
}
|
|
143169
|
-
for (const arg4 of args2) {
|
|
143170
|
-
const isBlocked = NOSHELL_BLOCKED_ARGS.some(
|
|
143171
|
-
(flag) => arg4 === flag || arg4.startsWith(flag + "=")
|
|
143172
|
-
);
|
|
143173
|
-
if (isBlocked) {
|
|
143174
|
-
throw new Error(
|
|
143175
|
-
`Blocked: '${arg4}' flag can execute arbitrary code and is not allowed.`
|
|
143176
|
-
);
|
|
143177
|
-
}
|
|
143178
|
-
}
|
|
143179
|
-
}
|
|
143180
|
-
const output = $("git", [subcommand, ...args2], { log: false });
|
|
143181
|
-
const lineCount = output.split("\n").length;
|
|
143182
|
-
if (lineCount > COLLAPSE_THRESHOLD) {
|
|
143183
|
-
log.group(`git ${subcommand} output (${lineCount} lines)`, () => {
|
|
143184
|
-
log.info(output);
|
|
143185
|
-
});
|
|
143186
|
-
} else if (output) {
|
|
143187
|
-
log.info(output);
|
|
143188
|
-
}
|
|
143189
|
-
return { success: true, output };
|
|
143190
|
-
})
|
|
143191
|
-
});
|
|
143192
|
-
}
|
|
143193
|
-
var GitFetch = type({
|
|
143194
|
-
ref: type.string.describe("Ref to fetch: branch name, tag, or 'pull/N/head' for PRs"),
|
|
143195
|
-
depth: type.number.describe("Fetch depth (for shallow clones)").optional()
|
|
143196
|
-
});
|
|
143197
|
-
function GitFetchTool(ctx) {
|
|
143198
|
-
return tool({
|
|
143199
|
-
name: "git_fetch",
|
|
143200
|
-
description: "Fetch refs from remote repository. Use this instead of git fetch directly.",
|
|
143201
|
-
parameters: GitFetch,
|
|
143202
|
-
execute: execute(async (params) => {
|
|
143203
|
-
const fetchArgs = ["--no-tags", "origin", params.ref];
|
|
143204
|
-
if (params.depth !== void 0) {
|
|
143205
|
-
fetchArgs.push(`--depth=${params.depth}`);
|
|
143206
|
-
}
|
|
143207
|
-
await $git("fetch", fetchArgs, {
|
|
143208
|
-
token: ctx.gitToken
|
|
143209
|
-
});
|
|
143210
|
-
return { success: true, ref: params.ref };
|
|
143211
|
-
})
|
|
143212
|
-
});
|
|
143213
|
-
}
|
|
143214
|
-
var DeleteBranch = type({
|
|
143215
|
-
branchName: type.string.describe("Remote branch to delete")
|
|
143216
|
-
});
|
|
143217
|
-
function DeleteBranchTool(ctx) {
|
|
143218
|
-
const pushPermission = ctx.payload.push;
|
|
143219
|
-
return tool({
|
|
143220
|
-
name: "delete_branch",
|
|
143221
|
-
description: "Delete a remote branch. Requires push: enabled permission.",
|
|
143222
|
-
parameters: DeleteBranch,
|
|
143223
|
-
execute: execute(async (params) => {
|
|
143224
|
-
if (pushPermission !== "enabled") {
|
|
143225
|
-
throw new Error(
|
|
143226
|
-
"Branch deletion requires push: enabled permission. Current mode only allows pushing to non-protected branches."
|
|
143227
|
-
);
|
|
143228
|
-
}
|
|
143229
|
-
await $git("push", ["origin", "--delete", params.branchName], {
|
|
143230
|
-
token: ctx.gitToken
|
|
143231
|
-
});
|
|
143232
|
-
return { success: true, deleted: params.branchName };
|
|
143233
|
-
})
|
|
143234
|
-
});
|
|
143235
|
-
}
|
|
143236
|
-
var PushTags = type({
|
|
143237
|
-
tag: type.string.describe("Tag name to push"),
|
|
143238
|
-
force: type.boolean.describe("Force push the tag").default(false)
|
|
143239
|
-
});
|
|
143240
|
-
function PushTagsTool(ctx) {
|
|
143241
|
-
const pushPermission = ctx.payload.push;
|
|
143242
|
-
return tool({
|
|
143243
|
-
name: "push_tags",
|
|
143244
|
-
description: "Push a tag to remote. Requires push: enabled permission.",
|
|
143245
|
-
parameters: PushTags,
|
|
143246
|
-
execute: execute(async (params) => {
|
|
143247
|
-
if (pushPermission !== "enabled") {
|
|
143248
|
-
throw new Error(
|
|
143249
|
-
"Tag pushing requires push: enabled permission. Current mode only allows pushing branches."
|
|
143250
|
-
);
|
|
143251
|
-
}
|
|
143252
|
-
const pushArgs = [...params.force ? ["-f"] : [], "origin", `refs/tags/${params.tag}`];
|
|
143253
|
-
await $git("push", pushArgs, {
|
|
143254
|
-
token: ctx.gitToken
|
|
143255
|
-
});
|
|
143256
|
-
return { success: true, tag: params.tag };
|
|
143257
|
-
})
|
|
143258
|
-
});
|
|
143259
|
-
}
|
|
143260
|
-
|
|
143261
144529
|
// mcp/issue.ts
|
|
143262
144530
|
var Issue = type({
|
|
143263
144531
|
title: type.string.describe("the title of the issue"),
|
|
@@ -143720,221 +144988,6 @@ function PullRequestInfoTool(ctx) {
|
|
|
143720
144988
|
});
|
|
143721
144989
|
}
|
|
143722
144990
|
|
|
143723
|
-
// mcp/review.ts
|
|
143724
|
-
function getHttpStatus(err) {
|
|
143725
|
-
if (typeof err !== "object" || err === null) return void 0;
|
|
143726
|
-
const status = err.status;
|
|
143727
|
-
return typeof status === "number" ? status : void 0;
|
|
143728
|
-
}
|
|
143729
|
-
var CreatePullRequestReview = type({
|
|
143730
|
-
pull_number: type.number.describe("The pull request number to review"),
|
|
143731
|
-
body: type.string.describe(
|
|
143732
|
-
"1-2 sentence high-level summary with urgency level, critical callouts, and feedback about code outside the diff. Specific feedback on diff lines goes in 'comments' array."
|
|
143733
|
-
).optional(),
|
|
143734
|
-
approved: type.boolean.describe(
|
|
143735
|
-
"Set to true to submit as an approval. ONLY when the review contains no actionable feedback \u2014 neither inline comments nor actionable content in the body. Defaults to false (comment-only review). Rejections are not supported."
|
|
143736
|
-
).optional(),
|
|
143737
|
-
commit_id: type.string.describe("Optional SHA of the commit being reviewed. Defaults to latest.").optional(),
|
|
143738
|
-
comments: type({
|
|
143739
|
-
path: type.string.describe(
|
|
143740
|
-
"The file path to comment on (relative to repo root). Must be a file that appears in the PR diff."
|
|
143741
|
-
),
|
|
143742
|
-
line: type.number.describe(
|
|
143743
|
-
"Line number to comment on. For multi-line ranges, this is the end line. Use NEW column from diff format."
|
|
143744
|
-
),
|
|
143745
|
-
side: type.enumerated("LEFT", "RIGHT").describe(
|
|
143746
|
-
"Side of the diff: LEFT (old code, lines starting with -) or RIGHT (new code, lines starting with + or unchanged). Defaults to RIGHT."
|
|
143747
|
-
).optional(),
|
|
143748
|
-
body: type.string.describe("Explanatory comment text (optional if suggestion is provided)").optional(),
|
|
143749
|
-
suggestion: type.string.describe(
|
|
143750
|
-
"Full replacement code for the line range [start_line, line]. MUST preserve the exact indentation of the original code."
|
|
143751
|
-
).optional(),
|
|
143752
|
-
start_line: type.number.describe(
|
|
143753
|
-
"Start line for multi-line comment ranges. Omit for single-line comments. The range [start_line, line] defines which lines a suggestion replaces."
|
|
143754
|
-
).optional()
|
|
143755
|
-
}).array().describe(
|
|
143756
|
-
"Inline comments on lines within diff hunks. Feedback about code outside the diff goes in 'body' instead."
|
|
143757
|
-
).optional()
|
|
143758
|
-
});
|
|
143759
|
-
function CreatePullRequestReviewTool(ctx) {
|
|
143760
|
-
return tool({
|
|
143761
|
-
name: "create_pull_request_review",
|
|
143762
|
-
description: `Submit a review for an existing pull request. Each call creates a permanent, visible review on the PR \u2014 NEVER submit test or diagnostic reviews. Reviews with no body AND no comments are silently skipped (nothing to post). IMPORTANT: 95%+ of feedback should be in 'comments' array with file paths and line numbers. Only use 'body' for a 1-2 sentence summary with urgency and critical callouts. Use 'suggestion' to propose replacement code - MUST preserve exact indentation of original code. Example replacing lines 42-44 (3 lines) with 5 lines: { path: 'src/api.ts', start_line: 42, line: 44, suggestion: ' const result = await fetch(url);\\n if (!result.ok) {\\n log.error(result.status);\\n throw new Error("request failed");\\n }' } CONSTRAINT: Inline comments can ONLY target files and lines that appear in the PR diff. If GitHub rejects comments due to incorrect line numbers, re-read the diff and retry.`,
|
|
143763
|
-
parameters: CreatePullRequestReview,
|
|
143764
|
-
execute: execute(async ({ pull_number, body, approved, commit_id, comments = [] }) => {
|
|
143765
|
-
if (body) body = fixDoubleEscapedString(body);
|
|
143766
|
-
if (body && ctx.toolState.selectedMode === "Review" && ctx.toolState.todoTracker) {
|
|
143767
|
-
ctx.toolState.todoTracker.cancel();
|
|
143768
|
-
await ctx.toolState.todoTracker.settled();
|
|
143769
|
-
ctx.toolState.todoTracker.completeInProgress();
|
|
143770
|
-
const collapsible = ctx.toolState.todoTracker.renderCollapsible();
|
|
143771
|
-
if (collapsible) {
|
|
143772
|
-
body = `${body}
|
|
143773
|
-
|
|
143774
|
-
${collapsible}`;
|
|
143775
|
-
}
|
|
143776
|
-
}
|
|
143777
|
-
ctx.toolState.issueNumber = pull_number;
|
|
143778
|
-
if (!approved && !body && comments.length === 0) {
|
|
143779
|
-
log.info(
|
|
143780
|
-
"review has no body and no inline comments \u2014 skipping submission (no issues found)"
|
|
143781
|
-
);
|
|
143782
|
-
return {
|
|
143783
|
-
success: true,
|
|
143784
|
-
skipped: true,
|
|
143785
|
-
reason: "no issues found \u2014 nothing to post"
|
|
143786
|
-
};
|
|
143787
|
-
}
|
|
143788
|
-
let event = approved ? "APPROVE" : "COMMENT";
|
|
143789
|
-
if (event === "APPROVE" && !ctx.prApproveEnabled) {
|
|
143790
|
-
log.info("prApproveEnabled is disabled \u2014 downgrading APPROVE to COMMENT");
|
|
143791
|
-
event = "COMMENT";
|
|
143792
|
-
}
|
|
143793
|
-
const params = {
|
|
143794
|
-
owner: ctx.repo.owner,
|
|
143795
|
-
repo: ctx.repo.name,
|
|
143796
|
-
pull_number,
|
|
143797
|
-
event
|
|
143798
|
-
};
|
|
143799
|
-
let latestHeadSha;
|
|
143800
|
-
if (commit_id) {
|
|
143801
|
-
params.commit_id = commit_id;
|
|
143802
|
-
} else {
|
|
143803
|
-
const pr = await ctx.octokit.rest.pulls.get({
|
|
143804
|
-
owner: ctx.repo.owner,
|
|
143805
|
-
repo: ctx.repo.name,
|
|
143806
|
-
pull_number
|
|
143807
|
-
});
|
|
143808
|
-
latestHeadSha = pr.data.head.sha;
|
|
143809
|
-
params.commit_id = ctx.toolState.checkoutSha ?? latestHeadSha;
|
|
143810
|
-
if (ctx.toolState.checkoutSha && latestHeadSha !== ctx.toolState.checkoutSha) {
|
|
143811
|
-
log.info(
|
|
143812
|
-
`anchoring review to checkout ${ctx.toolState.checkoutSha.slice(0, 7)} (HEAD is now ${latestHeadSha.slice(0, 7)})`
|
|
143813
|
-
);
|
|
143814
|
-
}
|
|
143815
|
-
}
|
|
143816
|
-
const reviewComments = comments.map((comment) => {
|
|
143817
|
-
let commentBody = fixDoubleEscapedString(comment.body || "");
|
|
143818
|
-
if (comment.suggestion !== void 0) {
|
|
143819
|
-
const suggestionBlock = "```suggestion\n" + comment.suggestion + "\n```";
|
|
143820
|
-
commentBody = commentBody ? commentBody + "\n\n" + suggestionBlock : suggestionBlock;
|
|
143821
|
-
}
|
|
143822
|
-
const side = comment.side || "RIGHT";
|
|
143823
|
-
const reviewComment = {
|
|
143824
|
-
path: comment.path,
|
|
143825
|
-
line: comment.line,
|
|
143826
|
-
body: commentBody,
|
|
143827
|
-
side
|
|
143828
|
-
};
|
|
143829
|
-
if (comment.start_line != null && comment.start_line !== comment.line) {
|
|
143830
|
-
reviewComment.start_line = comment.start_line;
|
|
143831
|
-
reviewComment.start_side = side;
|
|
143832
|
-
}
|
|
143833
|
-
return reviewComment;
|
|
143834
|
-
});
|
|
143835
|
-
if (reviewComments.length > 0) {
|
|
143836
|
-
params.comments = reviewComments;
|
|
143837
|
-
}
|
|
143838
|
-
let result;
|
|
143839
|
-
try {
|
|
143840
|
-
result = body ? await createAndSubmitWithFooter(ctx, params, {
|
|
143841
|
-
body,
|
|
143842
|
-
approved: approved ?? false,
|
|
143843
|
-
hasComments: reviewComments.length > 0
|
|
143844
|
-
}) : await ctx.octokit.rest.pulls.createReview(params);
|
|
143845
|
-
} catch (err) {
|
|
143846
|
-
if (getHttpStatus(err) !== 422 || !params.comments?.length) throw err;
|
|
143847
|
-
const details = params.comments.map((c2) => {
|
|
143848
|
-
const line = c2.line ?? 0;
|
|
143849
|
-
const startLine = c2.start_line ?? line;
|
|
143850
|
-
const range2 = startLine !== line ? `${startLine}-${line}` : `${line}`;
|
|
143851
|
-
return `${c2.path}:${range2} (${c2.side ?? "RIGHT"})`;
|
|
143852
|
-
});
|
|
143853
|
-
throw new Error(
|
|
143854
|
-
`GitHub rejected inline comment(s) with "Line could not be resolved". This usually means the diff changed since you last read it (new commits pushed). Re-read the diff to get current line numbers, or move failing comments to the review body. Affected: ${details.join(", ")}`
|
|
143855
|
-
);
|
|
143856
|
-
}
|
|
143857
|
-
log.debug(`createReview response: ${JSON.stringify(result.data)}`);
|
|
143858
|
-
if (!result.data.id) {
|
|
143859
|
-
throw new Error(`createReview returned invalid data: ${JSON.stringify(result.data)}`);
|
|
143860
|
-
}
|
|
143861
|
-
const reviewId = result.data.id;
|
|
143862
|
-
const reviewNodeId = result.data.node_id;
|
|
143863
|
-
const actuallyReviewedSha = ctx.toolState.checkoutSha ?? params.commit_id;
|
|
143864
|
-
ctx.toolState.review = {
|
|
143865
|
-
id: reviewId,
|
|
143866
|
-
nodeId: reviewNodeId,
|
|
143867
|
-
reviewedSha: actuallyReviewedSha
|
|
143868
|
-
};
|
|
143869
|
-
if (ctx.toolState.checkoutSha && latestHeadSha && latestHeadSha !== ctx.toolState.checkoutSha) {
|
|
143870
|
-
const fromSha = ctx.toolState.checkoutSha;
|
|
143871
|
-
const toSha = latestHeadSha;
|
|
143872
|
-
ctx.toolState.beforeSha = fromSha;
|
|
143873
|
-
ctx.toolState.checkoutSha = toSha;
|
|
143874
|
-
log.info(
|
|
143875
|
-
`new commits detected during review: ${fromSha.slice(0, 7)}..${toSha.slice(0, 7)}`
|
|
143876
|
-
);
|
|
143877
|
-
return {
|
|
143878
|
-
success: true,
|
|
143879
|
-
reviewId,
|
|
143880
|
-
html_url: result.data.html_url,
|
|
143881
|
-
state: result.data.state,
|
|
143882
|
-
user: result.data.user?.login,
|
|
143883
|
-
submitted_at: result.data.submitted_at,
|
|
143884
|
-
newCommits: {
|
|
143885
|
-
from: fromSha,
|
|
143886
|
-
to: toSha,
|
|
143887
|
-
instructions: `new commits were pushed while you were reviewing. call \`${formatMcpToolRef(ctx.agentId, "checkout_pr")}\` again to fetch the latest version \u2014 it will compute the incremental diff automatically. submit another review covering only the new changes. do not repeat feedback from your previous review.`
|
|
143888
|
-
}
|
|
143889
|
-
};
|
|
143890
|
-
}
|
|
143891
|
-
return {
|
|
143892
|
-
success: true,
|
|
143893
|
-
reviewId,
|
|
143894
|
-
html_url: result.data.html_url,
|
|
143895
|
-
state: result.data.state,
|
|
143896
|
-
user: result.data.user?.login,
|
|
143897
|
-
submitted_at: result.data.submitted_at
|
|
143898
|
-
};
|
|
143899
|
-
})
|
|
143900
|
-
});
|
|
143901
|
-
}
|
|
143902
|
-
async function createAndSubmitWithFooter(ctx, params, opts) {
|
|
143903
|
-
const { event: _2, ...pendingParams } = params;
|
|
143904
|
-
const pending = await ctx.octokit.rest.pulls.createReview(pendingParams);
|
|
143905
|
-
if (!pending.data.id) {
|
|
143906
|
-
throw new Error(`createReview returned invalid data: ${JSON.stringify(pending.data)}`);
|
|
143907
|
-
}
|
|
143908
|
-
const customParts = [];
|
|
143909
|
-
if (!opts.approved) {
|
|
143910
|
-
const apiUrl = getApiUrl();
|
|
143911
|
-
if (opts.hasComments) {
|
|
143912
|
-
const fixAllUrl = `${apiUrl}/trigger/${ctx.repo.owner}/${ctx.repo.name}/${params.pull_number}?action=fix&review_id=${pending.data.id}`;
|
|
143913
|
-
const fixApprovedUrl = `${apiUrl}/trigger/${ctx.repo.owner}/${ctx.repo.name}/${params.pull_number}?action=fix-approved&review_id=${pending.data.id}`;
|
|
143914
|
-
customParts.push(`[Fix all \u2794](${fixAllUrl})`, `[Fix \u{1F44D}s \u2794](${fixApprovedUrl})`);
|
|
143915
|
-
} else {
|
|
143916
|
-
const fixUrl = `${apiUrl}/trigger/${ctx.repo.owner}/${ctx.repo.name}/${params.pull_number}?action=fix&review_id=${pending.data.id}`;
|
|
143917
|
-
customParts.push(`[Fix it \u2794](${fixUrl})`);
|
|
143918
|
-
}
|
|
143919
|
-
}
|
|
143920
|
-
const footer = buildPullfrogFooter({
|
|
143921
|
-
workflowRun: ctx.runId ? { owner: ctx.repo.owner, repo: ctx.repo.name, runId: ctx.runId, jobId: ctx.jobId } : void 0,
|
|
143922
|
-
customParts,
|
|
143923
|
-
model: ctx.toolState.model
|
|
143924
|
-
});
|
|
143925
|
-
return ctx.octokit.rest.pulls.submitReview({
|
|
143926
|
-
owner: params.owner,
|
|
143927
|
-
repo: params.repo,
|
|
143928
|
-
pull_number: params.pull_number,
|
|
143929
|
-
review_id: pending.data.id,
|
|
143930
|
-
event: params.event,
|
|
143931
|
-
body: opts.body + footer
|
|
143932
|
-
});
|
|
143933
|
-
}
|
|
143934
|
-
async function reportReviewNodeId(ctx, params) {
|
|
143935
|
-
await patchWorkflowRunFields(ctx, { reviewNodeId: params.nodeId });
|
|
143936
|
-
}
|
|
143937
|
-
|
|
143938
144991
|
// mcp/reviewComments.ts
|
|
143939
144992
|
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
143940
144993
|
import { join as join6 } from "node:path";
|
|
@@ -143982,7 +145035,7 @@ query ($owner: String!, $name: String!, $prNumber: Int!) {
|
|
|
143982
145035
|
}
|
|
143983
145036
|
}
|
|
143984
145037
|
`;
|
|
143985
|
-
function
|
|
145038
|
+
function countLines2(str) {
|
|
143986
145039
|
let count = 1;
|
|
143987
145040
|
let index = -1;
|
|
143988
145041
|
while ((index = str.indexOf("\n", index + 1)) !== -1) {
|
|
@@ -144124,13 +145177,13 @@ function formatReviewThreads(threadBlocks, header) {
|
|
|
144124
145177
|
const reviewBodyLines = [];
|
|
144125
145178
|
if (header.reviewBody) {
|
|
144126
145179
|
reviewBodyLines.push("## Review Body", "", header.reviewBody, "");
|
|
144127
|
-
currentLine += reviewBodyLines.reduce((sum, line) => sum +
|
|
145180
|
+
currentLine += reviewBodyLines.reduce((sum, line) => sum + countLines2(line), 0);
|
|
144128
145181
|
}
|
|
144129
145182
|
const tocEntries = [];
|
|
144130
145183
|
const threadLines = [];
|
|
144131
145184
|
for (const block of threadBlocks) {
|
|
144132
145185
|
const startLine = currentLine;
|
|
144133
|
-
const actualLineCount = block.content.reduce((sum, line) => sum +
|
|
145186
|
+
const actualLineCount = block.content.reduce((sum, line) => sum + countLines2(line), 0);
|
|
144134
145187
|
const endLine = currentLine + actualLineCount - 1;
|
|
144135
145188
|
tocEntries.push(`- ${block.path}:${block.lineRange} \u2192 lines ${startLine}-${endLine}`);
|
|
144136
145189
|
threadLines.push(...block.content);
|
|
@@ -144453,7 +145506,7 @@ GitHub's markdown parser requires a blank line between ALL block-level elements.
|
|
|
144453
145506
|
Rules:
|
|
144454
145507
|
- \`##\` titles and key-change bullet lead-ins are plain-language summaries; backtick only actual code tokens (files, types, functions) where they appear in the title
|
|
144455
145508
|
- ALL variable names, identifiers, and file names in body text must be in backticks
|
|
144456
|
-
- ALL file references MUST link to the PR Files Changed view.
|
|
145509
|
+
- ALL file references MUST link to the PR Files Changed view. Use the \`diff-<hex>\` anchor precomputed next to each filename in the \`checkout_pr\` TOC \u2014 do NOT run \`sha256sum\` or any other shell command to compute anchors. NEVER fabricate hex strings. If a file is not in the TOC, omit the \`#diff-\` anchor rather than guessing.
|
|
144457
145510
|
- Add <br/> before each ## heading for visual spacing. Do NOT use horizontal rules (---)
|
|
144458
145511
|
- Do NOT include raw diff stats like '+123 / -45' or line counts
|
|
144459
145512
|
- Do NOT include code blocks or repeat diff contents
|
|
@@ -144528,7 +145581,7 @@ ${learningsStep(t2, 6)}`
|
|
|
144528
145581
|
description: "Review code, PRs, or implementations; provide feedback or suggestions; identify issues; or check code quality, style, and correctness",
|
|
144529
145582
|
prompt: `### Checklist
|
|
144530
145583
|
|
|
144531
|
-
1. Checkout the PR via \`${t2("checkout_pr")}\` \u2014 this returns PR metadata and a \`diffPath\`.
|
|
145584
|
+
1. Checkout the PR via \`${t2("checkout_pr")}\` \u2014 this returns PR metadata and a \`diffPath\`. read the diff TOC first and treat its file line ranges as your coverage checklist.
|
|
144532
145585
|
|
|
144533
145586
|
2. For each area of change:
|
|
144534
145587
|
- read the diff and trace data flow, check boundaries, and verify assumptions
|
|
@@ -144545,6 +145598,7 @@ ${learningsStep(t2, 6)}`
|
|
|
144545
145598
|
4. Submit \u2014 ALWAYS submit exactly one review via \`${t2("create_pull_request_review")}\`.
|
|
144546
145599
|
Do NOT call \`report_progress\` \u2014 the review is the final record and the progress
|
|
144547
145600
|
comment will be cleaned up automatically.
|
|
145601
|
+
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.
|
|
144548
145602
|
|
|
144549
145603
|
- **critical issues** (blocks merge \u2014 bugs, security, data loss):
|
|
144550
145604
|
\`approved: false\`. Body begins with a GitHub alert blockquote, e.g.:
|
|
@@ -144562,7 +145616,7 @@ ${learningsStep(t2, 6)}`
|
|
|
144562
145616
|
description: "Re-review a PR after new commits are pushed; focus on new changes since the last review",
|
|
144563
145617
|
prompt: `### Checklist
|
|
144564
145618
|
|
|
144565
|
-
1. Checkout the PR via \`${t2("checkout_pr")}\` \u2014 this returns PR metadata, \`diffPath\` (full diff), and \`incrementalDiffPath\` (changes since last reviewed version, if available).
|
|
145619
|
+
1. Checkout the PR via \`${t2("checkout_pr")}\` \u2014 this returns PR metadata, \`diffPath\` (full diff), and \`incrementalDiffPath\` (changes since last reviewed version, if available). read the diff TOC first and use its line ranges as your coverage checklist.
|
|
144566
145620
|
|
|
144567
145621
|
2. If \`incrementalDiffPath\` is present, read it to see what changed since the last review. This is a range-diff that isolates the net changes, filtering out base branch noise. If not present, fall back to reviewing the full PR diff.
|
|
144568
145622
|
|
|
@@ -144586,6 +145640,7 @@ ${learningsStep(t2, 6)}`
|
|
|
144586
145640
|
- in some cases you may receive a complete diff for the whole pull request instead of an incremental one. when this happens, you will need to determine what changes have happened since Pullfrog's most recent review.
|
|
144587
145641
|
|
|
144588
145642
|
7. Submit \u2014 Do NOT call \`report_progress\` or \`create_issue_comment\` \u2014 the review is the final record and the progress comment will be cleaned up automatically. the review body always includes the reviewed changes from step 6a. append \`Prior review feedback:\\n\` with the checklist from step 6b only if any prior comments were addressed. Follow these rules:
|
|
145643
|
+
- 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.
|
|
144589
145644
|
- IF NO NEW ISSUES, NON-SUBSTANTIVE CHANGES ONLY (trivial formatting, import reordering, comment tweaks): do NOT submit a review. Do NOT call \`report_progress\`. Exit \u2014 the progress comment will be cleaned up automatically.
|
|
144590
145645
|
- ELSE IF NEW CRITICAL ISSUES (blocks merge): call \`${t2("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with a GitHub alert blockquote (e.g. \`> [!CAUTION]\\n> This PR introduces ...\`), then the reviewed changes summary and prior feedback (if any).
|
|
144591
145646
|
- ELSE IF NEW RECOMMENDED CHANGES (non-critical): call \`${t2("create_pull_request_review")}\` with \`approved: false\`, all comments, and the review body. body opens with \`> [!IMPORTANT]\\n> ...\` alert, then the reviewed changes summary and prior feedback (if any).
|
|
@@ -145053,11 +146108,11 @@ Do NOT use this tool for git commands \u2014 use the dedicated git tools instead
|
|
|
145053
146108
|
await killProcessGroup(proc);
|
|
145054
146109
|
}
|
|
145055
146110
|
}, timeout);
|
|
145056
|
-
const exitCode = await new Promise((
|
|
146111
|
+
const exitCode = await new Promise((resolve3) => {
|
|
145057
146112
|
const done = (code) => {
|
|
145058
146113
|
exited = true;
|
|
145059
146114
|
clearTimeout(timeoutId);
|
|
145060
|
-
|
|
146115
|
+
resolve3(code);
|
|
145061
146116
|
};
|
|
145062
146117
|
proc.on("exit", done);
|
|
145063
146118
|
proc.on("error", () => done(null));
|
|
@@ -145196,12 +146251,12 @@ function readEnvPort() {
|
|
|
145196
146251
|
return parsed2;
|
|
145197
146252
|
}
|
|
145198
146253
|
function isPortAvailable(port) {
|
|
145199
|
-
return new Promise((
|
|
146254
|
+
return new Promise((resolve3) => {
|
|
145200
146255
|
const server = createServer();
|
|
145201
146256
|
server.unref();
|
|
145202
|
-
server.once("error", () =>
|
|
146257
|
+
server.once("error", () => resolve3(false));
|
|
145203
146258
|
server.once("listening", () => {
|
|
145204
|
-
server.close(() =>
|
|
146259
|
+
server.close(() => resolve3(true));
|
|
145205
146260
|
});
|
|
145206
146261
|
server.listen(port, mcpHost);
|
|
145207
146262
|
});
|
|
@@ -145341,9 +146396,12 @@ async function killBackgroundProcesses(toolState) {
|
|
|
145341
146396
|
async function startMcpHttpServer(ctx, options) {
|
|
145342
146397
|
const tools = buildOrchestratorTools(ctx, options?.outputSchema);
|
|
145343
146398
|
const startResult = await selectMcpPort(ctx, tools);
|
|
146399
|
+
let disposed = false;
|
|
145344
146400
|
return {
|
|
145345
146401
|
url: startResult.url,
|
|
145346
146402
|
[Symbol.asyncDispose]: async () => {
|
|
146403
|
+
if (disposed) return;
|
|
146404
|
+
disposed = true;
|
|
145347
146405
|
closeBrowserDaemon(ctx.toolState);
|
|
145348
146406
|
await killBackgroundProcesses(ctx.toolState);
|
|
145349
146407
|
await startResult.server.stop();
|
|
@@ -145538,39 +146596,6 @@ var ThinkingTimer = class {
|
|
|
145538
146596
|
}
|
|
145539
146597
|
};
|
|
145540
146598
|
|
|
145541
|
-
// agents/shared.ts
|
|
145542
|
-
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
145543
|
-
var MAX_STDERR_LINES = 20;
|
|
145544
|
-
var MAX_COMMIT_RETRIES = 3;
|
|
145545
|
-
function getGitStatus() {
|
|
145546
|
-
try {
|
|
145547
|
-
return execFileSync2("git", ["status", "--porcelain"], {
|
|
145548
|
-
encoding: "utf-8",
|
|
145549
|
-
timeout: 1e4
|
|
145550
|
-
}).trim();
|
|
145551
|
-
} catch {
|
|
145552
|
-
return "";
|
|
145553
|
-
}
|
|
145554
|
-
}
|
|
145555
|
-
function buildCommitPrompt(_agentId, status) {
|
|
145556
|
-
return [
|
|
145557
|
-
`UNCOMMITTED CHANGES \u2014 the working tree is dirty. push all changes to a pull request (new or existing). \`git status\` must be clean before you finish.`,
|
|
145558
|
-
"",
|
|
145559
|
-
"```",
|
|
145560
|
-
status,
|
|
145561
|
-
"```"
|
|
145562
|
-
].join("\n");
|
|
145563
|
-
}
|
|
145564
|
-
var agent = (input) => {
|
|
145565
|
-
return {
|
|
145566
|
-
...input,
|
|
145567
|
-
run: async (ctx) => {
|
|
145568
|
-
log.debug(`\xBB payload: ${JSON.stringify(ctx.payload, null, 2)}`);
|
|
145569
|
-
return input.run(ctx);
|
|
145570
|
-
}
|
|
145571
|
-
};
|
|
145572
|
-
};
|
|
145573
|
-
|
|
145574
146599
|
// agents/claude.ts
|
|
145575
146600
|
async function installClaudeCli() {
|
|
145576
146601
|
return await installFromNpmTarball({
|
|
@@ -145609,6 +146634,7 @@ async function runClaude(params) {
|
|
|
145609
146634
|
let finalOutput = "";
|
|
145610
146635
|
let sessionId;
|
|
145611
146636
|
let accumulatedTokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
146637
|
+
let accumulatedCostUsd = 0;
|
|
145612
146638
|
let tokensLogged = false;
|
|
145613
146639
|
function buildUsage() {
|
|
145614
146640
|
const totalInput = accumulatedTokens.input + accumulatedTokens.cacheRead + accumulatedTokens.cacheWrite;
|
|
@@ -145617,7 +146643,8 @@ async function runClaude(params) {
|
|
|
145617
146643
|
inputTokens: totalInput,
|
|
145618
146644
|
outputTokens: accumulatedTokens.output,
|
|
145619
146645
|
cacheReadTokens: accumulatedTokens.cacheRead || void 0,
|
|
145620
|
-
cacheWriteTokens: accumulatedTokens.cacheWrite || void 0
|
|
146646
|
+
cacheWriteTokens: accumulatedTokens.cacheWrite || void 0,
|
|
146647
|
+
costUsd: accumulatedCostUsd > 0 ? accumulatedCostUsd : void 0
|
|
145621
146648
|
} : void 0;
|
|
145622
146649
|
}
|
|
145623
146650
|
const handlers2 = {
|
|
@@ -145634,6 +146661,12 @@ async function runClaude(params) {
|
|
|
145634
146661
|
finalOutput = message;
|
|
145635
146662
|
} else if (block.type === "tool_use") {
|
|
145636
146663
|
const toolName = block.name || "unknown";
|
|
146664
|
+
if (params.onToolUse) {
|
|
146665
|
+
params.onToolUse({
|
|
146666
|
+
toolName,
|
|
146667
|
+
input: block.input
|
|
146668
|
+
});
|
|
146669
|
+
}
|
|
145637
146670
|
thinkingTimer.markToolCall();
|
|
145638
146671
|
log.toolCall({ toolName, input: block.input || {} });
|
|
145639
146672
|
if (toolName.includes("report_progress") && params.todoTracker) {
|
|
@@ -145649,6 +146682,8 @@ async function runClaude(params) {
|
|
|
145649
146682
|
if (msgUsage) {
|
|
145650
146683
|
accumulatedTokens.input += msgUsage.input_tokens || 0;
|
|
145651
146684
|
accumulatedTokens.output += msgUsage.output_tokens || 0;
|
|
146685
|
+
accumulatedTokens.cacheRead += msgUsage.cache_read_input_tokens || 0;
|
|
146686
|
+
accumulatedTokens.cacheWrite += msgUsage.cache_creation_input_tokens || 0;
|
|
145652
146687
|
}
|
|
145653
146688
|
},
|
|
145654
146689
|
user: (event) => {
|
|
@@ -145679,19 +146714,18 @@ async function runClaude(params) {
|
|
|
145679
146714
|
const cacheRead = usage?.cache_read_input_tokens || 0;
|
|
145680
146715
|
const cacheWrite = usage?.cache_creation_input_tokens || 0;
|
|
145681
146716
|
const outputTokens = usage?.output_tokens || 0;
|
|
145682
|
-
const
|
|
146717
|
+
const costUsd = typeof event.total_cost_usd === "number" && Number.isFinite(event.total_cost_usd) ? event.total_cost_usd : 0;
|
|
145683
146718
|
accumulatedTokens = { input: inputTokens, output: outputTokens, cacheRead, cacheWrite };
|
|
146719
|
+
accumulatedCostUsd = costUsd;
|
|
145684
146720
|
log.info(`\xBB ${params.label} result: subtype=${subtype}, turns=${numTurns}`);
|
|
145685
146721
|
if (!tokensLogged) {
|
|
145686
|
-
|
|
145687
|
-
|
|
145688
|
-
|
|
145689
|
-
|
|
145690
|
-
|
|
145691
|
-
|
|
145692
|
-
|
|
145693
|
-
[String(totalInput), String(cacheRead), String(cacheWrite), String(outputTokens)]
|
|
145694
|
-
]);
|
|
146722
|
+
logTokenTable({
|
|
146723
|
+
input: inputTokens,
|
|
146724
|
+
cacheRead,
|
|
146725
|
+
cacheWrite,
|
|
146726
|
+
output: outputTokens,
|
|
146727
|
+
costUsd
|
|
146728
|
+
});
|
|
145695
146729
|
tokensLogged = true;
|
|
145696
146730
|
}
|
|
145697
146731
|
} else if (subtype === "error_max_turns") {
|
|
@@ -145726,6 +146760,7 @@ async function runClaude(params) {
|
|
|
145726
146760
|
cwd: params.cwd,
|
|
145727
146761
|
env: params.env,
|
|
145728
146762
|
activityTimeout: 3e5,
|
|
146763
|
+
onActivityTimeout: params.onActivityTimeout,
|
|
145729
146764
|
stdio: ["ignore", "pipe", "pipe"],
|
|
145730
146765
|
onStdout: async (chunk) => {
|
|
145731
146766
|
const text = chunk.toString();
|
|
@@ -145737,25 +146772,33 @@ async function runClaude(params) {
|
|
|
145737
146772
|
for (const line of lines) {
|
|
145738
146773
|
const trimmed = line.trim();
|
|
145739
146774
|
if (!trimmed) continue;
|
|
146775
|
+
let event;
|
|
145740
146776
|
try {
|
|
145741
|
-
|
|
145742
|
-
eventCount++;
|
|
145743
|
-
log.debug(JSON.stringify(event, null, 2));
|
|
145744
|
-
const timeSinceLastActivity = getIdleMs();
|
|
145745
|
-
if (timeSinceLastActivity > 1e4) {
|
|
145746
|
-
log.info(
|
|
145747
|
-
`\xBB no activity for ${(timeSinceLastActivity / 1e3).toFixed(1)}s (${params.label} may be processing internally) (${eventCount} events processed so far)`
|
|
145748
|
-
);
|
|
145749
|
-
}
|
|
145750
|
-
markActivity();
|
|
145751
|
-
const handler2 = handlers2[event.type];
|
|
145752
|
-
if (handler2) {
|
|
145753
|
-
handler2(event);
|
|
145754
|
-
} else {
|
|
145755
|
-
log.debug(`\xBB ${params.label} event (unhandled): type=${event.type}`);
|
|
145756
|
-
}
|
|
146777
|
+
event = JSON.parse(trimmed);
|
|
145757
146778
|
} catch {
|
|
145758
146779
|
log.debug(`\xBB non-JSON stdout line: ${trimmed.substring(0, 200)}`);
|
|
146780
|
+
continue;
|
|
146781
|
+
}
|
|
146782
|
+
eventCount++;
|
|
146783
|
+
log.debug(JSON.stringify(event, null, 2));
|
|
146784
|
+
const timeSinceLastActivity = getIdleMs();
|
|
146785
|
+
if (timeSinceLastActivity > 1e4) {
|
|
146786
|
+
log.info(
|
|
146787
|
+
`\xBB no activity for ${(timeSinceLastActivity / 1e3).toFixed(1)}s (${params.label} may be processing internally) (${eventCount} events processed so far)`
|
|
146788
|
+
);
|
|
146789
|
+
}
|
|
146790
|
+
markActivity();
|
|
146791
|
+
const handler2 = handlers2[event.type];
|
|
146792
|
+
if (!handler2) {
|
|
146793
|
+
log.debug(`\xBB ${params.label} event (unhandled): type=${event.type}`);
|
|
146794
|
+
continue;
|
|
146795
|
+
}
|
|
146796
|
+
try {
|
|
146797
|
+
handler2(event);
|
|
146798
|
+
} catch (err) {
|
|
146799
|
+
log.info(
|
|
146800
|
+
`\xBB ${params.label} handler for type=${event.type} threw: ${err instanceof Error ? err.message : String(err)}`
|
|
146801
|
+
);
|
|
145759
146802
|
}
|
|
145760
146803
|
}
|
|
145761
146804
|
},
|
|
@@ -145789,16 +146832,9 @@ async function runClaude(params) {
|
|
|
145789
146832
|
if (stderrContext) log.info(`\xBB last stderr output:
|
|
145790
146833
|
${stderrContext}`);
|
|
145791
146834
|
}
|
|
145792
|
-
if (!tokensLogged && (accumulatedTokens.input > 0 || accumulatedTokens.output > 0)) {
|
|
145793
|
-
|
|
145794
|
-
|
|
145795
|
-
[
|
|
145796
|
-
{ data: "Input Tokens", header: true },
|
|
145797
|
-
{ data: "Output Tokens", header: true },
|
|
145798
|
-
{ data: "Total Tokens", header: true }
|
|
145799
|
-
],
|
|
145800
|
-
[String(accumulatedTokens.input), String(accumulatedTokens.output), String(totalTokens)]
|
|
145801
|
-
]);
|
|
146835
|
+
if (!tokensLogged && (accumulatedTokens.input > 0 || accumulatedTokens.output > 0 || accumulatedTokens.cacheRead > 0 || accumulatedTokens.cacheWrite > 0)) {
|
|
146836
|
+
logTokenTable({ ...accumulatedTokens, costUsd: accumulatedCostUsd });
|
|
146837
|
+
tokensLogged = true;
|
|
145802
146838
|
}
|
|
145803
146839
|
const usage = buildUsage();
|
|
145804
146840
|
if (result.exitCode !== 0) {
|
|
@@ -145831,7 +146867,7 @@ ${stderrContext}`);
|
|
|
145831
146867
|
params.todoTracker?.cancel();
|
|
145832
146868
|
const duration4 = performance6.now() - startTime;
|
|
145833
146869
|
const errorMessage = error49 instanceof Error ? error49.message : String(error49);
|
|
145834
|
-
const isActivityTimeout =
|
|
146870
|
+
const isActivityTimeout = error49 instanceof SpawnTimeoutError && error49.code === SPAWN_ACTIVITY_TIMEOUT_CODE;
|
|
145835
146871
|
const stderrContext = recentStderr.slice(-10).join("\n");
|
|
145836
146872
|
const diagnosis = lastProviderError ? `likely cause: ${lastProviderError}` : eventCount === 0 ? "Claude produced 0 stdout events - check if the API is reachable" : `${eventCount} events were processed before the hang`;
|
|
145837
146873
|
log.info(
|
|
@@ -145922,8 +146958,7 @@ var claude = agent({
|
|
|
145922
146958
|
"--effort",
|
|
145923
146959
|
effort,
|
|
145924
146960
|
"--disallowedTools",
|
|
145925
|
-
"Bash"
|
|
145926
|
-
"Agent(Bash)"
|
|
146961
|
+
"Bash,Agent(Bash)"
|
|
145927
146962
|
];
|
|
145928
146963
|
if (model) {
|
|
145929
146964
|
baseArgs.push("--model", model);
|
|
@@ -145936,11 +146971,19 @@ var claude = agent({
|
|
|
145936
146971
|
log.info(`\xBB effort: ${effort}`);
|
|
145937
146972
|
log.debug(`\xBB starting Pullfrog (Claude Code): node ${baseArgs.join(" ")}`);
|
|
145938
146973
|
log.debug(`\xBB working directory: ${repoDir}`);
|
|
145939
|
-
const runParams = {
|
|
146974
|
+
const runParams = {
|
|
146975
|
+
label: "Pullfrog",
|
|
146976
|
+
cwd: repoDir,
|
|
146977
|
+
env: env2,
|
|
146978
|
+
todoTracker: ctx.todoTracker,
|
|
146979
|
+
onActivityTimeout: ctx.onActivityTimeout,
|
|
146980
|
+
onToolUse: ctx.onToolUse
|
|
146981
|
+
};
|
|
145940
146982
|
let result = await runClaude({
|
|
145941
146983
|
...runParams,
|
|
145942
146984
|
args: [...baseArgs, "-p", ctx.instructions.full]
|
|
145943
146985
|
});
|
|
146986
|
+
let aggregatedUsage = result.usage;
|
|
145944
146987
|
for (let attempt = 0; attempt < MAX_COMMIT_RETRIES; attempt++) {
|
|
145945
146988
|
if (!result.success || !result.sessionId) break;
|
|
145946
146989
|
const status = getGitStatus();
|
|
@@ -145957,8 +147000,9 @@ ${status}`);
|
|
|
145957
147000
|
result.sessionId
|
|
145958
147001
|
]
|
|
145959
147002
|
});
|
|
147003
|
+
aggregatedUsage = mergeAgentUsage(aggregatedUsage, result.usage);
|
|
145960
147004
|
}
|
|
145961
|
-
return result;
|
|
147005
|
+
return { ...result, usage: aggregatedUsage };
|
|
145962
147006
|
}
|
|
145963
147007
|
});
|
|
145964
147008
|
|
|
@@ -146040,6 +147084,7 @@ async function runOpenCode(params) {
|
|
|
146040
147084
|
const thinkingTimer = new ThinkingTimer();
|
|
146041
147085
|
let finalOutput = "";
|
|
146042
147086
|
let accumulatedTokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
147087
|
+
let accumulatedCostUsd = 0;
|
|
146043
147088
|
let tokensLogged = false;
|
|
146044
147089
|
const toolCallTimings = /* @__PURE__ */ new Map();
|
|
146045
147090
|
let currentStepId = null;
|
|
@@ -146052,7 +147097,8 @@ async function runOpenCode(params) {
|
|
|
146052
147097
|
inputTokens: totalInput,
|
|
146053
147098
|
outputTokens: accumulatedTokens.output,
|
|
146054
147099
|
cacheReadTokens: accumulatedTokens.cacheRead || void 0,
|
|
146055
|
-
cacheWriteTokens: accumulatedTokens.cacheWrite || void 0
|
|
147100
|
+
cacheWriteTokens: accumulatedTokens.cacheWrite || void 0,
|
|
147101
|
+
costUsd: accumulatedCostUsd > 0 ? accumulatedCostUsd : void 0
|
|
146056
147102
|
} : void 0;
|
|
146057
147103
|
}
|
|
146058
147104
|
const handlers2 = {
|
|
@@ -146063,6 +147109,7 @@ async function runOpenCode(params) {
|
|
|
146063
147109
|
log.debug(`\xBB ${params.label} init event (full): ${JSON.stringify(event)}`);
|
|
146064
147110
|
finalOutput = "";
|
|
146065
147111
|
accumulatedTokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
147112
|
+
accumulatedCostUsd = 0;
|
|
146066
147113
|
tokensLogged = false;
|
|
146067
147114
|
},
|
|
146068
147115
|
message: (event) => {
|
|
@@ -146107,6 +147154,9 @@ async function runOpenCode(params) {
|
|
|
146107
147154
|
accumulatedTokens.cacheRead += eventTokens.cache?.read || 0;
|
|
146108
147155
|
accumulatedTokens.cacheWrite += eventTokens.cache?.write || 0;
|
|
146109
147156
|
}
|
|
147157
|
+
if (typeof event.part?.cost === "number" && Number.isFinite(event.part.cost)) {
|
|
147158
|
+
accumulatedCostUsd += event.part.cost;
|
|
147159
|
+
}
|
|
146110
147160
|
if (currentStepId === stepId) {
|
|
146111
147161
|
currentStepId = null;
|
|
146112
147162
|
currentStepType = null;
|
|
@@ -146124,6 +147174,12 @@ async function runOpenCode(params) {
|
|
|
146124
147174
|
if (stepHistory.length > 0) {
|
|
146125
147175
|
stepHistory[stepHistory.length - 1].toolCalls.push(toolName);
|
|
146126
147176
|
}
|
|
147177
|
+
if (params.onToolUse) {
|
|
147178
|
+
params.onToolUse({
|
|
147179
|
+
toolName,
|
|
147180
|
+
input: event.part?.state?.input
|
|
147181
|
+
});
|
|
147182
|
+
}
|
|
146127
147183
|
thinkingTimer.markToolCall();
|
|
146128
147184
|
log.toolCall({ toolName, input: event.part?.state?.input || {} });
|
|
146129
147185
|
if (event.part?.state?.status === "completed" && event.part.state.output) {
|
|
@@ -146179,19 +147235,9 @@ async function runOpenCode(params) {
|
|
|
146179
147235
|
if (event.status === "error") {
|
|
146180
147236
|
log.info(`\xBB ${params.label} failed: ${JSON.stringify(event)}`);
|
|
146181
147237
|
} else {
|
|
146182
|
-
const inputTokens = event.stats?.input_tokens || accumulatedTokens.input || 0;
|
|
146183
|
-
const outputTokens = event.stats?.output_tokens || accumulatedTokens.output || 0;
|
|
146184
|
-
const totalTokens = event.stats?.total_tokens || inputTokens + outputTokens;
|
|
146185
147238
|
log.info(`\xBB run complete: tool_calls=${toolCalls}, duration=${duration4}ms`);
|
|
146186
|
-
if ((
|
|
146187
|
-
|
|
146188
|
-
[
|
|
146189
|
-
{ data: "Input Tokens", header: true },
|
|
146190
|
-
{ data: "Output Tokens", header: true },
|
|
146191
|
-
{ data: "Total Tokens", header: true }
|
|
146192
|
-
],
|
|
146193
|
-
[String(inputTokens), String(outputTokens), String(totalTokens)]
|
|
146194
|
-
]);
|
|
147239
|
+
if ((accumulatedTokens.input > 0 || accumulatedTokens.output > 0 || accumulatedTokens.cacheRead > 0 || accumulatedTokens.cacheWrite > 0) && !tokensLogged) {
|
|
147240
|
+
logTokenTable({ ...accumulatedTokens, costUsd: accumulatedCostUsd });
|
|
146195
147241
|
tokensLogged = true;
|
|
146196
147242
|
}
|
|
146197
147243
|
}
|
|
@@ -146208,6 +147254,7 @@ async function runOpenCode(params) {
|
|
|
146208
147254
|
cwd: params.cwd,
|
|
146209
147255
|
env: params.env,
|
|
146210
147256
|
activityTimeout: 3e5,
|
|
147257
|
+
onActivityTimeout: params.onActivityTimeout,
|
|
146211
147258
|
stdio: ["ignore", "pipe", "pipe"],
|
|
146212
147259
|
onStdout: async (chunk) => {
|
|
146213
147260
|
const text = chunk.toString();
|
|
@@ -146219,29 +147266,37 @@ async function runOpenCode(params) {
|
|
|
146219
147266
|
for (const line of lines) {
|
|
146220
147267
|
const trimmed = line.trim();
|
|
146221
147268
|
if (!trimmed) continue;
|
|
147269
|
+
let event;
|
|
146222
147270
|
try {
|
|
146223
|
-
|
|
146224
|
-
eventCount++;
|
|
146225
|
-
log.debug(JSON.stringify(event, null, 2));
|
|
146226
|
-
const timeSinceLastActivity = getIdleMs();
|
|
146227
|
-
if (timeSinceLastActivity > 1e4) {
|
|
146228
|
-
const activeToolCalls = toolCallTimings.size;
|
|
146229
|
-
const toolCallInfo = activeToolCalls > 0 ? ` (waiting for ${activeToolCalls} tool call${activeToolCalls > 1 ? "s" : ""})` : ` (${params.label} may be processing internally - LLM calls, planning, etc.)`;
|
|
146230
|
-
log.info(
|
|
146231
|
-
`\xBB no activity for ${(timeSinceLastActivity / 1e3).toFixed(1)}s${toolCallInfo} (${eventCount} events processed so far)`
|
|
146232
|
-
);
|
|
146233
|
-
}
|
|
146234
|
-
markActivity();
|
|
146235
|
-
const handler2 = handlers2[event.type];
|
|
146236
|
-
if (handler2) {
|
|
146237
|
-
await handler2(event);
|
|
146238
|
-
} else {
|
|
146239
|
-
log.info(
|
|
146240
|
-
`\xBB ${params.label} event (unhandled): type=${event.type}, data=${JSON.stringify(event).substring(0, 500)}`
|
|
146241
|
-
);
|
|
146242
|
-
}
|
|
147271
|
+
event = JSON.parse(trimmed);
|
|
146243
147272
|
} catch {
|
|
146244
147273
|
log.debug(`\xBB non-JSON stdout line: ${trimmed.substring(0, 200)}`);
|
|
147274
|
+
continue;
|
|
147275
|
+
}
|
|
147276
|
+
eventCount++;
|
|
147277
|
+
log.debug(JSON.stringify(event, null, 2));
|
|
147278
|
+
const timeSinceLastActivity = getIdleMs();
|
|
147279
|
+
if (timeSinceLastActivity > 1e4) {
|
|
147280
|
+
const activeToolCalls = toolCallTimings.size;
|
|
147281
|
+
const toolCallInfo = activeToolCalls > 0 ? ` (waiting for ${activeToolCalls} tool call${activeToolCalls > 1 ? "s" : ""})` : ` (${params.label} may be processing internally - LLM calls, planning, etc.)`;
|
|
147282
|
+
log.info(
|
|
147283
|
+
`\xBB no activity for ${(timeSinceLastActivity / 1e3).toFixed(1)}s${toolCallInfo} (${eventCount} events processed so far)`
|
|
147284
|
+
);
|
|
147285
|
+
}
|
|
147286
|
+
markActivity();
|
|
147287
|
+
const handler2 = handlers2[event.type];
|
|
147288
|
+
if (!handler2) {
|
|
147289
|
+
log.info(
|
|
147290
|
+
`\xBB ${params.label} event (unhandled): type=${event.type}, data=${JSON.stringify(event).substring(0, 500)}`
|
|
147291
|
+
);
|
|
147292
|
+
continue;
|
|
147293
|
+
}
|
|
147294
|
+
try {
|
|
147295
|
+
await handler2(event);
|
|
147296
|
+
} catch (err) {
|
|
147297
|
+
log.info(
|
|
147298
|
+
`\xBB ${params.label} handler for type=${event.type} threw: ${err instanceof Error ? err.message : String(err)}`
|
|
147299
|
+
);
|
|
146245
147300
|
}
|
|
146246
147301
|
}
|
|
146247
147302
|
},
|
|
@@ -146275,16 +147330,9 @@ async function runOpenCode(params) {
|
|
|
146275
147330
|
if (stderrContext) log.info(`\xBB last stderr output:
|
|
146276
147331
|
${stderrContext}`);
|
|
146277
147332
|
}
|
|
146278
|
-
if (!tokensLogged && (accumulatedTokens.input > 0 || accumulatedTokens.output > 0)) {
|
|
146279
|
-
|
|
146280
|
-
|
|
146281
|
-
[
|
|
146282
|
-
{ data: "Input Tokens", header: true },
|
|
146283
|
-
{ data: "Output Tokens", header: true },
|
|
146284
|
-
{ data: "Total Tokens", header: true }
|
|
146285
|
-
],
|
|
146286
|
-
[String(accumulatedTokens.input), String(accumulatedTokens.output), String(totalTokens)]
|
|
146287
|
-
]);
|
|
147333
|
+
if (!tokensLogged && (accumulatedTokens.input > 0 || accumulatedTokens.output > 0 || accumulatedTokens.cacheRead > 0 || accumulatedTokens.cacheWrite > 0)) {
|
|
147334
|
+
logTokenTable({ ...accumulatedTokens, costUsd: accumulatedCostUsd });
|
|
147335
|
+
tokensLogged = true;
|
|
146288
147336
|
}
|
|
146289
147337
|
const usage = buildUsage();
|
|
146290
147338
|
if (result.exitCode !== 0) {
|
|
@@ -146310,7 +147358,7 @@ ${stderrContext}`);
|
|
|
146310
147358
|
params.todoTracker?.cancel();
|
|
146311
147359
|
const duration4 = performance7.now() - startTime;
|
|
146312
147360
|
const errorMessage = error49 instanceof Error ? error49.message : String(error49);
|
|
146313
|
-
const isActivityTimeout =
|
|
147361
|
+
const isActivityTimeout = error49 instanceof SpawnTimeoutError && error49.code === SPAWN_ACTIVITY_TIMEOUT_CODE;
|
|
146314
147362
|
const stderrContext = recentStderr.slice(-10).join("\n");
|
|
146315
147363
|
const diagnosis = lastProviderError ? `likely cause: ${lastProviderError}` : eventCount === 0 ? "OpenCode produced 0 stdout events - check if the model provider is reachable" : `${eventCount} events were processed before the hang`;
|
|
146316
147364
|
log.info(
|
|
@@ -146367,12 +147415,15 @@ var opencode = agent({
|
|
|
146367
147415
|
cliPath,
|
|
146368
147416
|
cwd: repoDir,
|
|
146369
147417
|
env: env2,
|
|
146370
|
-
todoTracker: ctx.todoTracker
|
|
147418
|
+
todoTracker: ctx.todoTracker,
|
|
147419
|
+
onActivityTimeout: ctx.onActivityTimeout,
|
|
147420
|
+
onToolUse: ctx.onToolUse
|
|
146371
147421
|
};
|
|
146372
147422
|
let result = await runOpenCode({
|
|
146373
147423
|
...runParams,
|
|
146374
147424
|
args: [...baseArgs, ctx.instructions.full]
|
|
146375
147425
|
});
|
|
147426
|
+
let aggregatedUsage = result.usage;
|
|
146376
147427
|
for (let attempt = 0; attempt < MAX_COMMIT_RETRIES; attempt++) {
|
|
146377
147428
|
if (!result.success) break;
|
|
146378
147429
|
const status = getGitStatus();
|
|
@@ -146383,8 +147434,9 @@ ${status}`);
|
|
|
146383
147434
|
...runParams,
|
|
146384
147435
|
args: [...baseArgs, "--continue", buildCommitPrompt("opencode", status)]
|
|
146385
147436
|
});
|
|
147437
|
+
aggregatedUsage = mergeAgentUsage(aggregatedUsage, result.usage);
|
|
146386
147438
|
}
|
|
146387
|
-
return result;
|
|
147439
|
+
return { ...result, usage: aggregatedUsage };
|
|
146388
147440
|
}
|
|
146389
147441
|
});
|
|
146390
147442
|
|
|
@@ -146402,13 +147454,11 @@ function hasClaudeCodeAuth() {
|
|
|
146402
147454
|
function resolveModel(ctx) {
|
|
146403
147455
|
const envModel = process.env.PULLFROG_MODEL?.trim();
|
|
146404
147456
|
if (envModel) {
|
|
146405
|
-
|
|
146406
|
-
return envModel;
|
|
147457
|
+
return resolveCliModel(envModel) ?? envModel;
|
|
146407
147458
|
}
|
|
146408
147459
|
if (ctx.slug) {
|
|
146409
147460
|
const resolved = resolveCliModel(ctx.slug);
|
|
146410
147461
|
if (resolved) {
|
|
146411
|
-
log.info(`\xBB model: ${resolved} (resolved from ${ctx.slug})`);
|
|
146412
147462
|
return resolved;
|
|
146413
147463
|
}
|
|
146414
147464
|
log.warning(`\xBB unknown model slug "${ctx.slug}" \u2014 agent will auto-select`);
|
|
@@ -146419,7 +147469,6 @@ function resolveAgent(ctx) {
|
|
|
146419
147469
|
const envAgent = process.env.PULLFROG_AGENT?.trim();
|
|
146420
147470
|
if (envAgent) {
|
|
146421
147471
|
if (envAgent in agents) {
|
|
146422
|
-
log.info(`\xBB agent: ${envAgent} (override via PULLFROG_AGENT)`);
|
|
146423
147472
|
return agents[envAgent];
|
|
146424
147473
|
}
|
|
146425
147474
|
log.warning(`\xBB unknown PULLFROG_AGENT="${envAgent}" \u2014 falling through to auto-select`);
|
|
@@ -146428,7 +147477,6 @@ function resolveAgent(ctx) {
|
|
|
146428
147477
|
try {
|
|
146429
147478
|
const provider2 = getModelProvider(ctx.model);
|
|
146430
147479
|
if (provider2 === "anthropic" && hasClaudeCodeAuth()) {
|
|
146431
|
-
log.info(`\xBB agent: claude (auto-selected for ${ctx.model})`);
|
|
146432
147480
|
return agents.claude;
|
|
146433
147481
|
}
|
|
146434
147482
|
} catch {
|
|
@@ -150648,9 +151696,9 @@ async function startGitAuthServer(tmpdir3) {
|
|
|
150648
151696
|
res.writeHead(409, { "Content-Type": "text/plain" });
|
|
150649
151697
|
res.end("compromised");
|
|
150650
151698
|
});
|
|
150651
|
-
await new Promise((
|
|
151699
|
+
await new Promise((resolve3, reject) => {
|
|
150652
151700
|
server.on("error", reject);
|
|
150653
|
-
server.listen(0, "127.0.0.1", () =>
|
|
151701
|
+
server.listen(0, "127.0.0.1", () => resolve3());
|
|
150654
151702
|
});
|
|
150655
151703
|
const rawAddr = server.address();
|
|
150656
151704
|
if (!rawAddr || typeof rawAddr === "string") {
|
|
@@ -150694,7 +151742,7 @@ async function startGitAuthServer(tmpdir3) {
|
|
|
150694
151742
|
clearTimeout(entry.timeout);
|
|
150695
151743
|
}
|
|
150696
151744
|
codes.clear();
|
|
150697
|
-
await new Promise((
|
|
151745
|
+
await new Promise((resolve3) => server.close(() => resolve3()));
|
|
150698
151746
|
log.debug("git auth server closed");
|
|
150699
151747
|
}
|
|
150700
151748
|
return {
|
|
@@ -150881,7 +151929,7 @@ MCP servers provide tools you can call. Inspect your available MCP servers at st
|
|
|
150881
151929
|
|
|
150882
151930
|
### Git
|
|
150883
151931
|
|
|
150884
|
-
Use \`${t2("git")}\` for local git commands (status, log,
|
|
151932
|
+
Use \`${t2("git")}\` for local git commands (status, log, add, commit, checkout, branch, merge, etc.). When reviewing a PR, do NOT re-derive the PR diff via \`git diff <base>..<head>\` \u2014 the diffPath returned by \`${t2("checkout_pr")}\` is authoritative. \`git log\` and \`git diff --stat\` are fine for commit-range overview; \`git diff\` / \`git diff --cached\` are fine for inspecting your *own* uncommitted changes. For operations requiring remote authentication, use the dedicated MCP tools:
|
|
150885
151933
|
- \`${t2("push_branch")}\` - push current or specified branch
|
|
150886
151934
|
- \`${t2("git_fetch")}\` - fetch refs from remote
|
|
150887
151935
|
- \`${t2("checkout_pr")}\` - checkout a PR branch (fetches and configures push for forks)
|
|
@@ -151059,7 +152107,7 @@ function normalizeEnv() {
|
|
|
151059
152107
|
|
|
151060
152108
|
// utils/payload.ts
|
|
151061
152109
|
var core4 = __toESM(require_core(), 1);
|
|
151062
|
-
import { isAbsolute, resolve } from "node:path";
|
|
152110
|
+
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
151063
152111
|
|
|
151064
152112
|
// utils/versioning.ts
|
|
151065
152113
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
@@ -151113,8 +152161,8 @@ function isPayloadEvent(value2) {
|
|
|
151113
152161
|
function resolveCwd(cwd) {
|
|
151114
152162
|
const workspace = process.env.GITHUB_WORKSPACE;
|
|
151115
152163
|
if (!cwd) return workspace;
|
|
151116
|
-
if (
|
|
151117
|
-
return workspace ?
|
|
152164
|
+
if (isAbsolute2(cwd)) return cwd;
|
|
152165
|
+
return workspace ? resolve2(workspace, cwd) : cwd;
|
|
151118
152166
|
}
|
|
151119
152167
|
function resolvePromptInput() {
|
|
151120
152168
|
const prompt = core4.getInput("prompt", { required: true });
|
|
@@ -151293,7 +152341,8 @@ var defaultSettings = {
|
|
|
151293
152341
|
shell: "restricted",
|
|
151294
152342
|
prApproveEnabled: false,
|
|
151295
152343
|
modeInstructions: {},
|
|
151296
|
-
learnings: null
|
|
152344
|
+
learnings: null,
|
|
152345
|
+
envAllowlist: null
|
|
151297
152346
|
};
|
|
151298
152347
|
var defaultRunContext = {
|
|
151299
152348
|
settings: defaultSettings,
|
|
@@ -151373,7 +152422,7 @@ async function resolveRunContextData(params) {
|
|
|
151373
152422
|
}
|
|
151374
152423
|
|
|
151375
152424
|
// utils/setup.ts
|
|
151376
|
-
import { execSync as execSync3 } from "node:child_process";
|
|
152425
|
+
import { execFileSync as execFileSync5, execSync as execSync3 } from "node:child_process";
|
|
151377
152426
|
import { mkdtempSync } from "node:fs";
|
|
151378
152427
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
151379
152428
|
import { join as join13 } from "node:path";
|
|
@@ -151383,6 +152432,51 @@ function createTempDirectory() {
|
|
|
151383
152432
|
log.info(`\xBB created temp dir at ${sharedTempDir}`);
|
|
151384
152433
|
return sharedTempDir;
|
|
151385
152434
|
}
|
|
152435
|
+
function envScopedToRepo() {
|
|
152436
|
+
const scoped = { ...process.env };
|
|
152437
|
+
for (const key of Object.keys(scoped)) {
|
|
152438
|
+
if (key.startsWith("GIT_")) delete scoped[key];
|
|
152439
|
+
}
|
|
152440
|
+
return scoped;
|
|
152441
|
+
}
|
|
152442
|
+
function removeIncludeIfEntries(repoDir) {
|
|
152443
|
+
const env2 = envScopedToRepo();
|
|
152444
|
+
let configOutput;
|
|
152445
|
+
try {
|
|
152446
|
+
configOutput = execSync3("git config --local --get-regexp -z ^includeif\\.", {
|
|
152447
|
+
cwd: repoDir,
|
|
152448
|
+
encoding: "utf-8",
|
|
152449
|
+
stdio: "pipe",
|
|
152450
|
+
env: env2
|
|
152451
|
+
});
|
|
152452
|
+
} catch {
|
|
152453
|
+
log.debug("\xBB no includeIf credential entries to remove");
|
|
152454
|
+
return;
|
|
152455
|
+
}
|
|
152456
|
+
const seen = /* @__PURE__ */ new Set();
|
|
152457
|
+
for (const entry of configOutput.split("\0")) {
|
|
152458
|
+
if (!entry) continue;
|
|
152459
|
+
const nl = entry.indexOf("\n");
|
|
152460
|
+
const key = nl === -1 ? entry : entry.slice(0, nl);
|
|
152461
|
+
if (!key || seen.has(key)) continue;
|
|
152462
|
+
seen.add(key);
|
|
152463
|
+
try {
|
|
152464
|
+
execFileSync5("git", ["config", "--local", "--unset-all", key], {
|
|
152465
|
+
cwd: repoDir,
|
|
152466
|
+
stdio: "pipe",
|
|
152467
|
+
env: env2
|
|
152468
|
+
});
|
|
152469
|
+
} catch (error49) {
|
|
152470
|
+
log.debug(
|
|
152471
|
+
`\xBB failed to unset ${key}: ${error49 instanceof Error ? error49.message : String(error49)}`
|
|
152472
|
+
);
|
|
152473
|
+
}
|
|
152474
|
+
}
|
|
152475
|
+
if (seen.size > 0)
|
|
152476
|
+
log.info(
|
|
152477
|
+
`\xBB removed ${seen.size} includeIf credential ${seen.size === 1 ? "entry" : "entries"}`
|
|
152478
|
+
);
|
|
152479
|
+
}
|
|
151386
152480
|
async function setupGit(params) {
|
|
151387
152481
|
const repoDir = process.cwd();
|
|
151388
152482
|
log.info("\xBB setting up git configuration...");
|
|
@@ -151429,24 +152523,7 @@ async function setupGit(params) {
|
|
|
151429
152523
|
} catch {
|
|
151430
152524
|
log.debug("\xBB no existing authentication headers to remove");
|
|
151431
152525
|
}
|
|
151432
|
-
|
|
151433
|
-
const configOutput = execSync3("git config --local --get-regexp ^includeif\\.", {
|
|
151434
|
-
cwd: repoDir,
|
|
151435
|
-
encoding: "utf-8",
|
|
151436
|
-
stdio: "pipe"
|
|
151437
|
-
});
|
|
151438
|
-
for (const line of configOutput.trim().split("\n")) {
|
|
151439
|
-
const key = line.split(" ")[0];
|
|
151440
|
-
if (!key) continue;
|
|
151441
|
-
execSync3(`git config --local --unset "${key}"`, {
|
|
151442
|
-
cwd: repoDir,
|
|
151443
|
-
stdio: "pipe"
|
|
151444
|
-
});
|
|
151445
|
-
}
|
|
151446
|
-
log.info("\xBB removed includeIf credential entries");
|
|
151447
|
-
} catch {
|
|
151448
|
-
log.debug("\xBB no includeIf credential entries to remove");
|
|
151449
|
-
}
|
|
152526
|
+
removeIncludeIfEntries(repoDir);
|
|
151450
152527
|
const originUrl = `https://github.com/${params.owner}/${params.name}.git`;
|
|
151451
152528
|
$("git", ["remote", "set-url", "origin", originUrl], { cwd: repoDir });
|
|
151452
152529
|
params.toolState.pushUrl = originUrl;
|
|
@@ -151465,6 +152542,13 @@ function parseTimeString(input) {
|
|
|
151465
152542
|
const seconds = parseInt(match3[3] || "0", 10);
|
|
151466
152543
|
return (hours * 3600 + minutes * 60 + seconds) * 1e3;
|
|
151467
152544
|
}
|
|
152545
|
+
var TIMEOUT_MAX_MS = 2147483647;
|
|
152546
|
+
function resolveTimeoutMs(input) {
|
|
152547
|
+
if (!input) return null;
|
|
152548
|
+
const parsed2 = parseTimeString(input);
|
|
152549
|
+
if (parsed2 === null || parsed2 <= 0 || parsed2 > TIMEOUT_MAX_MS) return null;
|
|
152550
|
+
return parsed2;
|
|
152551
|
+
}
|
|
151468
152552
|
|
|
151469
152553
|
// utils/todoTracking.ts
|
|
151470
152554
|
function isValidTodoStatus(value2) {
|
|
@@ -151567,9 +152651,12 @@ function createTodoTracker(onUpdate) {
|
|
|
151567
152651
|
if (item.status === "in_progress") item.status = "completed";
|
|
151568
152652
|
}
|
|
151569
152653
|
},
|
|
151570
|
-
renderCollapsible() {
|
|
152654
|
+
renderCollapsible(options) {
|
|
151571
152655
|
if (state.size === 0) return "";
|
|
151572
|
-
const
|
|
152656
|
+
const shouldCompleteInProgress = options?.completeInProgress === true;
|
|
152657
|
+
const todos = Array.from(state.values()).map(
|
|
152658
|
+
(item) => shouldCompleteInProgress && item.status === "in_progress" ? { ...item, status: "completed" } : item
|
|
152659
|
+
);
|
|
151573
152660
|
const completed = todos.filter((t2) => t2.status === "completed").length;
|
|
151574
152661
|
const markdown = renderTodoMarkdown(todos);
|
|
151575
152662
|
return `<details>
|
|
@@ -151629,6 +152716,32 @@ function resolveOutputSchema() {
|
|
|
151629
152716
|
log.info("\xBB structured output schema provided \u2014 output will be required");
|
|
151630
152717
|
return parsed2;
|
|
151631
152718
|
}
|
|
152719
|
+
function resolveTimeoutForLog(timeout) {
|
|
152720
|
+
if (!timeout) return "1h (default)";
|
|
152721
|
+
if (timeout === TIMEOUT_DISABLED) return "none (disabled)";
|
|
152722
|
+
return timeout;
|
|
152723
|
+
}
|
|
152724
|
+
function resolveModelForLog(ctx) {
|
|
152725
|
+
const envModel = process.env.PULLFROG_MODEL?.trim();
|
|
152726
|
+
if (envModel) return `${envModel} (override via PULLFROG_MODEL)`;
|
|
152727
|
+
if (ctx.payload.proxyModel) return `${ctx.payload.proxyModel} (proxy)`;
|
|
152728
|
+
if (ctx.resolvedModel && ctx.payload.model && ctx.payload.model !== ctx.resolvedModel) {
|
|
152729
|
+
return `${ctx.resolvedModel} (resolved from ${ctx.payload.model})`;
|
|
152730
|
+
}
|
|
152731
|
+
if (ctx.resolvedModel) return ctx.resolvedModel;
|
|
152732
|
+
if (ctx.payload.model) return `${ctx.payload.model} (unresolved)`;
|
|
152733
|
+
return "auto";
|
|
152734
|
+
}
|
|
152735
|
+
function resolveAgentForLog(ctx) {
|
|
152736
|
+
const envAgent = process.env.PULLFROG_AGENT?.trim();
|
|
152737
|
+
if (envAgent && envAgent === ctx.agentName) {
|
|
152738
|
+
return `${ctx.agentName} (override via PULLFROG_AGENT)`;
|
|
152739
|
+
}
|
|
152740
|
+
if (ctx.agentName === "claude" && ctx.resolvedModel) {
|
|
152741
|
+
return `${ctx.agentName} (auto-selected for ${ctx.resolvedModel})`;
|
|
152742
|
+
}
|
|
152743
|
+
return ctx.agentName;
|
|
152744
|
+
}
|
|
151632
152745
|
async function mintProxyKey(ctx) {
|
|
151633
152746
|
try {
|
|
151634
152747
|
process.env.ACTIONS_ID_TOKEN_REQUEST_URL = ctx.oidcCredentials.requestUrl;
|
|
@@ -151688,6 +152801,7 @@ async function main() {
|
|
|
151688
152801
|
}
|
|
151689
152802
|
const timer = new Timer();
|
|
151690
152803
|
let activityTimeout = null;
|
|
152804
|
+
let safetyNetTimer;
|
|
151691
152805
|
const resolvedPromptInput = resolvePromptInput();
|
|
151692
152806
|
const toolState = initToolState({
|
|
151693
152807
|
progressCommentId: typeof resolvedPromptInput !== "string" ? resolvedPromptInput.progressCommentId : void 0
|
|
@@ -151707,6 +152821,9 @@ async function main() {
|
|
|
151707
152821
|
const count = Object.keys(runContext.dbSecrets).length;
|
|
151708
152822
|
if (count > 0) log.info(`\xBB ${count} db secret(s) loaded`);
|
|
151709
152823
|
}
|
|
152824
|
+
if (runContext.repoSettings.envAllowlist) {
|
|
152825
|
+
setEnvAllowlist(runContext.repoSettings.envAllowlist);
|
|
152826
|
+
}
|
|
151710
152827
|
const payload = resolvePayload(resolvedPromptInput, runContext.repoSettings);
|
|
151711
152828
|
toolState.model = payload.model;
|
|
151712
152829
|
if (payload.event.trigger === "pull_request_synchronize") {
|
|
@@ -151771,10 +152888,13 @@ async function main() {
|
|
|
151771
152888
|
postCheckoutScript: runContext.repoSettings.postCheckoutScript
|
|
151772
152889
|
});
|
|
151773
152890
|
timer.checkpoint("git");
|
|
151774
|
-
await executeLifecycleHook({
|
|
152891
|
+
const setupHook = await executeLifecycleHook({
|
|
151775
152892
|
event: "setup",
|
|
151776
152893
|
script: runContext.repoSettings.setupScript
|
|
151777
152894
|
});
|
|
152895
|
+
if (setupHook.warning) {
|
|
152896
|
+
throw new Error(setupHook.warning);
|
|
152897
|
+
}
|
|
151778
152898
|
timer.checkpoint("lifecycleHooks::setup");
|
|
151779
152899
|
const agentId = agent2.name;
|
|
151780
152900
|
const modes2 = [...computeModes(agentId), ...runContext.repoSettings.modes];
|
|
@@ -151796,17 +152916,22 @@ async function main() {
|
|
|
151796
152916
|
runId: runInfo.runId,
|
|
151797
152917
|
jobId: runInfo.jobId,
|
|
151798
152918
|
mcpServerUrl: "",
|
|
151799
|
-
tmpdir: tmpdir3
|
|
152919
|
+
tmpdir: tmpdir3,
|
|
152920
|
+
resolvedModel
|
|
151800
152921
|
};
|
|
151801
152922
|
const mcpHttpServer = __using(_stack, await startMcpHttpServer(toolContext, { outputSchema }), true);
|
|
151802
152923
|
toolContext.mcpServerUrl = mcpHttpServer.url;
|
|
151803
152924
|
log.info(`\xBB MCP server started at ${mcpHttpServer.url}`);
|
|
151804
152925
|
timer.checkpoint("mcpServer");
|
|
151805
152926
|
startInstallation(toolContext);
|
|
151806
|
-
|
|
151807
|
-
|
|
152927
|
+
const modelForLog = resolveModelForLog({ payload, resolvedModel });
|
|
152928
|
+
const agentForLog = resolveAgentForLog({ agentName: agent2.name, resolvedModel });
|
|
152929
|
+
const timeoutForLog = resolveTimeoutForLog(payload.timeout);
|
|
152930
|
+
log.info(`\xBB model: ${modelForLog}`);
|
|
152931
|
+
log.info(`\xBB agent: ${agentForLog}`);
|
|
151808
152932
|
log.info(`\xBB push: ${payload.push}`);
|
|
151809
152933
|
log.info(`\xBB shell: ${payload.shell}`);
|
|
152934
|
+
log.info(`\xBB timeout: ${timeoutForLog}`);
|
|
151810
152935
|
const instructions = resolveInstructions({
|
|
151811
152936
|
payload,
|
|
151812
152937
|
repo: runContext.repo,
|
|
@@ -151855,24 +152980,62 @@ ${instructions.user}` : null,
|
|
|
151855
152980
|
}
|
|
151856
152981
|
});
|
|
151857
152982
|
toolState.todoTracker = todoTracker;
|
|
152983
|
+
let innerTimeoutFired = false;
|
|
152984
|
+
const onInnerActivityTimeout = () => {
|
|
152985
|
+
if (innerTimeoutFired) return;
|
|
152986
|
+
innerTimeoutFired = true;
|
|
152987
|
+
log.info(
|
|
152988
|
+
"\xBB inner activity timeout fired \u2014 stopping MCP server and starting 5min safety-net timer"
|
|
152989
|
+
);
|
|
152990
|
+
mcpHttpServer[Symbol.asyncDispose]().catch((err) => {
|
|
152991
|
+
log.debug(
|
|
152992
|
+
`mcp server stop after inner kill failed: ${err instanceof Error ? err.message : String(err)}`
|
|
152993
|
+
);
|
|
152994
|
+
});
|
|
152995
|
+
safetyNetTimer = setTimeout(
|
|
152996
|
+
() => {
|
|
152997
|
+
activityTimeout?.forceReject(
|
|
152998
|
+
"agent still pending 5min after inner activity kill \u2014 forcing exit"
|
|
152999
|
+
);
|
|
153000
|
+
},
|
|
153001
|
+
5 * 60 * 1e3
|
|
153002
|
+
);
|
|
153003
|
+
safetyNetTimer.unref?.();
|
|
153004
|
+
};
|
|
151858
153005
|
const agentPromise = agent2.run({
|
|
151859
153006
|
payload,
|
|
151860
153007
|
resolvedModel,
|
|
151861
153008
|
mcpServerUrl: mcpHttpServer.url,
|
|
151862
153009
|
tmpdir: tmpdir3,
|
|
151863
153010
|
instructions,
|
|
151864
|
-
todoTracker
|
|
153011
|
+
todoTracker,
|
|
153012
|
+
onActivityTimeout: onInnerActivityTimeout,
|
|
153013
|
+
onToolUse: (event) => {
|
|
153014
|
+
const wasTracked = recordDiffReadFromToolUse({
|
|
153015
|
+
state: toolState.diffCoverage,
|
|
153016
|
+
toolName: event.toolName,
|
|
153017
|
+
input: event.input,
|
|
153018
|
+
cwd: process.cwd()
|
|
153019
|
+
});
|
|
153020
|
+
if (!wasTracked) return;
|
|
153021
|
+
const trackedRanges = toolState.diffCoverage?.coveredRanges ?? [];
|
|
153022
|
+
log.debug(
|
|
153023
|
+
`\xBB diff coverage tracked from tool ${event.toolName} (${trackedRanges.length} merged range${trackedRanges.length === 1 ? "" : "s"})`
|
|
153024
|
+
);
|
|
153025
|
+
}
|
|
153026
|
+
});
|
|
153027
|
+
agentPromise.catch(() => {
|
|
151865
153028
|
});
|
|
151866
153029
|
let result;
|
|
151867
153030
|
if (payload.timeout === TIMEOUT_DISABLED) {
|
|
151868
153031
|
result = await Promise.race([agentPromise, activityTimeout.promise]);
|
|
151869
153032
|
} else {
|
|
151870
|
-
const
|
|
151871
|
-
if (payload.timeout &&
|
|
151872
|
-
log.warning(`invalid timeout
|
|
153033
|
+
const usable = resolveTimeoutMs(payload.timeout);
|
|
153034
|
+
if (payload.timeout && usable === null) {
|
|
153035
|
+
log.warning(`invalid timeout "${payload.timeout}" (use --notimeout to disable), using 1h`);
|
|
151873
153036
|
}
|
|
151874
|
-
const timeoutMs =
|
|
151875
|
-
const actualTimeout =
|
|
153037
|
+
const timeoutMs = usable ?? 36e5;
|
|
153038
|
+
const actualTimeout = usable !== null ? payload.timeout : "1h";
|
|
151876
153039
|
let timeoutId;
|
|
151877
153040
|
const timeoutPromise = new Promise((_4, reject) => {
|
|
151878
153041
|
timeoutId = setTimeout(() => {
|
|
@@ -151959,8 +153122,21 @@ ${errorMessage}
|
|
|
151959
153122
|
};
|
|
151960
153123
|
} finally {
|
|
151961
153124
|
activityTimeout?.stop();
|
|
153125
|
+
if (safetyNetTimer) clearTimeout(safetyNetTimer);
|
|
151962
153126
|
if (usageSummaryPath) {
|
|
151963
|
-
|
|
153127
|
+
try {
|
|
153128
|
+
await writeGitHubUsageSummaryToFile(usageSummaryPath);
|
|
153129
|
+
} catch (err) {
|
|
153130
|
+
log.debug(
|
|
153131
|
+
`failed to write usage summary to ${usageSummaryPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
153132
|
+
);
|
|
153133
|
+
}
|
|
153134
|
+
}
|
|
153135
|
+
if (toolContext) {
|
|
153136
|
+
const patch = aggregateUsage(toolState.usageEntries);
|
|
153137
|
+
if (Object.keys(patch).length > 0) {
|
|
153138
|
+
await patchWorkflowRunFields(toolContext, patch);
|
|
153139
|
+
}
|
|
151964
153140
|
}
|
|
151965
153141
|
}
|
|
151966
153142
|
} catch (_3) {
|
|
@@ -152014,7 +153190,7 @@ async function validateStuckProgressComment(ctx) {
|
|
|
152014
153190
|
comment_id: commentId
|
|
152015
153191
|
});
|
|
152016
153192
|
const body = commentResult.data.body ?? "";
|
|
152017
|
-
if (body
|
|
153193
|
+
if (isLeapingIntoActionCommentBody(body)) {
|
|
152018
153194
|
log.info(`[post] comment ${commentId} is stuck on "Leaping into action"`);
|
|
152019
153195
|
return commentId;
|
|
152020
153196
|
}
|
|
@@ -152224,7 +153400,7 @@ async function run(args2) {
|
|
|
152224
153400
|
}
|
|
152225
153401
|
|
|
152226
153402
|
// commands/init.ts
|
|
152227
|
-
import { execFileSync as
|
|
153403
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
152228
153404
|
|
|
152229
153405
|
// node_modules/.pnpm/@clack+core@1.2.0/node_modules/@clack/core/dist/index.mjs
|
|
152230
153406
|
import { styleText as y } from "node:util";
|
|
@@ -153216,7 +154392,7 @@ function handleCancel(value2) {
|
|
|
153216
154392
|
function getGhToken() {
|
|
153217
154393
|
let token;
|
|
153218
154394
|
try {
|
|
153219
|
-
token =
|
|
154395
|
+
token = execFileSync6("gh", ["auth", "token"], { encoding: "utf-8" }).trim();
|
|
153220
154396
|
} catch {
|
|
153221
154397
|
bail(
|
|
153222
154398
|
`gh cli not found or not authenticated.
|
|
@@ -153259,7 +154435,7 @@ async function ghApi(path3, token) {
|
|
|
153259
154435
|
function parseGitRemote() {
|
|
153260
154436
|
let url4;
|
|
153261
154437
|
try {
|
|
153262
|
-
url4 =
|
|
154438
|
+
url4 = execFileSync6("git", ["remote", "get-url", "origin"], { encoding: "utf-8" }).trim();
|
|
153263
154439
|
} catch {
|
|
153264
154440
|
bail("not a git repository or no 'origin' remote found.");
|
|
153265
154441
|
}
|
|
@@ -153270,10 +154446,10 @@ function parseGitRemote() {
|
|
|
153270
154446
|
function openBrowser(url4) {
|
|
153271
154447
|
try {
|
|
153272
154448
|
const platform = process.platform;
|
|
153273
|
-
if (platform === "darwin")
|
|
154449
|
+
if (platform === "darwin") execFileSync6("open", [url4], { stdio: "ignore" });
|
|
153274
154450
|
else if (platform === "win32")
|
|
153275
|
-
|
|
153276
|
-
else
|
|
154451
|
+
execFileSync6("cmd", ["/c", "start", "", url4], { stdio: "ignore" });
|
|
154452
|
+
else execFileSync6("xdg-open", [url4], { stdio: "ignore" });
|
|
153277
154453
|
} catch {
|
|
153278
154454
|
}
|
|
153279
154455
|
}
|
|
@@ -153500,7 +154676,7 @@ function setGhSecret(ctx) {
|
|
|
153500
154676
|
let orgFailed = false;
|
|
153501
154677
|
if (ctx.org) {
|
|
153502
154678
|
try {
|
|
153503
|
-
|
|
154679
|
+
execFileSync6("gh", ["secret", "set", ctx.name, "--org", ctx.org, "--visibility", "all"], {
|
|
153504
154680
|
input: ctx.value,
|
|
153505
154681
|
stdio: ["pipe", "ignore", "pipe"],
|
|
153506
154682
|
encoding: "utf-8"
|
|
@@ -153511,7 +154687,7 @@ function setGhSecret(ctx) {
|
|
|
153511
154687
|
}
|
|
153512
154688
|
}
|
|
153513
154689
|
try {
|
|
153514
|
-
|
|
154690
|
+
execFileSync6("gh", ["secret", "set", ctx.name, "--repo", ctx.repoSlug], {
|
|
153515
154691
|
input: ctx.value,
|
|
153516
154692
|
stdio: ["pipe", "ignore", "pipe"],
|
|
153517
154693
|
encoding: "utf-8"
|
|
@@ -153881,7 +155057,7 @@ async function run2() {
|
|
|
153881
155057
|
}
|
|
153882
155058
|
|
|
153883
155059
|
// cli.ts
|
|
153884
|
-
var VERSION10 = "0.0.
|
|
155060
|
+
var VERSION10 = "0.0.202";
|
|
153885
155061
|
var bin = basename2(process.argv[1] || "");
|
|
153886
155062
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
153887
155063
|
var rawArgs = process.argv.slice(2);
|