@helloleo/plugins 0.1.3 → 0.1.5
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/index.js +250 -74
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/tools/inspect-http.ts +258 -0
- package/src/utils/try-catch.ts +22 -0
package/dist/index.js
CHANGED
|
@@ -10,11 +10,7 @@ var __export = (target, all) => {
|
|
|
10
10
|
});
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
import { unlink } from "fs/promises";
|
|
15
|
-
import path from "path";
|
|
16
|
-
|
|
17
|
-
// node_modules/zod/v4/classic/external.js
|
|
13
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
|
|
18
14
|
var exports_external = {};
|
|
19
15
|
__export(exports_external, {
|
|
20
16
|
xid: () => xid2,
|
|
@@ -244,7 +240,7 @@ __export(exports_external, {
|
|
|
244
240
|
$brand: () => $brand
|
|
245
241
|
});
|
|
246
242
|
|
|
247
|
-
// node_modules/zod/v4/core/index.js
|
|
243
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/index.js
|
|
248
244
|
var exports_core2 = {};
|
|
249
245
|
__export(exports_core2, {
|
|
250
246
|
version: () => version,
|
|
@@ -508,7 +504,7 @@ __export(exports_core2, {
|
|
|
508
504
|
$ZodAny: () => $ZodAny
|
|
509
505
|
});
|
|
510
506
|
|
|
511
|
-
// node_modules/zod/v4/core/core.js
|
|
507
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/core.js
|
|
512
508
|
var NEVER = Object.freeze({
|
|
513
509
|
status: "aborted"
|
|
514
510
|
});
|
|
@@ -575,7 +571,7 @@ function config(newConfig) {
|
|
|
575
571
|
Object.assign(globalConfig, newConfig);
|
|
576
572
|
return globalConfig;
|
|
577
573
|
}
|
|
578
|
-
// node_modules/zod/v4/core/util.js
|
|
574
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/util.js
|
|
579
575
|
var exports_util = {};
|
|
580
576
|
__export(exports_util, {
|
|
581
577
|
unwrapMessage: () => unwrapMessage,
|
|
@@ -1204,7 +1200,7 @@ class Class {
|
|
|
1204
1200
|
constructor(..._args) {}
|
|
1205
1201
|
}
|
|
1206
1202
|
|
|
1207
|
-
// node_modules/zod/v4/core/errors.js
|
|
1203
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/errors.js
|
|
1208
1204
|
var initializer = (inst, def) => {
|
|
1209
1205
|
inst.name = "$ZodError";
|
|
1210
1206
|
Object.defineProperty(inst, "_zod", {
|
|
@@ -1347,7 +1343,7 @@ function prettifyError(error) {
|
|
|
1347
1343
|
`);
|
|
1348
1344
|
}
|
|
1349
1345
|
|
|
1350
|
-
// node_modules/zod/v4/core/parse.js
|
|
1346
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/parse.js
|
|
1351
1347
|
var _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
1352
1348
|
const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
|
1353
1349
|
const result = schema._zod.run({ value, issues: [] }, ctx);
|
|
@@ -1434,7 +1430,7 @@ var _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
|
|
|
1434
1430
|
return _safeParseAsync(_Err)(schema, value, _ctx);
|
|
1435
1431
|
};
|
|
1436
1432
|
var safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
|
|
1437
|
-
// node_modules/zod/v4/core/regexes.js
|
|
1433
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/regexes.js
|
|
1438
1434
|
var exports_regexes = {};
|
|
1439
1435
|
__export(exports_regexes, {
|
|
1440
1436
|
xid: () => xid,
|
|
@@ -1586,7 +1582,7 @@ var sha512_hex = /^[0-9a-fA-F]{128}$/;
|
|
|
1586
1582
|
var sha512_base64 = /* @__PURE__ */ fixedBase64(86, "==");
|
|
1587
1583
|
var sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
|
|
1588
1584
|
|
|
1589
|
-
// node_modules/zod/v4/core/checks.js
|
|
1585
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/checks.js
|
|
1590
1586
|
var $ZodCheck = /* @__PURE__ */ $constructor("$ZodCheck", (inst, def) => {
|
|
1591
1587
|
var _a;
|
|
1592
1588
|
inst._zod ?? (inst._zod = {});
|
|
@@ -2127,7 +2123,7 @@ var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (ins
|
|
|
2127
2123
|
};
|
|
2128
2124
|
});
|
|
2129
2125
|
|
|
2130
|
-
// node_modules/zod/v4/core/doc.js
|
|
2126
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/doc.js
|
|
2131
2127
|
class Doc {
|
|
2132
2128
|
constructor(args = []) {
|
|
2133
2129
|
this.content = [];
|
|
@@ -2165,14 +2161,14 @@ class Doc {
|
|
|
2165
2161
|
}
|
|
2166
2162
|
}
|
|
2167
2163
|
|
|
2168
|
-
// node_modules/zod/v4/core/versions.js
|
|
2164
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/versions.js
|
|
2169
2165
|
var version = {
|
|
2170
2166
|
major: 4,
|
|
2171
2167
|
minor: 1,
|
|
2172
2168
|
patch: 8
|
|
2173
2169
|
};
|
|
2174
2170
|
|
|
2175
|
-
// node_modules/zod/v4/core/schemas.js
|
|
2171
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/schemas.js
|
|
2176
2172
|
var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
2177
2173
|
var _a;
|
|
2178
2174
|
inst ?? (inst = {});
|
|
@@ -3995,7 +3991,7 @@ function handleRefineResult(result, payload, input, inst) {
|
|
|
3995
3991
|
payload.issues.push(issue(_iss));
|
|
3996
3992
|
}
|
|
3997
3993
|
}
|
|
3998
|
-
// node_modules/zod/v4/locales/index.js
|
|
3994
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/index.js
|
|
3999
3995
|
var exports_locales = {};
|
|
4000
3996
|
__export(exports_locales, {
|
|
4001
3997
|
zhTW: () => zh_TW_default,
|
|
@@ -4046,7 +4042,7 @@ __export(exports_locales, {
|
|
|
4046
4042
|
ar: () => ar_default
|
|
4047
4043
|
});
|
|
4048
4044
|
|
|
4049
|
-
// node_modules/zod/v4/locales/ar.js
|
|
4045
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ar.js
|
|
4050
4046
|
var error = () => {
|
|
4051
4047
|
const Sizable = {
|
|
4052
4048
|
string: { unit: "\u062D\u0631\u0641", verb: "\u0623\u0646 \u064A\u062D\u0648\u064A" },
|
|
@@ -4162,7 +4158,7 @@ function ar_default() {
|
|
|
4162
4158
|
localeError: error()
|
|
4163
4159
|
};
|
|
4164
4160
|
}
|
|
4165
|
-
// node_modules/zod/v4/locales/az.js
|
|
4161
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/az.js
|
|
4166
4162
|
var error2 = () => {
|
|
4167
4163
|
const Sizable = {
|
|
4168
4164
|
string: { unit: "simvol", verb: "olmal\u0131d\u0131r" },
|
|
@@ -4277,7 +4273,7 @@ function az_default() {
|
|
|
4277
4273
|
localeError: error2()
|
|
4278
4274
|
};
|
|
4279
4275
|
}
|
|
4280
|
-
// node_modules/zod/v4/locales/be.js
|
|
4276
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/be.js
|
|
4281
4277
|
function getBelarusianPlural(count, one, few, many) {
|
|
4282
4278
|
const absCount = Math.abs(count);
|
|
4283
4279
|
const lastDigit = absCount % 10;
|
|
@@ -4441,7 +4437,7 @@ function be_default() {
|
|
|
4441
4437
|
localeError: error3()
|
|
4442
4438
|
};
|
|
4443
4439
|
}
|
|
4444
|
-
// node_modules/zod/v4/locales/ca.js
|
|
4440
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ca.js
|
|
4445
4441
|
var error4 = () => {
|
|
4446
4442
|
const Sizable = {
|
|
4447
4443
|
string: { unit: "car\xE0cters", verb: "contenir" },
|
|
@@ -4558,7 +4554,7 @@ function ca_default() {
|
|
|
4558
4554
|
localeError: error4()
|
|
4559
4555
|
};
|
|
4560
4556
|
}
|
|
4561
|
-
// node_modules/zod/v4/locales/cs.js
|
|
4557
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/cs.js
|
|
4562
4558
|
var error5 = () => {
|
|
4563
4559
|
const Sizable = {
|
|
4564
4560
|
string: { unit: "znak\u016F", verb: "m\xEDt" },
|
|
@@ -4693,7 +4689,7 @@ function cs_default() {
|
|
|
4693
4689
|
localeError: error5()
|
|
4694
4690
|
};
|
|
4695
4691
|
}
|
|
4696
|
-
// node_modules/zod/v4/locales/da.js
|
|
4692
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/da.js
|
|
4697
4693
|
var error6 = () => {
|
|
4698
4694
|
const Sizable = {
|
|
4699
4695
|
string: { unit: "tegn", verb: "havde" },
|
|
@@ -4824,7 +4820,7 @@ function da_default() {
|
|
|
4824
4820
|
localeError: error6()
|
|
4825
4821
|
};
|
|
4826
4822
|
}
|
|
4827
|
-
// node_modules/zod/v4/locales/de.js
|
|
4823
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/de.js
|
|
4828
4824
|
var error7 = () => {
|
|
4829
4825
|
const Sizable = {
|
|
4830
4826
|
string: { unit: "Zeichen", verb: "zu haben" },
|
|
@@ -4940,7 +4936,7 @@ function de_default() {
|
|
|
4940
4936
|
localeError: error7()
|
|
4941
4937
|
};
|
|
4942
4938
|
}
|
|
4943
|
-
// node_modules/zod/v4/locales/en.js
|
|
4939
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/en.js
|
|
4944
4940
|
var parsedType = (data) => {
|
|
4945
4941
|
const t = typeof data;
|
|
4946
4942
|
switch (t) {
|
|
@@ -5057,7 +5053,7 @@ function en_default() {
|
|
|
5057
5053
|
localeError: error8()
|
|
5058
5054
|
};
|
|
5059
5055
|
}
|
|
5060
|
-
// node_modules/zod/v4/locales/eo.js
|
|
5056
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/eo.js
|
|
5061
5057
|
var parsedType2 = (data) => {
|
|
5062
5058
|
const t = typeof data;
|
|
5063
5059
|
switch (t) {
|
|
@@ -5173,7 +5169,7 @@ function eo_default() {
|
|
|
5173
5169
|
localeError: error9()
|
|
5174
5170
|
};
|
|
5175
5171
|
}
|
|
5176
|
-
// node_modules/zod/v4/locales/es.js
|
|
5172
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/es.js
|
|
5177
5173
|
var error10 = () => {
|
|
5178
5174
|
const Sizable = {
|
|
5179
5175
|
string: { unit: "caracteres", verb: "tener" },
|
|
@@ -5321,7 +5317,7 @@ function es_default() {
|
|
|
5321
5317
|
localeError: error10()
|
|
5322
5318
|
};
|
|
5323
5319
|
}
|
|
5324
|
-
// node_modules/zod/v4/locales/fa.js
|
|
5320
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fa.js
|
|
5325
5321
|
var error11 = () => {
|
|
5326
5322
|
const Sizable = {
|
|
5327
5323
|
string: { unit: "\u06A9\u0627\u0631\u0627\u06A9\u062A\u0631", verb: "\u062F\u0627\u0634\u062A\u0647 \u0628\u0627\u0634\u062F" },
|
|
@@ -5443,7 +5439,7 @@ function fa_default() {
|
|
|
5443
5439
|
localeError: error11()
|
|
5444
5440
|
};
|
|
5445
5441
|
}
|
|
5446
|
-
// node_modules/zod/v4/locales/fi.js
|
|
5442
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fi.js
|
|
5447
5443
|
var error12 = () => {
|
|
5448
5444
|
const Sizable = {
|
|
5449
5445
|
string: { unit: "merkki\xE4", subject: "merkkijonon" },
|
|
@@ -5565,7 +5561,7 @@ function fi_default() {
|
|
|
5565
5561
|
localeError: error12()
|
|
5566
5562
|
};
|
|
5567
5563
|
}
|
|
5568
|
-
// node_modules/zod/v4/locales/fr.js
|
|
5564
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fr.js
|
|
5569
5565
|
var error13 = () => {
|
|
5570
5566
|
const Sizable = {
|
|
5571
5567
|
string: { unit: "caract\xE8res", verb: "avoir" },
|
|
@@ -5681,7 +5677,7 @@ function fr_default() {
|
|
|
5681
5677
|
localeError: error13()
|
|
5682
5678
|
};
|
|
5683
5679
|
}
|
|
5684
|
-
// node_modules/zod/v4/locales/fr-CA.js
|
|
5680
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/fr-CA.js
|
|
5685
5681
|
var error14 = () => {
|
|
5686
5682
|
const Sizable = {
|
|
5687
5683
|
string: { unit: "caract\xE8res", verb: "avoir" },
|
|
@@ -5798,7 +5794,7 @@ function fr_CA_default() {
|
|
|
5798
5794
|
localeError: error14()
|
|
5799
5795
|
};
|
|
5800
5796
|
}
|
|
5801
|
-
// node_modules/zod/v4/locales/he.js
|
|
5797
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/he.js
|
|
5802
5798
|
var error15 = () => {
|
|
5803
5799
|
const Sizable = {
|
|
5804
5800
|
string: { unit: "\u05D0\u05D5\u05EA\u05D9\u05D5\u05EA", verb: "\u05DC\u05DB\u05DC\u05D5\u05DC" },
|
|
@@ -5914,7 +5910,7 @@ function he_default() {
|
|
|
5914
5910
|
localeError: error15()
|
|
5915
5911
|
};
|
|
5916
5912
|
}
|
|
5917
|
-
// node_modules/zod/v4/locales/hu.js
|
|
5913
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/hu.js
|
|
5918
5914
|
var error16 = () => {
|
|
5919
5915
|
const Sizable = {
|
|
5920
5916
|
string: { unit: "karakter", verb: "legyen" },
|
|
@@ -6030,7 +6026,7 @@ function hu_default() {
|
|
|
6030
6026
|
localeError: error16()
|
|
6031
6027
|
};
|
|
6032
6028
|
}
|
|
6033
|
-
// node_modules/zod/v4/locales/id.js
|
|
6029
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/id.js
|
|
6034
6030
|
var error17 = () => {
|
|
6035
6031
|
const Sizable = {
|
|
6036
6032
|
string: { unit: "karakter", verb: "memiliki" },
|
|
@@ -6146,7 +6142,7 @@ function id_default() {
|
|
|
6146
6142
|
localeError: error17()
|
|
6147
6143
|
};
|
|
6148
6144
|
}
|
|
6149
|
-
// node_modules/zod/v4/locales/is.js
|
|
6145
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/is.js
|
|
6150
6146
|
var parsedType3 = (data) => {
|
|
6151
6147
|
const t = typeof data;
|
|
6152
6148
|
switch (t) {
|
|
@@ -6263,7 +6259,7 @@ function is_default() {
|
|
|
6263
6259
|
localeError: error18()
|
|
6264
6260
|
};
|
|
6265
6261
|
}
|
|
6266
|
-
// node_modules/zod/v4/locales/it.js
|
|
6262
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/it.js
|
|
6267
6263
|
var error19 = () => {
|
|
6268
6264
|
const Sizable = {
|
|
6269
6265
|
string: { unit: "caratteri", verb: "avere" },
|
|
@@ -6379,7 +6375,7 @@ function it_default() {
|
|
|
6379
6375
|
localeError: error19()
|
|
6380
6376
|
};
|
|
6381
6377
|
}
|
|
6382
|
-
// node_modules/zod/v4/locales/ja.js
|
|
6378
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ja.js
|
|
6383
6379
|
var error20 = () => {
|
|
6384
6380
|
const Sizable = {
|
|
6385
6381
|
string: { unit: "\u6587\u5B57", verb: "\u3067\u3042\u308B" },
|
|
@@ -6494,7 +6490,7 @@ function ja_default() {
|
|
|
6494
6490
|
localeError: error20()
|
|
6495
6491
|
};
|
|
6496
6492
|
}
|
|
6497
|
-
// node_modules/zod/v4/locales/ka.js
|
|
6493
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ka.js
|
|
6498
6494
|
var parsedType4 = (data) => {
|
|
6499
6495
|
const t = typeof data;
|
|
6500
6496
|
switch (t) {
|
|
@@ -6619,7 +6615,7 @@ function ka_default() {
|
|
|
6619
6615
|
localeError: error21()
|
|
6620
6616
|
};
|
|
6621
6617
|
}
|
|
6622
|
-
// node_modules/zod/v4/locales/km.js
|
|
6618
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/km.js
|
|
6623
6619
|
var error22 = () => {
|
|
6624
6620
|
const Sizable = {
|
|
6625
6621
|
string: { unit: "\u178F\u17BD\u17A2\u1780\u17D2\u179F\u179A", verb: "\u1782\u17BD\u179A\u1798\u17B6\u1793" },
|
|
@@ -6737,11 +6733,11 @@ function km_default() {
|
|
|
6737
6733
|
};
|
|
6738
6734
|
}
|
|
6739
6735
|
|
|
6740
|
-
// node_modules/zod/v4/locales/kh.js
|
|
6736
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/kh.js
|
|
6741
6737
|
function kh_default() {
|
|
6742
6738
|
return km_default();
|
|
6743
6739
|
}
|
|
6744
|
-
// node_modules/zod/v4/locales/ko.js
|
|
6740
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ko.js
|
|
6745
6741
|
var error23 = () => {
|
|
6746
6742
|
const Sizable = {
|
|
6747
6743
|
string: { unit: "\uBB38\uC790", verb: "to have" },
|
|
@@ -6862,7 +6858,7 @@ function ko_default() {
|
|
|
6862
6858
|
localeError: error23()
|
|
6863
6859
|
};
|
|
6864
6860
|
}
|
|
6865
|
-
// node_modules/zod/v4/locales/lt.js
|
|
6861
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/lt.js
|
|
6866
6862
|
var parsedType5 = (data) => {
|
|
6867
6863
|
const t = typeof data;
|
|
6868
6864
|
return parsedTypeFromType(t, data);
|
|
@@ -7091,7 +7087,7 @@ function lt_default() {
|
|
|
7091
7087
|
localeError: error24()
|
|
7092
7088
|
};
|
|
7093
7089
|
}
|
|
7094
|
-
// node_modules/zod/v4/locales/mk.js
|
|
7090
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/mk.js
|
|
7095
7091
|
var error25 = () => {
|
|
7096
7092
|
const Sizable = {
|
|
7097
7093
|
string: { unit: "\u0437\u043D\u0430\u0446\u0438", verb: "\u0434\u0430 \u0438\u043C\u0430\u0430\u0442" },
|
|
@@ -7208,7 +7204,7 @@ function mk_default() {
|
|
|
7208
7204
|
localeError: error25()
|
|
7209
7205
|
};
|
|
7210
7206
|
}
|
|
7211
|
-
// node_modules/zod/v4/locales/ms.js
|
|
7207
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ms.js
|
|
7212
7208
|
var error26 = () => {
|
|
7213
7209
|
const Sizable = {
|
|
7214
7210
|
string: { unit: "aksara", verb: "mempunyai" },
|
|
@@ -7324,7 +7320,7 @@ function ms_default() {
|
|
|
7324
7320
|
localeError: error26()
|
|
7325
7321
|
};
|
|
7326
7322
|
}
|
|
7327
|
-
// node_modules/zod/v4/locales/nl.js
|
|
7323
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/nl.js
|
|
7328
7324
|
var error27 = () => {
|
|
7329
7325
|
const Sizable = {
|
|
7330
7326
|
string: { unit: "tekens" },
|
|
@@ -7441,7 +7437,7 @@ function nl_default() {
|
|
|
7441
7437
|
localeError: error27()
|
|
7442
7438
|
};
|
|
7443
7439
|
}
|
|
7444
|
-
// node_modules/zod/v4/locales/no.js
|
|
7440
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/no.js
|
|
7445
7441
|
var error28 = () => {
|
|
7446
7442
|
const Sizable = {
|
|
7447
7443
|
string: { unit: "tegn", verb: "\xE5 ha" },
|
|
@@ -7557,7 +7553,7 @@ function no_default() {
|
|
|
7557
7553
|
localeError: error28()
|
|
7558
7554
|
};
|
|
7559
7555
|
}
|
|
7560
|
-
// node_modules/zod/v4/locales/ota.js
|
|
7556
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ota.js
|
|
7561
7557
|
var error29 = () => {
|
|
7562
7558
|
const Sizable = {
|
|
7563
7559
|
string: { unit: "harf", verb: "olmal\u0131d\u0131r" },
|
|
@@ -7673,7 +7669,7 @@ function ota_default() {
|
|
|
7673
7669
|
localeError: error29()
|
|
7674
7670
|
};
|
|
7675
7671
|
}
|
|
7676
|
-
// node_modules/zod/v4/locales/ps.js
|
|
7672
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ps.js
|
|
7677
7673
|
var error30 = () => {
|
|
7678
7674
|
const Sizable = {
|
|
7679
7675
|
string: { unit: "\u062A\u0648\u06A9\u064A", verb: "\u0648\u0644\u0631\u064A" },
|
|
@@ -7795,7 +7791,7 @@ function ps_default() {
|
|
|
7795
7791
|
localeError: error30()
|
|
7796
7792
|
};
|
|
7797
7793
|
}
|
|
7798
|
-
// node_modules/zod/v4/locales/pl.js
|
|
7794
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/pl.js
|
|
7799
7795
|
var error31 = () => {
|
|
7800
7796
|
const Sizable = {
|
|
7801
7797
|
string: { unit: "znak\xF3w", verb: "mie\u0107" },
|
|
@@ -7912,7 +7908,7 @@ function pl_default() {
|
|
|
7912
7908
|
localeError: error31()
|
|
7913
7909
|
};
|
|
7914
7910
|
}
|
|
7915
|
-
// node_modules/zod/v4/locales/pt.js
|
|
7911
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/pt.js
|
|
7916
7912
|
var error32 = () => {
|
|
7917
7913
|
const Sizable = {
|
|
7918
7914
|
string: { unit: "caracteres", verb: "ter" },
|
|
@@ -8028,7 +8024,7 @@ function pt_default() {
|
|
|
8028
8024
|
localeError: error32()
|
|
8029
8025
|
};
|
|
8030
8026
|
}
|
|
8031
|
-
// node_modules/zod/v4/locales/ru.js
|
|
8027
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ru.js
|
|
8032
8028
|
function getRussianPlural(count, one, few, many) {
|
|
8033
8029
|
const absCount = Math.abs(count);
|
|
8034
8030
|
const lastDigit = absCount % 10;
|
|
@@ -8192,7 +8188,7 @@ function ru_default() {
|
|
|
8192
8188
|
localeError: error33()
|
|
8193
8189
|
};
|
|
8194
8190
|
}
|
|
8195
|
-
// node_modules/zod/v4/locales/sl.js
|
|
8191
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/sl.js
|
|
8196
8192
|
var error34 = () => {
|
|
8197
8193
|
const Sizable = {
|
|
8198
8194
|
string: { unit: "znakov", verb: "imeti" },
|
|
@@ -8309,7 +8305,7 @@ function sl_default() {
|
|
|
8309
8305
|
localeError: error34()
|
|
8310
8306
|
};
|
|
8311
8307
|
}
|
|
8312
|
-
// node_modules/zod/v4/locales/sv.js
|
|
8308
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/sv.js
|
|
8313
8309
|
var error35 = () => {
|
|
8314
8310
|
const Sizable = {
|
|
8315
8311
|
string: { unit: "tecken", verb: "att ha" },
|
|
@@ -8427,7 +8423,7 @@ function sv_default() {
|
|
|
8427
8423
|
localeError: error35()
|
|
8428
8424
|
};
|
|
8429
8425
|
}
|
|
8430
|
-
// node_modules/zod/v4/locales/ta.js
|
|
8426
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ta.js
|
|
8431
8427
|
var error36 = () => {
|
|
8432
8428
|
const Sizable = {
|
|
8433
8429
|
string: { unit: "\u0B8E\u0BB4\u0BC1\u0BA4\u0BCD\u0BA4\u0BC1\u0B95\u0BCD\u0B95\u0BB3\u0BCD", verb: "\u0B95\u0BCA\u0BA3\u0BCD\u0B9F\u0BBF\u0BB0\u0BC1\u0B95\u0BCD\u0B95 \u0BB5\u0BC7\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD" },
|
|
@@ -8544,7 +8540,7 @@ function ta_default() {
|
|
|
8544
8540
|
localeError: error36()
|
|
8545
8541
|
};
|
|
8546
8542
|
}
|
|
8547
|
-
// node_modules/zod/v4/locales/th.js
|
|
8543
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/th.js
|
|
8548
8544
|
var error37 = () => {
|
|
8549
8545
|
const Sizable = {
|
|
8550
8546
|
string: { unit: "\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", verb: "\u0E04\u0E27\u0E23\u0E21\u0E35" },
|
|
@@ -8661,7 +8657,7 @@ function th_default() {
|
|
|
8661
8657
|
localeError: error37()
|
|
8662
8658
|
};
|
|
8663
8659
|
}
|
|
8664
|
-
// node_modules/zod/v4/locales/tr.js
|
|
8660
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/tr.js
|
|
8665
8661
|
var parsedType6 = (data) => {
|
|
8666
8662
|
const t = typeof data;
|
|
8667
8663
|
switch (t) {
|
|
@@ -8776,7 +8772,7 @@ function tr_default() {
|
|
|
8776
8772
|
localeError: error38()
|
|
8777
8773
|
};
|
|
8778
8774
|
}
|
|
8779
|
-
// node_modules/zod/v4/locales/uk.js
|
|
8775
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/uk.js
|
|
8780
8776
|
var error39 = () => {
|
|
8781
8777
|
const Sizable = {
|
|
8782
8778
|
string: { unit: "\u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432", verb: "\u043C\u0430\u0442\u0438\u043C\u0435" },
|
|
@@ -8893,11 +8889,11 @@ function uk_default() {
|
|
|
8893
8889
|
};
|
|
8894
8890
|
}
|
|
8895
8891
|
|
|
8896
|
-
// node_modules/zod/v4/locales/ua.js
|
|
8892
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ua.js
|
|
8897
8893
|
function ua_default() {
|
|
8898
8894
|
return uk_default();
|
|
8899
8895
|
}
|
|
8900
|
-
// node_modules/zod/v4/locales/ur.js
|
|
8896
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/ur.js
|
|
8901
8897
|
var error40 = () => {
|
|
8902
8898
|
const Sizable = {
|
|
8903
8899
|
string: { unit: "\u062D\u0631\u0648\u0641", verb: "\u06C1\u0648\u0646\u0627" },
|
|
@@ -9014,7 +9010,7 @@ function ur_default() {
|
|
|
9014
9010
|
localeError: error40()
|
|
9015
9011
|
};
|
|
9016
9012
|
}
|
|
9017
|
-
// node_modules/zod/v4/locales/vi.js
|
|
9013
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/vi.js
|
|
9018
9014
|
var error41 = () => {
|
|
9019
9015
|
const Sizable = {
|
|
9020
9016
|
string: { unit: "k\xFD t\u1EF1", verb: "c\xF3" },
|
|
@@ -9130,7 +9126,7 @@ function vi_default() {
|
|
|
9130
9126
|
localeError: error41()
|
|
9131
9127
|
};
|
|
9132
9128
|
}
|
|
9133
|
-
// node_modules/zod/v4/locales/zh-CN.js
|
|
9129
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/zh-CN.js
|
|
9134
9130
|
var error42 = () => {
|
|
9135
9131
|
const Sizable = {
|
|
9136
9132
|
string: { unit: "\u5B57\u7B26", verb: "\u5305\u542B" },
|
|
@@ -9246,7 +9242,7 @@ function zh_CN_default() {
|
|
|
9246
9242
|
localeError: error42()
|
|
9247
9243
|
};
|
|
9248
9244
|
}
|
|
9249
|
-
// node_modules/zod/v4/locales/zh-TW.js
|
|
9245
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/zh-TW.js
|
|
9250
9246
|
var error43 = () => {
|
|
9251
9247
|
const Sizable = {
|
|
9252
9248
|
string: { unit: "\u5B57\u5143", verb: "\u64C1\u6709" },
|
|
@@ -9363,7 +9359,7 @@ function zh_TW_default() {
|
|
|
9363
9359
|
localeError: error43()
|
|
9364
9360
|
};
|
|
9365
9361
|
}
|
|
9366
|
-
// node_modules/zod/v4/locales/yo.js
|
|
9362
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/locales/yo.js
|
|
9367
9363
|
var error44 = () => {
|
|
9368
9364
|
const Sizable = {
|
|
9369
9365
|
string: { unit: "\xE0mi", verb: "n\xED" },
|
|
@@ -9478,7 +9474,7 @@ function yo_default() {
|
|
|
9478
9474
|
localeError: error44()
|
|
9479
9475
|
};
|
|
9480
9476
|
}
|
|
9481
|
-
// node_modules/zod/v4/core/registries.js
|
|
9477
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/registries.js
|
|
9482
9478
|
var $output = Symbol("ZodOutput");
|
|
9483
9479
|
var $input = Symbol("ZodInput");
|
|
9484
9480
|
|
|
@@ -9529,7 +9525,7 @@ function registry() {
|
|
|
9529
9525
|
return new $ZodRegistry;
|
|
9530
9526
|
}
|
|
9531
9527
|
var globalRegistry = /* @__PURE__ */ registry();
|
|
9532
|
-
// node_modules/zod/v4/core/api.js
|
|
9528
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/api.js
|
|
9533
9529
|
function _string(Class2, params) {
|
|
9534
9530
|
return new Class2({
|
|
9535
9531
|
type: "string",
|
|
@@ -10407,7 +10403,7 @@ function _stringFormat(Class2, format, fnOrRegex, _params = {}) {
|
|
|
10407
10403
|
const inst = new Class2(def);
|
|
10408
10404
|
return inst;
|
|
10409
10405
|
}
|
|
10410
|
-
// node_modules/zod/v4/core/to-json-schema.js
|
|
10406
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/to-json-schema.js
|
|
10411
10407
|
class JSONSchemaGenerator {
|
|
10412
10408
|
constructor(params) {
|
|
10413
10409
|
this.counter = 0;
|
|
@@ -11211,9 +11207,9 @@ function isTransforming(_schema, _ctx) {
|
|
|
11211
11207
|
}
|
|
11212
11208
|
throw new Error(`Unknown schema type: ${def.type}`);
|
|
11213
11209
|
}
|
|
11214
|
-
// node_modules/zod/v4/core/json-schema.js
|
|
11210
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/core/json-schema.js
|
|
11215
11211
|
var exports_json_schema = {};
|
|
11216
|
-
// node_modules/zod/v4/classic/iso.js
|
|
11212
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/iso.js
|
|
11217
11213
|
var exports_iso = {};
|
|
11218
11214
|
__export(exports_iso, {
|
|
11219
11215
|
time: () => time2,
|
|
@@ -11254,7 +11250,7 @@ function duration2(params) {
|
|
|
11254
11250
|
return _isoDuration(ZodISODuration, params);
|
|
11255
11251
|
}
|
|
11256
11252
|
|
|
11257
|
-
// node_modules/zod/v4/classic/errors.js
|
|
11253
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/errors.js
|
|
11258
11254
|
var initializer2 = (inst, issues) => {
|
|
11259
11255
|
$ZodError.init(inst, issues);
|
|
11260
11256
|
inst.name = "ZodError";
|
|
@@ -11289,7 +11285,7 @@ var ZodRealError = $constructor("ZodError", initializer2, {
|
|
|
11289
11285
|
Parent: Error
|
|
11290
11286
|
});
|
|
11291
11287
|
|
|
11292
|
-
// node_modules/zod/v4/classic/parse.js
|
|
11288
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/parse.js
|
|
11293
11289
|
var parse3 = /* @__PURE__ */ _parse(ZodRealError);
|
|
11294
11290
|
var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
11295
11291
|
var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
@@ -11303,7 +11299,7 @@ var safeDecode2 = /* @__PURE__ */ _safeDecode(ZodRealError);
|
|
|
11303
11299
|
var safeEncodeAsync2 = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
|
|
11304
11300
|
var safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
|
|
11305
11301
|
|
|
11306
|
-
// node_modules/zod/v4/classic/schemas.js
|
|
11302
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/schemas.js
|
|
11307
11303
|
var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
|
|
11308
11304
|
$ZodType.init(inst, def);
|
|
11309
11305
|
inst.def = def;
|
|
@@ -12278,7 +12274,7 @@ function json(params) {
|
|
|
12278
12274
|
function preprocess(fn, schema) {
|
|
12279
12275
|
return pipe(transform(fn), schema);
|
|
12280
12276
|
}
|
|
12281
|
-
// node_modules/zod/v4/classic/compat.js
|
|
12277
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/compat.js
|
|
12282
12278
|
var ZodIssueCode = {
|
|
12283
12279
|
invalid_type: "invalid_type",
|
|
12284
12280
|
too_big: "too_big",
|
|
@@ -12302,7 +12298,7 @@ function getErrorMap() {
|
|
|
12302
12298
|
}
|
|
12303
12299
|
var ZodFirstPartyTypeKind;
|
|
12304
12300
|
(function(ZodFirstPartyTypeKind2) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
12305
|
-
// node_modules/zod/v4/classic/coerce.js
|
|
12301
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/coerce.js
|
|
12306
12302
|
var exports_coerce = {};
|
|
12307
12303
|
__export(exports_coerce, {
|
|
12308
12304
|
string: () => string3,
|
|
@@ -12327,14 +12323,193 @@ function date4(params) {
|
|
|
12327
12323
|
return _coercedDate(ZodDate, params);
|
|
12328
12324
|
}
|
|
12329
12325
|
|
|
12330
|
-
// node_modules/zod/v4/classic/external.js
|
|
12326
|
+
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
|
|
12331
12327
|
config(en_default());
|
|
12332
12328
|
// node_modules/@opencode-ai/plugin/dist/tool.js
|
|
12333
12329
|
function tool(input) {
|
|
12334
12330
|
return input;
|
|
12335
12331
|
}
|
|
12336
12332
|
tool.schema = exports_external;
|
|
12333
|
+
// src/tools/inspect-http.ts
|
|
12334
|
+
var z = tool.schema;
|
|
12335
|
+
var ALLOWED_EXACT_HOSTS = new Set(["api.app.helloleo.dev"]);
|
|
12336
|
+
var ALLOWED_HOST_SUFFIXES = [
|
|
12337
|
+
".augustin-d60.workers.dev",
|
|
12338
|
+
".live.helloleo.dev"
|
|
12339
|
+
];
|
|
12340
|
+
var DEFAULT_TIMEOUT_MS = 15000;
|
|
12341
|
+
var MAX_TIMEOUT_MS = 30000;
|
|
12342
|
+
var MAX_RESPONSE_BYTES = 1e6;
|
|
12343
|
+
var METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
12344
|
+
var METHODS_AUTO_JSON = new Set(["POST", "PUT", "PATCH"]);
|
|
12345
|
+
var argsShape = {
|
|
12346
|
+
url: z.string().describe("Fully-qualified URL to request. Must be on the HelloLeo whitelist " + "(api.app.helloleo.dev, *.augustin-d60.workers.dev, *.live.helloleo.dev)."),
|
|
12347
|
+
method: z.enum(METHODS).default("GET").describe(`HTTP method (${METHODS.join(", ")}). Defaults to GET.`),
|
|
12348
|
+
body: z.string().optional().describe("Request body as a string. Not valid for GET. Sent with " + "Content-Type: application/json on POST/PUT/PATCH unless a " + "different Content-Type is supplied via headers."),
|
|
12349
|
+
headers: z.record(z.string(), z.string()).default({}).describe("Optional additional request headers as key/value pairs (e.g. Authorization)."),
|
|
12350
|
+
timeout: z.number().max(MAX_TIMEOUT_MS).default(DEFAULT_TIMEOUT_MS).describe(`Optional timeout in milliseconds (max ${MAX_TIMEOUT_MS}, default ${DEFAULT_TIMEOUT_MS}).`)
|
|
12351
|
+
};
|
|
12352
|
+
var argsSchema = z.object(argsShape);
|
|
12353
|
+
var inspectHttp = tool({
|
|
12354
|
+
description: "Send an HTTP request to a HelloLeo endpoint and return the status code, " + "response headers, and response body. Use this to inspect the live behaviour " + "of HelloLeo workers, the production API, or preview deployments so you can " + "self-debug instead of operating blind. " + "Only URLs on the HelloLeo whitelist are allowed: " + "api.app.helloleo.dev, *.augustin-d60.workers.dev, *.live.helloleo.dev. " + "Supports GET, POST, PUT, PATCH and DELETE (with an optional JSON body).",
|
|
12355
|
+
args: argsShape,
|
|
12356
|
+
async execute(rawArgs, context) {
|
|
12357
|
+
const args = argsSchema.parse(rawArgs);
|
|
12358
|
+
const url2 = parseTargetUrl(args.url);
|
|
12359
|
+
if (args.method === "GET" && args.body !== undefined) {
|
|
12360
|
+
throw new Error("GET requests cannot have a body");
|
|
12361
|
+
}
|
|
12362
|
+
await context.ask({
|
|
12363
|
+
permission: "inspect_http",
|
|
12364
|
+
patterns: [url2.toString()],
|
|
12365
|
+
always: [`${url2.protocol}//${url2.hostname}/*`],
|
|
12366
|
+
metadata: {
|
|
12367
|
+
url: url2.toString(),
|
|
12368
|
+
method: args.method,
|
|
12369
|
+
hasBody: args.body !== undefined
|
|
12370
|
+
}
|
|
12371
|
+
});
|
|
12372
|
+
const timeoutMs = Math.max(1, Math.min(args.timeout, MAX_TIMEOUT_MS));
|
|
12373
|
+
const requestHeaders = {
|
|
12374
|
+
Accept: "application/json, text/plain, */*",
|
|
12375
|
+
"User-Agent": "helloleo-plugins-inspect-http/0.1",
|
|
12376
|
+
Origin: "https://app.helloleo.dev",
|
|
12377
|
+
...args.headers
|
|
12378
|
+
};
|
|
12379
|
+
if (METHODS_AUTO_JSON.has(args.method) && args.body !== undefined && !hasHeader(requestHeaders, "content-type")) {
|
|
12380
|
+
requestHeaders["Content-Type"] = "application/json";
|
|
12381
|
+
}
|
|
12382
|
+
const signal = AbortSignal.any([
|
|
12383
|
+
context.abort,
|
|
12384
|
+
AbortSignal.timeout(timeoutMs)
|
|
12385
|
+
]);
|
|
12386
|
+
let response;
|
|
12387
|
+
try {
|
|
12388
|
+
response = await fetch(url2, {
|
|
12389
|
+
method: args.method,
|
|
12390
|
+
headers: requestHeaders,
|
|
12391
|
+
body: args.method === "GET" ? undefined : args.body,
|
|
12392
|
+
signal,
|
|
12393
|
+
redirect: "follow"
|
|
12394
|
+
});
|
|
12395
|
+
} catch (err) {
|
|
12396
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
12397
|
+
throw new Error(`Request timed out after ${timeoutMs}ms`);
|
|
12398
|
+
}
|
|
12399
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
12400
|
+
throw new Error("Request aborted");
|
|
12401
|
+
}
|
|
12402
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12403
|
+
throw new Error(`Request failed: ${message}`);
|
|
12404
|
+
}
|
|
12405
|
+
const { text, truncated } = await readBody(response);
|
|
12406
|
+
const contentType = response.headers.get("content-type");
|
|
12407
|
+
const formattedBody = formatBody(text, contentType);
|
|
12408
|
+
const redirected = response.url && response.url !== url2.toString();
|
|
12409
|
+
const lines = [`${args.method} ${url2.toString()}`];
|
|
12410
|
+
if (redirected) {
|
|
12411
|
+
lines.push(`Final URL: ${response.url}`);
|
|
12412
|
+
}
|
|
12413
|
+
lines.push(`Status: ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`, "", "Response headers:", formatHeaders(response.headers) || "(none)", "", "Response body:", formattedBody.length > 0 ? formattedBody : "(empty)");
|
|
12414
|
+
if (truncated) {
|
|
12415
|
+
lines.push("", `(body truncated at ${MAX_RESPONSE_BYTES} bytes)`);
|
|
12416
|
+
}
|
|
12417
|
+
return lines.join(`
|
|
12418
|
+
`);
|
|
12419
|
+
}
|
|
12420
|
+
});
|
|
12421
|
+
function parseTargetUrl(raw) {
|
|
12422
|
+
let url2;
|
|
12423
|
+
try {
|
|
12424
|
+
url2 = new URL(raw);
|
|
12425
|
+
} catch {
|
|
12426
|
+
throw new Error(`Invalid URL: ${raw}`);
|
|
12427
|
+
}
|
|
12428
|
+
if (url2.protocol !== "https:" && url2.protocol !== "http:") {
|
|
12429
|
+
throw new Error(`URL must use http or https scheme (got "${url2.protocol}")`);
|
|
12430
|
+
}
|
|
12431
|
+
if (url2.username || url2.password) {
|
|
12432
|
+
throw new Error("URL must not contain embedded credentials");
|
|
12433
|
+
}
|
|
12434
|
+
if (!isAllowedHost(url2.hostname)) {
|
|
12435
|
+
throw new Error(`Host "${url2.hostname}" is not on the HelloLeo whitelist. Allowed: ${allowedHostsHuman()}`);
|
|
12436
|
+
}
|
|
12437
|
+
return url2;
|
|
12438
|
+
}
|
|
12439
|
+
function allowedHostsHuman() {
|
|
12440
|
+
return [
|
|
12441
|
+
...ALLOWED_EXACT_HOSTS,
|
|
12442
|
+
...ALLOWED_HOST_SUFFIXES.map((s) => `*${s}`)
|
|
12443
|
+
].join(", ");
|
|
12444
|
+
}
|
|
12445
|
+
function isAllowedHost(hostname3) {
|
|
12446
|
+
const host = hostname3.toLowerCase().replace(/\.$/, "");
|
|
12447
|
+
if (ALLOWED_EXACT_HOSTS.has(host))
|
|
12448
|
+
return true;
|
|
12449
|
+
for (const suffix of ALLOWED_HOST_SUFFIXES) {
|
|
12450
|
+
if (host.endsWith(suffix) && host.length > suffix.length)
|
|
12451
|
+
return true;
|
|
12452
|
+
}
|
|
12453
|
+
return false;
|
|
12454
|
+
}
|
|
12455
|
+
function hasHeader(headers, name) {
|
|
12456
|
+
const target = name.toLowerCase();
|
|
12457
|
+
for (const key of Object.keys(headers)) {
|
|
12458
|
+
if (key.toLowerCase() === target)
|
|
12459
|
+
return true;
|
|
12460
|
+
}
|
|
12461
|
+
return false;
|
|
12462
|
+
}
|
|
12463
|
+
function formatHeaders(headers) {
|
|
12464
|
+
const entries = [];
|
|
12465
|
+
headers.forEach((value, key) => {
|
|
12466
|
+
entries.push(`${key}: ${value}`);
|
|
12467
|
+
});
|
|
12468
|
+
return entries.sort().join(`
|
|
12469
|
+
`);
|
|
12470
|
+
}
|
|
12471
|
+
function formatBody(raw, contentType) {
|
|
12472
|
+
const mime = contentType?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
12473
|
+
if (mime.includes("application/json") || mime.endsWith("+json")) {
|
|
12474
|
+
try {
|
|
12475
|
+
return JSON.stringify(JSON.parse(raw), null, 2);
|
|
12476
|
+
} catch {}
|
|
12477
|
+
}
|
|
12478
|
+
return raw;
|
|
12479
|
+
}
|
|
12480
|
+
async function readBody(response) {
|
|
12481
|
+
if (!response.body)
|
|
12482
|
+
return { text: "", truncated: false };
|
|
12483
|
+
const reader = response.body.getReader();
|
|
12484
|
+
const decoder = new TextDecoder;
|
|
12485
|
+
let text = "";
|
|
12486
|
+
let total = 0;
|
|
12487
|
+
let truncated = false;
|
|
12488
|
+
while (true) {
|
|
12489
|
+
const { done, value } = await reader.read();
|
|
12490
|
+
if (done)
|
|
12491
|
+
break;
|
|
12492
|
+
if (!value)
|
|
12493
|
+
continue;
|
|
12494
|
+
total += value.byteLength;
|
|
12495
|
+
if (total > MAX_RESPONSE_BYTES) {
|
|
12496
|
+
truncated = true;
|
|
12497
|
+
await reader.cancel();
|
|
12498
|
+
break;
|
|
12499
|
+
}
|
|
12500
|
+
text += decoder.decode(value, { stream: true });
|
|
12501
|
+
}
|
|
12502
|
+
text += decoder.decode();
|
|
12503
|
+
return { text, truncated };
|
|
12504
|
+
}
|
|
12505
|
+
var InspectHttpPlugin = async () => {
|
|
12506
|
+
return {
|
|
12507
|
+
tool: { inspect_http: inspectHttp }
|
|
12508
|
+
};
|
|
12509
|
+
};
|
|
12337
12510
|
// src/tools/remove.ts
|
|
12511
|
+
import { unlink } from "fs/promises";
|
|
12512
|
+
import path from "path";
|
|
12338
12513
|
var remove = tool({
|
|
12339
12514
|
description: "Remove a file from the project. The file path must be relative to the project root. " + "This tool will ask for permission before deleting. " + "Cannot delete files outside the project boundary.",
|
|
12340
12515
|
args: {
|
|
@@ -12623,5 +12798,6 @@ var ScaffoldPlugin = async () => {
|
|
|
12623
12798
|
};
|
|
12624
12799
|
export {
|
|
12625
12800
|
ScaffoldPlugin,
|
|
12626
|
-
RemovePlugin
|
|
12801
|
+
RemovePlugin,
|
|
12802
|
+
InspectHttpPlugin
|
|
12627
12803
|
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
import { tool } from "@opencode-ai/plugin";
|
|
3
|
+
|
|
4
|
+
const z = tool.schema;
|
|
5
|
+
|
|
6
|
+
const ALLOWED_EXACT_HOSTS = new Set(["api.app.helloleo.dev"]);
|
|
7
|
+
const ALLOWED_HOST_SUFFIXES = [
|
|
8
|
+
".augustin-d60.workers.dev",
|
|
9
|
+
".live.helloleo.dev",
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
const DEFAULT_TIMEOUT_MS = 15_000;
|
|
13
|
+
const MAX_TIMEOUT_MS = 30_000;
|
|
14
|
+
const MAX_RESPONSE_BYTES = 1_000_000;
|
|
15
|
+
|
|
16
|
+
const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"] as const;
|
|
17
|
+
const METHODS_AUTO_JSON = new Set(["POST", "PUT", "PATCH"]);
|
|
18
|
+
|
|
19
|
+
// tool() is an identity function; parse args explicitly so .default() applies.
|
|
20
|
+
const argsShape = {
|
|
21
|
+
url: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe(
|
|
24
|
+
"Fully-qualified URL to request. Must be on the HelloLeo whitelist " +
|
|
25
|
+
"(api.app.helloleo.dev, *.augustin-d60.workers.dev, *.live.helloleo.dev).",
|
|
26
|
+
),
|
|
27
|
+
method: z
|
|
28
|
+
.enum(METHODS)
|
|
29
|
+
.default("GET")
|
|
30
|
+
.describe(`HTTP method (${METHODS.join(", ")}). Defaults to GET.`),
|
|
31
|
+
body: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe(
|
|
35
|
+
"Request body as a string. Not valid for GET. Sent with " +
|
|
36
|
+
"Content-Type: application/json on POST/PUT/PATCH unless a " +
|
|
37
|
+
"different Content-Type is supplied via headers.",
|
|
38
|
+
),
|
|
39
|
+
headers: z
|
|
40
|
+
.record(z.string(), z.string())
|
|
41
|
+
.default({})
|
|
42
|
+
.describe(
|
|
43
|
+
"Optional additional request headers as key/value pairs (e.g. Authorization).",
|
|
44
|
+
),
|
|
45
|
+
timeout: z
|
|
46
|
+
.number()
|
|
47
|
+
.max(MAX_TIMEOUT_MS)
|
|
48
|
+
.default(DEFAULT_TIMEOUT_MS)
|
|
49
|
+
.describe(
|
|
50
|
+
`Optional timeout in milliseconds (max ${MAX_TIMEOUT_MS}, default ${DEFAULT_TIMEOUT_MS}).`,
|
|
51
|
+
),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const argsSchema = z.object(argsShape);
|
|
55
|
+
|
|
56
|
+
export const inspectHttp = tool({
|
|
57
|
+
description:
|
|
58
|
+
"Send an HTTP request to a HelloLeo endpoint and return the status code, " +
|
|
59
|
+
"response headers, and response body. Use this to inspect the live behaviour " +
|
|
60
|
+
"of HelloLeo workers, the production API, or preview deployments so you can " +
|
|
61
|
+
"self-debug instead of operating blind. " +
|
|
62
|
+
"Only URLs on the HelloLeo whitelist are allowed: " +
|
|
63
|
+
"api.app.helloleo.dev, *.augustin-d60.workers.dev, *.live.helloleo.dev. " +
|
|
64
|
+
"Supports GET, POST, PUT, PATCH and DELETE (with an optional JSON body).",
|
|
65
|
+
args: argsShape,
|
|
66
|
+
async execute(rawArgs, context) {
|
|
67
|
+
const args = argsSchema.parse(rawArgs);
|
|
68
|
+
const url = parseTargetUrl(args.url);
|
|
69
|
+
|
|
70
|
+
if (args.method === "GET" && args.body !== undefined) {
|
|
71
|
+
throw new Error("GET requests cannot have a body");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await context.ask({
|
|
75
|
+
permission: "inspect_http",
|
|
76
|
+
patterns: [url.toString()],
|
|
77
|
+
always: [`${url.protocol}//${url.hostname}/*`],
|
|
78
|
+
metadata: {
|
|
79
|
+
url: url.toString(),
|
|
80
|
+
method: args.method,
|
|
81
|
+
hasBody: args.body !== undefined,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const timeoutMs = Math.max(1, Math.min(args.timeout, MAX_TIMEOUT_MS));
|
|
86
|
+
|
|
87
|
+
const requestHeaders: Record<string, string> = {
|
|
88
|
+
Accept: "application/json, text/plain, */*",
|
|
89
|
+
"User-Agent": "helloleo-plugins-inspect-http/0.1",
|
|
90
|
+
Origin: "https://app.helloleo.dev",
|
|
91
|
+
...args.headers,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
METHODS_AUTO_JSON.has(args.method) &&
|
|
96
|
+
args.body !== undefined &&
|
|
97
|
+
!hasHeader(requestHeaders, "content-type")
|
|
98
|
+
) {
|
|
99
|
+
requestHeaders["Content-Type"] = "application/json";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const signal = AbortSignal.any([
|
|
103
|
+
context.abort,
|
|
104
|
+
AbortSignal.timeout(timeoutMs),
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
let response: Response;
|
|
108
|
+
try {
|
|
109
|
+
response = await fetch(url, {
|
|
110
|
+
method: args.method,
|
|
111
|
+
headers: requestHeaders,
|
|
112
|
+
body: args.method === "GET" ? undefined : args.body,
|
|
113
|
+
signal,
|
|
114
|
+
redirect: "follow",
|
|
115
|
+
});
|
|
116
|
+
} catch (err) {
|
|
117
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
118
|
+
throw new Error(`Request timed out after ${timeoutMs}ms`);
|
|
119
|
+
}
|
|
120
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
121
|
+
throw new Error("Request aborted");
|
|
122
|
+
}
|
|
123
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
124
|
+
throw new Error(`Request failed: ${message}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const { text, truncated } = await readBody(response);
|
|
128
|
+
const contentType = response.headers.get("content-type");
|
|
129
|
+
const formattedBody = formatBody(text, contentType);
|
|
130
|
+
|
|
131
|
+
const redirected = response.url && response.url !== url.toString();
|
|
132
|
+
|
|
133
|
+
const lines: string[] = [`${args.method} ${url.toString()}`];
|
|
134
|
+
if (redirected) {
|
|
135
|
+
lines.push(`Final URL: ${response.url}`);
|
|
136
|
+
}
|
|
137
|
+
lines.push(
|
|
138
|
+
`Status: ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`,
|
|
139
|
+
"",
|
|
140
|
+
"Response headers:",
|
|
141
|
+
formatHeaders(response.headers) || "(none)",
|
|
142
|
+
"",
|
|
143
|
+
"Response body:",
|
|
144
|
+
formattedBody.length > 0 ? formattedBody : "(empty)",
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (truncated) {
|
|
148
|
+
lines.push("", `(body truncated at ${MAX_RESPONSE_BYTES} bytes)`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return lines.join("\n");
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
function parseTargetUrl(raw: string): URL {
|
|
156
|
+
let url: URL;
|
|
157
|
+
try {
|
|
158
|
+
url = new URL(raw);
|
|
159
|
+
} catch {
|
|
160
|
+
throw new Error(`Invalid URL: ${raw}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`URL must use http or https scheme (got "${url.protocol}")`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (url.username || url.password) {
|
|
170
|
+
throw new Error("URL must not contain embedded credentials");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!isAllowedHost(url.hostname)) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`Host "${url.hostname}" is not on the HelloLeo whitelist. Allowed: ${allowedHostsHuman()}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return url;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function allowedHostsHuman(): string {
|
|
183
|
+
return [
|
|
184
|
+
...ALLOWED_EXACT_HOSTS,
|
|
185
|
+
...ALLOWED_HOST_SUFFIXES.map((s) => `*${s}`),
|
|
186
|
+
].join(", ");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function isAllowedHost(hostname: string): boolean {
|
|
190
|
+
const host = hostname.toLowerCase().replace(/\.$/, "");
|
|
191
|
+
if (ALLOWED_EXACT_HOSTS.has(host)) return true;
|
|
192
|
+
for (const suffix of ALLOWED_HOST_SUFFIXES) {
|
|
193
|
+
if (host.endsWith(suffix) && host.length > suffix.length) return true;
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function hasHeader(headers: Record<string, string>, name: string): boolean {
|
|
199
|
+
const target = name.toLowerCase();
|
|
200
|
+
for (const key of Object.keys(headers)) {
|
|
201
|
+
if (key.toLowerCase() === target) return true;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function formatHeaders(headers: Headers): string {
|
|
207
|
+
const entries: string[] = [];
|
|
208
|
+
headers.forEach((value, key) => {
|
|
209
|
+
entries.push(`${key}: ${value}`);
|
|
210
|
+
});
|
|
211
|
+
return entries.sort().join("\n");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function formatBody(raw: string, contentType: string | null): string {
|
|
215
|
+
const mime = contentType?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
216
|
+
if (mime.includes("application/json") || mime.endsWith("+json")) {
|
|
217
|
+
try {
|
|
218
|
+
return JSON.stringify(JSON.parse(raw), null, 2);
|
|
219
|
+
} catch {}
|
|
220
|
+
}
|
|
221
|
+
return raw;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function readBody(response: Response): Promise<{
|
|
225
|
+
text: string;
|
|
226
|
+
truncated: boolean;
|
|
227
|
+
}> {
|
|
228
|
+
if (!response.body) return { text: "", truncated: false };
|
|
229
|
+
|
|
230
|
+
const reader = response.body.getReader();
|
|
231
|
+
const decoder = new TextDecoder();
|
|
232
|
+
let text = "";
|
|
233
|
+
let total = 0;
|
|
234
|
+
let truncated = false;
|
|
235
|
+
|
|
236
|
+
while (true) {
|
|
237
|
+
const { done, value } = await reader.read();
|
|
238
|
+
if (done) break;
|
|
239
|
+
if (!value) continue;
|
|
240
|
+
|
|
241
|
+
total += value.byteLength;
|
|
242
|
+
if (total > MAX_RESPONSE_BYTES) {
|
|
243
|
+
truncated = true;
|
|
244
|
+
await reader.cancel();
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
text += decoder.decode(value, { stream: true });
|
|
248
|
+
}
|
|
249
|
+
text += decoder.decode();
|
|
250
|
+
|
|
251
|
+
return { text, truncated };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export const InspectHttpPlugin: Plugin = async () => {
|
|
255
|
+
return {
|
|
256
|
+
tool: { inspect_http: inspectHttp },
|
|
257
|
+
};
|
|
258
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type Success<T> = {
|
|
2
|
+
data: T;
|
|
3
|
+
error: null;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type Failure<E> = {
|
|
7
|
+
data: null;
|
|
8
|
+
error: E;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type Result<T, E = Error> = Success<T> | Failure<E>;
|
|
12
|
+
|
|
13
|
+
export async function tryCatch<T, E = Error>(
|
|
14
|
+
promise: Promise<T>,
|
|
15
|
+
): Promise<Result<T, E>> {
|
|
16
|
+
try {
|
|
17
|
+
const data = await promise;
|
|
18
|
+
return { data, error: null };
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return { data: null, error: error as E };
|
|
21
|
+
}
|
|
22
|
+
}
|