@sjawhar/opencode-legion-envoy 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/src/server.js +807 -166
- package/package.json +4 -3
- package/skills/dispatch/SKILL.md +196 -45
- package/src/server.ts +73 -26
- package/dist/bin/dispatch-mcp-shim.js +0 -4889
- package/src/config/index.ts +0 -69
- package/src/config/schema.ts +0 -21
- package/src/dispatch-mcp.ts +0 -113
package/dist/src/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/server.ts
|
|
3
|
-
import { existsSync
|
|
4
|
-
import
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import path3 from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
|
|
7
7
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/core.js
|
|
@@ -86,6 +86,9 @@ function getEnumValues(entries) {
|
|
|
86
86
|
const values = Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
|
|
87
87
|
return values;
|
|
88
88
|
}
|
|
89
|
+
function joinValues(array, separator = "|") {
|
|
90
|
+
return array.map((val) => stringifyPrimitive(val)).join(separator);
|
|
91
|
+
}
|
|
89
92
|
function jsonStringifyReplacer(_, value) {
|
|
90
93
|
if (typeof value === "bigint")
|
|
91
94
|
return value.toString();
|
|
@@ -237,6 +240,13 @@ function normalizeParams(_params) {
|
|
|
237
240
|
return { ...params, error: () => params.error };
|
|
238
241
|
return params;
|
|
239
242
|
}
|
|
243
|
+
function stringifyPrimitive(value) {
|
|
244
|
+
if (typeof value === "bigint")
|
|
245
|
+
return value.toString() + "n";
|
|
246
|
+
if (typeof value === "string")
|
|
247
|
+
return `"${value}"`;
|
|
248
|
+
return `${value}`;
|
|
249
|
+
}
|
|
240
250
|
function optionalKeys(shape) {
|
|
241
251
|
return Object.keys(shape).filter((k) => {
|
|
242
252
|
return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional";
|
|
@@ -459,6 +469,27 @@ function getLengthableOrigin(input) {
|
|
|
459
469
|
return "string";
|
|
460
470
|
return "unknown";
|
|
461
471
|
}
|
|
472
|
+
function parsedType(data) {
|
|
473
|
+
const t = typeof data;
|
|
474
|
+
switch (t) {
|
|
475
|
+
case "number": {
|
|
476
|
+
return Number.isNaN(data) ? "nan" : "number";
|
|
477
|
+
}
|
|
478
|
+
case "object": {
|
|
479
|
+
if (data === null) {
|
|
480
|
+
return "null";
|
|
481
|
+
}
|
|
482
|
+
if (Array.isArray(data)) {
|
|
483
|
+
return "array";
|
|
484
|
+
}
|
|
485
|
+
const obj = data;
|
|
486
|
+
if (obj && Object.getPrototypeOf(obj) !== Object.prototype && "constructor" in obj && obj.constructor) {
|
|
487
|
+
return obj.constructor.name;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return t;
|
|
492
|
+
}
|
|
462
493
|
function issue(...args) {
|
|
463
494
|
const [iss, input, inst] = args;
|
|
464
495
|
if (typeof iss === "string") {
|
|
@@ -2473,6 +2504,112 @@ function handleRefineResult(result, payload, input, inst) {
|
|
|
2473
2504
|
payload.issues.push(issue(_iss));
|
|
2474
2505
|
}
|
|
2475
2506
|
}
|
|
2507
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/locales/en.js
|
|
2508
|
+
var error = () => {
|
|
2509
|
+
const Sizable = {
|
|
2510
|
+
string: { unit: "characters", verb: "to have" },
|
|
2511
|
+
file: { unit: "bytes", verb: "to have" },
|
|
2512
|
+
array: { unit: "items", verb: "to have" },
|
|
2513
|
+
set: { unit: "items", verb: "to have" },
|
|
2514
|
+
map: { unit: "entries", verb: "to have" }
|
|
2515
|
+
};
|
|
2516
|
+
function getSizing(origin) {
|
|
2517
|
+
return Sizable[origin] ?? null;
|
|
2518
|
+
}
|
|
2519
|
+
const FormatDictionary = {
|
|
2520
|
+
regex: "input",
|
|
2521
|
+
email: "email address",
|
|
2522
|
+
url: "URL",
|
|
2523
|
+
emoji: "emoji",
|
|
2524
|
+
uuid: "UUID",
|
|
2525
|
+
uuidv4: "UUIDv4",
|
|
2526
|
+
uuidv6: "UUIDv6",
|
|
2527
|
+
nanoid: "nanoid",
|
|
2528
|
+
guid: "GUID",
|
|
2529
|
+
cuid: "cuid",
|
|
2530
|
+
cuid2: "cuid2",
|
|
2531
|
+
ulid: "ULID",
|
|
2532
|
+
xid: "XID",
|
|
2533
|
+
ksuid: "KSUID",
|
|
2534
|
+
datetime: "ISO datetime",
|
|
2535
|
+
date: "ISO date",
|
|
2536
|
+
time: "ISO time",
|
|
2537
|
+
duration: "ISO duration",
|
|
2538
|
+
ipv4: "IPv4 address",
|
|
2539
|
+
ipv6: "IPv6 address",
|
|
2540
|
+
mac: "MAC address",
|
|
2541
|
+
cidrv4: "IPv4 range",
|
|
2542
|
+
cidrv6: "IPv6 range",
|
|
2543
|
+
base64: "base64-encoded string",
|
|
2544
|
+
base64url: "base64url-encoded string",
|
|
2545
|
+
json_string: "JSON string",
|
|
2546
|
+
e164: "E.164 number",
|
|
2547
|
+
jwt: "JWT",
|
|
2548
|
+
template_literal: "input"
|
|
2549
|
+
};
|
|
2550
|
+
const TypeDictionary = {
|
|
2551
|
+
nan: "NaN"
|
|
2552
|
+
};
|
|
2553
|
+
return (issue) => {
|
|
2554
|
+
switch (issue.code) {
|
|
2555
|
+
case "invalid_type": {
|
|
2556
|
+
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
|
2557
|
+
const receivedType = parsedType(issue.input);
|
|
2558
|
+
const received = TypeDictionary[receivedType] ?? receivedType;
|
|
2559
|
+
return `Invalid input: expected ${expected}, received ${received}`;
|
|
2560
|
+
}
|
|
2561
|
+
case "invalid_value":
|
|
2562
|
+
if (issue.values.length === 1)
|
|
2563
|
+
return `Invalid input: expected ${stringifyPrimitive(issue.values[0])}`;
|
|
2564
|
+
return `Invalid option: expected one of ${joinValues(issue.values, "|")}`;
|
|
2565
|
+
case "too_big": {
|
|
2566
|
+
const adj = issue.inclusive ? "<=" : "<";
|
|
2567
|
+
const sizing = getSizing(issue.origin);
|
|
2568
|
+
if (sizing)
|
|
2569
|
+
return `Too big: expected ${issue.origin ?? "value"} to have ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elements"}`;
|
|
2570
|
+
return `Too big: expected ${issue.origin ?? "value"} to be ${adj}${issue.maximum.toString()}`;
|
|
2571
|
+
}
|
|
2572
|
+
case "too_small": {
|
|
2573
|
+
const adj = issue.inclusive ? ">=" : ">";
|
|
2574
|
+
const sizing = getSizing(issue.origin);
|
|
2575
|
+
if (sizing) {
|
|
2576
|
+
return `Too small: expected ${issue.origin} to have ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
|
2577
|
+
}
|
|
2578
|
+
return `Too small: expected ${issue.origin} to be ${adj}${issue.minimum.toString()}`;
|
|
2579
|
+
}
|
|
2580
|
+
case "invalid_format": {
|
|
2581
|
+
const _issue = issue;
|
|
2582
|
+
if (_issue.format === "starts_with") {
|
|
2583
|
+
return `Invalid string: must start with "${_issue.prefix}"`;
|
|
2584
|
+
}
|
|
2585
|
+
if (_issue.format === "ends_with")
|
|
2586
|
+
return `Invalid string: must end with "${_issue.suffix}"`;
|
|
2587
|
+
if (_issue.format === "includes")
|
|
2588
|
+
return `Invalid string: must include "${_issue.includes}"`;
|
|
2589
|
+
if (_issue.format === "regex")
|
|
2590
|
+
return `Invalid string: must match pattern ${_issue.pattern}`;
|
|
2591
|
+
return `Invalid ${FormatDictionary[_issue.format] ?? issue.format}`;
|
|
2592
|
+
}
|
|
2593
|
+
case "not_multiple_of":
|
|
2594
|
+
return `Invalid number: must be a multiple of ${issue.divisor}`;
|
|
2595
|
+
case "unrecognized_keys":
|
|
2596
|
+
return `Unrecognized key${issue.keys.length > 1 ? "s" : ""}: ${joinValues(issue.keys, ", ")}`;
|
|
2597
|
+
case "invalid_key":
|
|
2598
|
+
return `Invalid key in ${issue.origin}`;
|
|
2599
|
+
case "invalid_union":
|
|
2600
|
+
return "Invalid input";
|
|
2601
|
+
case "invalid_element":
|
|
2602
|
+
return `Invalid value in ${issue.origin}`;
|
|
2603
|
+
default:
|
|
2604
|
+
return `Invalid input`;
|
|
2605
|
+
}
|
|
2606
|
+
};
|
|
2607
|
+
};
|
|
2608
|
+
function en_default() {
|
|
2609
|
+
return {
|
|
2610
|
+
localeError: error()
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2476
2613
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/registries.js
|
|
2477
2614
|
var _a;
|
|
2478
2615
|
var $output = Symbol("ZodOutput");
|
|
@@ -3415,10 +3552,45 @@ var numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
3415
3552
|
var booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
3416
3553
|
json.type = "boolean";
|
|
3417
3554
|
};
|
|
3555
|
+
var bigintProcessor = (_schema, ctx, _json, _params) => {
|
|
3556
|
+
if (ctx.unrepresentable === "throw") {
|
|
3557
|
+
throw new Error("BigInt cannot be represented in JSON Schema");
|
|
3558
|
+
}
|
|
3559
|
+
};
|
|
3560
|
+
var symbolProcessor = (_schema, ctx, _json, _params) => {
|
|
3561
|
+
if (ctx.unrepresentable === "throw") {
|
|
3562
|
+
throw new Error("Symbols cannot be represented in JSON Schema");
|
|
3563
|
+
}
|
|
3564
|
+
};
|
|
3565
|
+
var nullProcessor = (_schema, ctx, json, _params) => {
|
|
3566
|
+
if (ctx.target === "openapi-3.0") {
|
|
3567
|
+
json.type = "string";
|
|
3568
|
+
json.nullable = true;
|
|
3569
|
+
json.enum = [null];
|
|
3570
|
+
} else {
|
|
3571
|
+
json.type = "null";
|
|
3572
|
+
}
|
|
3573
|
+
};
|
|
3574
|
+
var undefinedProcessor = (_schema, ctx, _json, _params) => {
|
|
3575
|
+
if (ctx.unrepresentable === "throw") {
|
|
3576
|
+
throw new Error("Undefined cannot be represented in JSON Schema");
|
|
3577
|
+
}
|
|
3578
|
+
};
|
|
3579
|
+
var voidProcessor = (_schema, ctx, _json, _params) => {
|
|
3580
|
+
if (ctx.unrepresentable === "throw") {
|
|
3581
|
+
throw new Error("Void cannot be represented in JSON Schema");
|
|
3582
|
+
}
|
|
3583
|
+
};
|
|
3418
3584
|
var neverProcessor = (_schema, _ctx, json, _params) => {
|
|
3419
3585
|
json.not = {};
|
|
3420
3586
|
};
|
|
3587
|
+
var anyProcessor = (_schema, _ctx, _json, _params) => {};
|
|
3421
3588
|
var unknownProcessor = (_schema, _ctx, _json, _params) => {};
|
|
3589
|
+
var dateProcessor = (_schema, ctx, _json, _params) => {
|
|
3590
|
+
if (ctx.unrepresentable === "throw") {
|
|
3591
|
+
throw new Error("Date cannot be represented in JSON Schema");
|
|
3592
|
+
}
|
|
3593
|
+
};
|
|
3422
3594
|
var enumProcessor = (schema, _ctx, json, _params) => {
|
|
3423
3595
|
const def = schema._zod.def;
|
|
3424
3596
|
const values = getEnumValues(def.entries);
|
|
@@ -3466,16 +3638,71 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
3466
3638
|
json.enum = vals;
|
|
3467
3639
|
}
|
|
3468
3640
|
};
|
|
3641
|
+
var nanProcessor = (_schema, ctx, _json, _params) => {
|
|
3642
|
+
if (ctx.unrepresentable === "throw") {
|
|
3643
|
+
throw new Error("NaN cannot be represented in JSON Schema");
|
|
3644
|
+
}
|
|
3645
|
+
};
|
|
3646
|
+
var templateLiteralProcessor = (schema, _ctx, json, _params) => {
|
|
3647
|
+
const _json = json;
|
|
3648
|
+
const pattern = schema._zod.pattern;
|
|
3649
|
+
if (!pattern)
|
|
3650
|
+
throw new Error("Pattern not found in template literal");
|
|
3651
|
+
_json.type = "string";
|
|
3652
|
+
_json.pattern = pattern.source;
|
|
3653
|
+
};
|
|
3654
|
+
var fileProcessor = (schema, _ctx, json, _params) => {
|
|
3655
|
+
const _json = json;
|
|
3656
|
+
const file = {
|
|
3657
|
+
type: "string",
|
|
3658
|
+
format: "binary",
|
|
3659
|
+
contentEncoding: "binary"
|
|
3660
|
+
};
|
|
3661
|
+
const { minimum, maximum, mime } = schema._zod.bag;
|
|
3662
|
+
if (minimum !== undefined)
|
|
3663
|
+
file.minLength = minimum;
|
|
3664
|
+
if (maximum !== undefined)
|
|
3665
|
+
file.maxLength = maximum;
|
|
3666
|
+
if (mime) {
|
|
3667
|
+
if (mime.length === 1) {
|
|
3668
|
+
file.contentMediaType = mime[0];
|
|
3669
|
+
Object.assign(_json, file);
|
|
3670
|
+
} else {
|
|
3671
|
+
Object.assign(_json, file);
|
|
3672
|
+
_json.anyOf = mime.map((m) => ({ contentMediaType: m }));
|
|
3673
|
+
}
|
|
3674
|
+
} else {
|
|
3675
|
+
Object.assign(_json, file);
|
|
3676
|
+
}
|
|
3677
|
+
};
|
|
3678
|
+
var successProcessor = (_schema, _ctx, json, _params) => {
|
|
3679
|
+
json.type = "boolean";
|
|
3680
|
+
};
|
|
3469
3681
|
var customProcessor = (_schema, ctx, _json, _params) => {
|
|
3470
3682
|
if (ctx.unrepresentable === "throw") {
|
|
3471
3683
|
throw new Error("Custom types cannot be represented in JSON Schema");
|
|
3472
3684
|
}
|
|
3473
3685
|
};
|
|
3686
|
+
var functionProcessor = (_schema, ctx, _json, _params) => {
|
|
3687
|
+
if (ctx.unrepresentable === "throw") {
|
|
3688
|
+
throw new Error("Function types cannot be represented in JSON Schema");
|
|
3689
|
+
}
|
|
3690
|
+
};
|
|
3474
3691
|
var transformProcessor = (_schema, ctx, _json, _params) => {
|
|
3475
3692
|
if (ctx.unrepresentable === "throw") {
|
|
3476
3693
|
throw new Error("Transforms cannot be represented in JSON Schema");
|
|
3477
3694
|
}
|
|
3478
3695
|
};
|
|
3696
|
+
var mapProcessor = (_schema, ctx, _json, _params) => {
|
|
3697
|
+
if (ctx.unrepresentable === "throw") {
|
|
3698
|
+
throw new Error("Map cannot be represented in JSON Schema");
|
|
3699
|
+
}
|
|
3700
|
+
};
|
|
3701
|
+
var setProcessor = (_schema, ctx, _json, _params) => {
|
|
3702
|
+
if (ctx.unrepresentable === "throw") {
|
|
3703
|
+
throw new Error("Set cannot be represented in JSON Schema");
|
|
3704
|
+
}
|
|
3705
|
+
};
|
|
3479
3706
|
var arrayProcessor = (schema, ctx, _json, params) => {
|
|
3480
3707
|
const json = _json;
|
|
3481
3708
|
const def = schema._zod.def;
|
|
@@ -3553,6 +3780,48 @@ var intersectionProcessor = (schema, ctx, json, params) => {
|
|
|
3553
3780
|
];
|
|
3554
3781
|
json.allOf = allOf;
|
|
3555
3782
|
};
|
|
3783
|
+
var tupleProcessor = (schema, ctx, _json, params) => {
|
|
3784
|
+
const json = _json;
|
|
3785
|
+
const def = schema._zod.def;
|
|
3786
|
+
json.type = "array";
|
|
3787
|
+
const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
|
|
3788
|
+
const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
|
|
3789
|
+
const prefixItems = def.items.map((x, i) => process2(x, ctx, {
|
|
3790
|
+
...params,
|
|
3791
|
+
path: [...params.path, prefixPath, i]
|
|
3792
|
+
}));
|
|
3793
|
+
const rest = def.rest ? process2(def.rest, ctx, {
|
|
3794
|
+
...params,
|
|
3795
|
+
path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
|
|
3796
|
+
}) : null;
|
|
3797
|
+
if (ctx.target === "draft-2020-12") {
|
|
3798
|
+
json.prefixItems = prefixItems;
|
|
3799
|
+
if (rest) {
|
|
3800
|
+
json.items = rest;
|
|
3801
|
+
}
|
|
3802
|
+
} else if (ctx.target === "openapi-3.0") {
|
|
3803
|
+
json.items = {
|
|
3804
|
+
anyOf: prefixItems
|
|
3805
|
+
};
|
|
3806
|
+
if (rest) {
|
|
3807
|
+
json.items.anyOf.push(rest);
|
|
3808
|
+
}
|
|
3809
|
+
json.minItems = prefixItems.length;
|
|
3810
|
+
if (!rest) {
|
|
3811
|
+
json.maxItems = prefixItems.length;
|
|
3812
|
+
}
|
|
3813
|
+
} else {
|
|
3814
|
+
json.items = prefixItems;
|
|
3815
|
+
if (rest) {
|
|
3816
|
+
json.additionalItems = rest;
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
const { minimum, maximum } = schema._zod.bag;
|
|
3820
|
+
if (typeof minimum === "number")
|
|
3821
|
+
json.minItems = minimum;
|
|
3822
|
+
if (typeof maximum === "number")
|
|
3823
|
+
json.maxItems = maximum;
|
|
3824
|
+
};
|
|
3556
3825
|
var recordProcessor = (schema, ctx, _json, params) => {
|
|
3557
3826
|
const json = _json;
|
|
3558
3827
|
const def = schema._zod.def;
|
|
@@ -3648,12 +3917,99 @@ var readonlyProcessor = (schema, ctx, json, params) => {
|
|
|
3648
3917
|
seen.ref = def.innerType;
|
|
3649
3918
|
json.readOnly = true;
|
|
3650
3919
|
};
|
|
3920
|
+
var promiseProcessor = (schema, ctx, _json, params) => {
|
|
3921
|
+
const def = schema._zod.def;
|
|
3922
|
+
process2(def.innerType, ctx, params);
|
|
3923
|
+
const seen = ctx.seen.get(schema);
|
|
3924
|
+
seen.ref = def.innerType;
|
|
3925
|
+
};
|
|
3651
3926
|
var optionalProcessor = (schema, ctx, _json, params) => {
|
|
3652
3927
|
const def = schema._zod.def;
|
|
3653
3928
|
process2(def.innerType, ctx, params);
|
|
3654
3929
|
const seen = ctx.seen.get(schema);
|
|
3655
3930
|
seen.ref = def.innerType;
|
|
3656
3931
|
};
|
|
3932
|
+
var lazyProcessor = (schema, ctx, _json, params) => {
|
|
3933
|
+
const innerType = schema._zod.innerType;
|
|
3934
|
+
process2(innerType, ctx, params);
|
|
3935
|
+
const seen = ctx.seen.get(schema);
|
|
3936
|
+
seen.ref = innerType;
|
|
3937
|
+
};
|
|
3938
|
+
var allProcessors = {
|
|
3939
|
+
string: stringProcessor,
|
|
3940
|
+
number: numberProcessor,
|
|
3941
|
+
boolean: booleanProcessor,
|
|
3942
|
+
bigint: bigintProcessor,
|
|
3943
|
+
symbol: symbolProcessor,
|
|
3944
|
+
null: nullProcessor,
|
|
3945
|
+
undefined: undefinedProcessor,
|
|
3946
|
+
void: voidProcessor,
|
|
3947
|
+
never: neverProcessor,
|
|
3948
|
+
any: anyProcessor,
|
|
3949
|
+
unknown: unknownProcessor,
|
|
3950
|
+
date: dateProcessor,
|
|
3951
|
+
enum: enumProcessor,
|
|
3952
|
+
literal: literalProcessor,
|
|
3953
|
+
nan: nanProcessor,
|
|
3954
|
+
template_literal: templateLiteralProcessor,
|
|
3955
|
+
file: fileProcessor,
|
|
3956
|
+
success: successProcessor,
|
|
3957
|
+
custom: customProcessor,
|
|
3958
|
+
function: functionProcessor,
|
|
3959
|
+
transform: transformProcessor,
|
|
3960
|
+
map: mapProcessor,
|
|
3961
|
+
set: setProcessor,
|
|
3962
|
+
array: arrayProcessor,
|
|
3963
|
+
object: objectProcessor,
|
|
3964
|
+
union: unionProcessor,
|
|
3965
|
+
intersection: intersectionProcessor,
|
|
3966
|
+
tuple: tupleProcessor,
|
|
3967
|
+
record: recordProcessor,
|
|
3968
|
+
nullable: nullableProcessor,
|
|
3969
|
+
nonoptional: nonoptionalProcessor,
|
|
3970
|
+
default: defaultProcessor,
|
|
3971
|
+
prefault: prefaultProcessor,
|
|
3972
|
+
catch: catchProcessor,
|
|
3973
|
+
pipe: pipeProcessor,
|
|
3974
|
+
readonly: readonlyProcessor,
|
|
3975
|
+
promise: promiseProcessor,
|
|
3976
|
+
optional: optionalProcessor,
|
|
3977
|
+
lazy: lazyProcessor
|
|
3978
|
+
};
|
|
3979
|
+
function toJSONSchema(input, params) {
|
|
3980
|
+
if ("_idmap" in input) {
|
|
3981
|
+
const registry = input;
|
|
3982
|
+
const ctx = initializeContext({ ...params, processors: allProcessors });
|
|
3983
|
+
const defs = {};
|
|
3984
|
+
for (const entry of registry._idmap.entries()) {
|
|
3985
|
+
const [_, schema] = entry;
|
|
3986
|
+
process2(schema, ctx);
|
|
3987
|
+
}
|
|
3988
|
+
const schemas = {};
|
|
3989
|
+
const external = {
|
|
3990
|
+
registry,
|
|
3991
|
+
uri: params?.uri,
|
|
3992
|
+
defs
|
|
3993
|
+
};
|
|
3994
|
+
ctx.external = external;
|
|
3995
|
+
for (const entry of registry._idmap.entries()) {
|
|
3996
|
+
const [key, schema] = entry;
|
|
3997
|
+
extractDefs(ctx, schema);
|
|
3998
|
+
schemas[key] = finalize(ctx, schema);
|
|
3999
|
+
}
|
|
4000
|
+
if (Object.keys(defs).length > 0) {
|
|
4001
|
+
const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
|
|
4002
|
+
schemas.__shared = {
|
|
4003
|
+
[defsSegment]: defs
|
|
4004
|
+
};
|
|
4005
|
+
}
|
|
4006
|
+
return { schemas };
|
|
4007
|
+
}
|
|
4008
|
+
const ctx = initializeContext({ ...params, processors: allProcessors });
|
|
4009
|
+
process2(input, ctx);
|
|
4010
|
+
extractDefs(ctx, input);
|
|
4011
|
+
return finalize(ctx, input);
|
|
4012
|
+
}
|
|
3657
4013
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/iso.js
|
|
3658
4014
|
var ZodISODateTime = /* @__PURE__ */ $constructor("ZodISODateTime", (inst, def) => {
|
|
3659
4015
|
$ZodISODateTime.init(inst, def);
|
|
@@ -4372,6 +4728,8 @@ function refine(fn, _params = {}) {
|
|
|
4372
4728
|
function superRefine(fn) {
|
|
4373
4729
|
return _superRefine(fn);
|
|
4374
4730
|
}
|
|
4731
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
4732
|
+
config(en_default());
|
|
4375
4733
|
// ../contracts/src/envelope.ts
|
|
4376
4734
|
var isSubject = (value) => typeof value === "string" && value.length > 0;
|
|
4377
4735
|
var EnvelopeSchema = object({
|
|
@@ -4669,11 +5027,382 @@ function normalizeEnvoyUrl(value) {
|
|
|
4669
5027
|
return value.replace(/\/+$/, "");
|
|
4670
5028
|
}
|
|
4671
5029
|
|
|
5030
|
+
// ../envoy-client/src/dispatch-contract.ts
|
|
5031
|
+
var DISPATCH_TOOL_NAME = "dispatch";
|
|
5032
|
+
var DISPATCH_CONTEXT_MAX = 1200;
|
|
5033
|
+
var DISPATCH_QUESTION_MAX = 800;
|
|
5034
|
+
var DISPATCH_URGENCIES = ["low", "med", "high", "blocking"];
|
|
5035
|
+
var DISPATCH_TOOL_DESCRIPTION = "Raise a durable question to the human as a Dispatch thread (a GitHub issue shown on the dashboard), or continue an existing thread with a follow-up question. The reader has NOT seen your transcript. Open a thread with `subject`; continue one with `thread`. The reply arrives in this session as a steer.";
|
|
5036
|
+
var DISPATCH_ARGUMENTS = {
|
|
5037
|
+
subject: "Open a new thread: one line naming the decision needed (the issue title). Omit when continuing a thread with `thread`.",
|
|
5038
|
+
thread: `Continue an existing thread: "<n>" (an issue in the working directory's repo) or "owner/name#<n>". When set, omit subject, urgency, repo, and parent.`,
|
|
5039
|
+
context: `What you are doing, what you found, why you are stuck \u2014 at most ${DISPATCH_CONTEXT_MAX} characters, at most three short paragraphs or a bullet list. The reader has NOT seen your transcript: no nouns you coined this session, no internal identifiers unless the question is about them. GitHub references (#N, owner/repo#N, URLs) may be bare; the dashboard unfurls them.`,
|
|
5040
|
+
question: `The ask, at most ${DISPATCH_QUESTION_MAX} characters, as a list: current state \u2192 desired state \u2192 your recommendation and why; options go in \`ask\`.`,
|
|
5041
|
+
ask: "Structured questions rendered as buttons on the dashboard. Each: { question, header?, options: [{ label, description? }], multiple?, custom? }. Use this whenever the answer is one of N choices.",
|
|
5042
|
+
urgency: "low | med | high | blocking (default med). Opening a thread only.",
|
|
5043
|
+
repo: "owner/name. Opening a thread only; defaults to the working directory's GitHub repo.",
|
|
5044
|
+
parent: "<n> | owner/name#<n>[#<commentId>]. Opening a thread only: link the thread as a sub-issue of an existing issue and append a breadcrumb to the comment."
|
|
5045
|
+
};
|
|
5046
|
+
|
|
5047
|
+
class DispatchArgumentError extends Error {
|
|
5048
|
+
name = "DispatchArgumentError";
|
|
5049
|
+
}
|
|
5050
|
+
var QuestionOptionSchema = strictObject({
|
|
5051
|
+
label: string2().min(1),
|
|
5052
|
+
description: string2().optional()
|
|
5053
|
+
});
|
|
5054
|
+
var DispatchQuestionSchema = strictObject({
|
|
5055
|
+
question: string2().min(1),
|
|
5056
|
+
header: string2().optional(),
|
|
5057
|
+
options: array(QuestionOptionSchema).optional(),
|
|
5058
|
+
multiple: boolean2().optional(),
|
|
5059
|
+
custom: boolean2().optional()
|
|
5060
|
+
});
|
|
5061
|
+
var prose = {
|
|
5062
|
+
context: string2(),
|
|
5063
|
+
question: string2(),
|
|
5064
|
+
ask: array(DispatchQuestionSchema).optional()
|
|
5065
|
+
};
|
|
5066
|
+
var OpenThreadCallSchema = strictObject({
|
|
5067
|
+
subject: string2(),
|
|
5068
|
+
...prose,
|
|
5069
|
+
urgency: _enum(DISPATCH_URGENCIES).optional(),
|
|
5070
|
+
repo: string2().optional(),
|
|
5071
|
+
parent: string2().optional()
|
|
5072
|
+
});
|
|
5073
|
+
var ContinueThreadCallSchema = strictObject({ thread: string2(), ...prose });
|
|
5074
|
+
var dispatchToolShape = {
|
|
5075
|
+
subject: string2().describe(DISPATCH_ARGUMENTS.subject).optional(),
|
|
5076
|
+
thread: string2().describe(DISPATCH_ARGUMENTS.thread).optional(),
|
|
5077
|
+
context: string2().describe(DISPATCH_ARGUMENTS.context),
|
|
5078
|
+
question: string2().describe(DISPATCH_ARGUMENTS.question),
|
|
5079
|
+
ask: array(DispatchQuestionSchema).describe(DISPATCH_ARGUMENTS.ask).optional(),
|
|
5080
|
+
urgency: _enum(DISPATCH_URGENCIES).describe(DISPATCH_ARGUMENTS.urgency).optional(),
|
|
5081
|
+
repo: string2().describe(DISPATCH_ARGUMENTS.repo).optional(),
|
|
5082
|
+
parent: string2().describe(DISPATCH_ARGUMENTS.parent).optional()
|
|
5083
|
+
};
|
|
5084
|
+
var DISPATCH_TOOL_JSON_SCHEMA = toJSONSchema(object(dispatchToolShape));
|
|
5085
|
+
function isContinueCall(call) {
|
|
5086
|
+
return "thread" in call;
|
|
5087
|
+
}
|
|
5088
|
+
function present(raw) {
|
|
5089
|
+
return Object.fromEntries(Object.entries(raw).filter(([, value]) => value !== undefined));
|
|
5090
|
+
}
|
|
5091
|
+
function describeIssues(error) {
|
|
5092
|
+
return error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
5093
|
+
}
|
|
5094
|
+
function parseDispatchCall(raw) {
|
|
5095
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
5096
|
+
throw new DispatchArgumentError("dispatch: invalid arguments \u2014 expected an object");
|
|
5097
|
+
}
|
|
5098
|
+
const args = present(raw);
|
|
5099
|
+
const hasSubject = "subject" in args;
|
|
5100
|
+
const hasThread = "thread" in args;
|
|
5101
|
+
if (hasSubject && hasThread) {
|
|
5102
|
+
throw new DispatchArgumentError("dispatch: pass either subject (open a thread) or thread (continue one), not both");
|
|
5103
|
+
}
|
|
5104
|
+
if (!hasSubject && !hasThread) {
|
|
5105
|
+
throw new DispatchArgumentError("dispatch: subject or thread is required");
|
|
5106
|
+
}
|
|
5107
|
+
if (hasThread && (("urgency" in args) || ("repo" in args) || ("parent" in args))) {
|
|
5108
|
+
throw new DispatchArgumentError("dispatch: thread cannot be combined with urgency, repo, or parent");
|
|
5109
|
+
}
|
|
5110
|
+
const parsed = hasThread ? ContinueThreadCallSchema.safeParse(args) : OpenThreadCallSchema.safeParse(args);
|
|
5111
|
+
if (!parsed.success) {
|
|
5112
|
+
throw new DispatchArgumentError(`dispatch: invalid arguments \u2014 ${describeIssues(parsed.error)}`);
|
|
5113
|
+
}
|
|
5114
|
+
return parsed.data;
|
|
5115
|
+
}
|
|
5116
|
+
|
|
5117
|
+
// ../envoy-client/src/dispatch-cwd.ts
|
|
5118
|
+
import { execFile } from "child_process";
|
|
5119
|
+
import { promisify } from "util";
|
|
5120
|
+
|
|
5121
|
+
// ../envoy-client/src/machine.ts
|
|
5122
|
+
import { hostname } from "os";
|
|
5123
|
+
function machineID() {
|
|
5124
|
+
return process.env["ENVOY_MACHINE_ID"] || hostname();
|
|
5125
|
+
}
|
|
5126
|
+
|
|
5127
|
+
// ../envoy-client/src/dispatch-cwd.ts
|
|
5128
|
+
var execFileAsync = promisify(execFile);
|
|
5129
|
+
var defaultExec = (file, args, options) => execFileAsync(file, args, { cwd: options.cwd, timeout: 5000 });
|
|
5130
|
+
async function tryExec(exec, file, args, cwd) {
|
|
5131
|
+
try {
|
|
5132
|
+
const { stdout } = await exec(file, args, { cwd });
|
|
5133
|
+
return stdout;
|
|
5134
|
+
} catch {
|
|
5135
|
+
return null;
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
function parseRemoteList(stdout) {
|
|
5139
|
+
const remotes = new Map;
|
|
5140
|
+
for (const line of stdout.split(`
|
|
5141
|
+
`)) {
|
|
5142
|
+
const trimmed = line.trim();
|
|
5143
|
+
if (!trimmed)
|
|
5144
|
+
continue;
|
|
5145
|
+
const match = trimmed.match(/^(\S+)\s+(\S+)/);
|
|
5146
|
+
const [, name, url] = match ?? [];
|
|
5147
|
+
if (name && url)
|
|
5148
|
+
remotes.set(name, url);
|
|
5149
|
+
}
|
|
5150
|
+
return remotes;
|
|
5151
|
+
}
|
|
5152
|
+
function selectRemoteUrl(remotes) {
|
|
5153
|
+
const origin = remotes.get("origin");
|
|
5154
|
+
if (origin)
|
|
5155
|
+
return origin;
|
|
5156
|
+
const candidates = [...remotes.entries()].filter(([name]) => name !== "upstream");
|
|
5157
|
+
return candidates.length === 1 ? candidates[0]?.[1] ?? null : null;
|
|
5158
|
+
}
|
|
5159
|
+
var GITHUB_REMOTE_PATTERNS = [
|
|
5160
|
+
/^https:\/\/(?:[^@/\s]+@)?github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i,
|
|
5161
|
+
/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?\/?$/i,
|
|
5162
|
+
/^ssh:\/\/git@github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i
|
|
5163
|
+
];
|
|
5164
|
+
function parseGitHubRemoteUrl(url) {
|
|
5165
|
+
const trimmed = url.trim();
|
|
5166
|
+
for (const pattern of GITHUB_REMOTE_PATTERNS) {
|
|
5167
|
+
const match = trimmed.match(pattern);
|
|
5168
|
+
if (match)
|
|
5169
|
+
return `${match[1]}/${match[2]}`;
|
|
5170
|
+
}
|
|
5171
|
+
return null;
|
|
5172
|
+
}
|
|
5173
|
+
async function resolveCwdRepo(cwd, exec) {
|
|
5174
|
+
const jjOutput = await tryExec(exec, "jj", ["git", "remote", "list"], cwd);
|
|
5175
|
+
if (jjOutput !== null) {
|
|
5176
|
+
const url = selectRemoteUrl(parseRemoteList(jjOutput));
|
|
5177
|
+
return url ? parseGitHubRemoteUrl(url) : null;
|
|
5178
|
+
}
|
|
5179
|
+
const originUrl = await tryExec(exec, "git", ["remote", "get-url", "origin"], cwd);
|
|
5180
|
+
return originUrl ? parseGitHubRemoteUrl(originUrl) : null;
|
|
5181
|
+
}
|
|
5182
|
+
async function resolveOrigin(env, exec, cwd) {
|
|
5183
|
+
const origin = {
|
|
5184
|
+
cwd,
|
|
5185
|
+
machine: machineID()
|
|
5186
|
+
};
|
|
5187
|
+
const pane = env["TMUX_PANE"];
|
|
5188
|
+
if (pane) {
|
|
5189
|
+
const output = await tryExec(exec, "tmux", ["display-message", "-p", "-t", pane, "#S:#I.#P #{pane_id}"], cwd);
|
|
5190
|
+
const [target, paneId] = output?.trim().split(" ") ?? [];
|
|
5191
|
+
if (target)
|
|
5192
|
+
origin.tmux = target;
|
|
5193
|
+
if (paneId)
|
|
5194
|
+
origin.pane = paneId;
|
|
5195
|
+
}
|
|
5196
|
+
return origin;
|
|
5197
|
+
}
|
|
5198
|
+
|
|
5199
|
+
// ../envoy-client/src/errors.ts
|
|
5200
|
+
function messageFor(error) {
|
|
5201
|
+
return error instanceof Error ? error.message : String(error);
|
|
5202
|
+
}
|
|
5203
|
+
|
|
5204
|
+
// ../envoy-client/src/dispatch-client.ts
|
|
5205
|
+
function ghTokenGetter(cwd, exec = defaultExec) {
|
|
5206
|
+
return async () => {
|
|
5207
|
+
try {
|
|
5208
|
+
const { stdout } = await exec("gh", ["auth", "token"], { cwd });
|
|
5209
|
+
const value = stdout.trim();
|
|
5210
|
+
return value.length > 0 ? value : null;
|
|
5211
|
+
} catch {
|
|
5212
|
+
return null;
|
|
5213
|
+
}
|
|
5214
|
+
};
|
|
5215
|
+
}
|
|
5216
|
+
|
|
5217
|
+
class DispatchServiceError extends Error {
|
|
5218
|
+
kind;
|
|
5219
|
+
name = "DispatchServiceError";
|
|
5220
|
+
constructor(kind, message) {
|
|
5221
|
+
super(message);
|
|
5222
|
+
this.kind = kind;
|
|
5223
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
function parseResponseBody(body, contentType) {
|
|
5226
|
+
if (!contentType.includes("text/event-stream"))
|
|
5227
|
+
return JSON.parse(body);
|
|
5228
|
+
for (const line of body.split(`
|
|
5229
|
+
`)) {
|
|
5230
|
+
const payload = line.match(/^data:\s*(.+)$/)?.[1];
|
|
5231
|
+
if (payload !== undefined)
|
|
5232
|
+
return JSON.parse(payload);
|
|
5233
|
+
}
|
|
5234
|
+
return null;
|
|
5235
|
+
}
|
|
5236
|
+
function isDispatchServiceResult(value) {
|
|
5237
|
+
return typeof value === "object" && value !== null && "thread" in value && typeof value.thread === "number" && "url" in value && typeof value.url === "string";
|
|
5238
|
+
}
|
|
5239
|
+
async function callDispatch(options, args) {
|
|
5240
|
+
const token = await options.getToken();
|
|
5241
|
+
if (!token) {
|
|
5242
|
+
throw new DispatchServiceError("auth", `dispatch: gh auth token returned empty in ${args.origin.cwd} \u2014 check your gh-app setup`);
|
|
5243
|
+
}
|
|
5244
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5245
|
+
let response;
|
|
5246
|
+
try {
|
|
5247
|
+
response = await fetchImpl(options.serviceUrl, {
|
|
5248
|
+
method: "POST",
|
|
5249
|
+
headers: {
|
|
5250
|
+
Authorization: `Bearer ${token}`,
|
|
5251
|
+
"Content-Type": "application/json",
|
|
5252
|
+
Accept: "application/json, text/event-stream"
|
|
5253
|
+
},
|
|
5254
|
+
body: JSON.stringify({
|
|
5255
|
+
jsonrpc: "2.0",
|
|
5256
|
+
id: 1,
|
|
5257
|
+
method: "tools/call",
|
|
5258
|
+
params: { name: DISPATCH_TOOL_NAME, arguments: args }
|
|
5259
|
+
})
|
|
5260
|
+
});
|
|
5261
|
+
} catch (error) {
|
|
5262
|
+
throw new DispatchServiceError("transport", `dispatch service unreachable at ${options.serviceUrl}: ${messageFor(error)}`);
|
|
5263
|
+
}
|
|
5264
|
+
const body = await response.text();
|
|
5265
|
+
if (response.status === 401) {
|
|
5266
|
+
throw new DispatchServiceError("auth", `dispatch service rejected the GitHub token (401): ${body.slice(0, 200)}`);
|
|
5267
|
+
}
|
|
5268
|
+
if (!response.ok) {
|
|
5269
|
+
throw new DispatchServiceError("transport", `dispatch service returned ${response.status} ${response.statusText}: ${body.slice(0, 200)}`);
|
|
5270
|
+
}
|
|
5271
|
+
let parsed;
|
|
5272
|
+
try {
|
|
5273
|
+
parsed = parseResponseBody(body, response.headers.get("content-type") ?? "");
|
|
5274
|
+
} catch (error) {
|
|
5275
|
+
throw new DispatchServiceError("transport", `dispatch service sent an unreadable response: ${messageFor(error)}`);
|
|
5276
|
+
}
|
|
5277
|
+
const rpc = parsed ?? {};
|
|
5278
|
+
if (rpc.error) {
|
|
5279
|
+
throw new DispatchServiceError("tool", rpc.error.message ?? "dispatch service returned an error");
|
|
5280
|
+
}
|
|
5281
|
+
const text = (rpc.result?.content ?? []).map((item) => item.text ?? "").filter(Boolean).join(`
|
|
5282
|
+
`);
|
|
5283
|
+
if (rpc.result?.isError)
|
|
5284
|
+
throw new DispatchServiceError("tool", text || "dispatch failed");
|
|
5285
|
+
let result;
|
|
5286
|
+
try {
|
|
5287
|
+
result = JSON.parse(text);
|
|
5288
|
+
} catch {
|
|
5289
|
+
throw new DispatchServiceError("transport", `dispatch service returned a non-JSON result: ${text.slice(0, 200)}`);
|
|
5290
|
+
}
|
|
5291
|
+
if (!isDispatchServiceResult(result)) {
|
|
5292
|
+
throw new DispatchServiceError("transport", `dispatch service result lacks thread/url: ${text.slice(0, 200)}`);
|
|
5293
|
+
}
|
|
5294
|
+
return result;
|
|
5295
|
+
}
|
|
5296
|
+
|
|
5297
|
+
// ../envoy-client/src/dispatch-call.ts
|
|
5298
|
+
var QUALIFIED_REF = /^[^/\s#]+\/[^/\s#]+#\d+/;
|
|
5299
|
+
async function prepareDispatchCall(input) {
|
|
5300
|
+
const { call, cwd } = input;
|
|
5301
|
+
const continuing = isContinueCall(call);
|
|
5302
|
+
const needsRepo = continuing ? !QUALIFIED_REF.test(call.thread) : call.repo === undefined && !QUALIFIED_REF.test(call.parent ?? "");
|
|
5303
|
+
let repo;
|
|
5304
|
+
if (needsRepo) {
|
|
5305
|
+
const resolved = await resolveCwdRepo(cwd, input.exec);
|
|
5306
|
+
if (resolved === null) {
|
|
5307
|
+
throw new DispatchArgumentError(continuing ? `dispatch: ${cwd} has no GitHub remote; pass thread=owner/name#<n>` : `dispatch: ${cwd} has no GitHub remote; pass repo=owner/name`);
|
|
5308
|
+
}
|
|
5309
|
+
repo = resolved;
|
|
5310
|
+
}
|
|
5311
|
+
const resolvedOrigin = await resolveOrigin(input.env, input.exec, cwd);
|
|
5312
|
+
const origin = {
|
|
5313
|
+
...resolvedOrigin,
|
|
5314
|
+
host: input.host,
|
|
5315
|
+
...input.sessionId ? { sessionId: input.sessionId } : {},
|
|
5316
|
+
...input.sessionTitle ? { sessionTitle: input.sessionTitle } : {}
|
|
5317
|
+
};
|
|
5318
|
+
return { ...call, ...repo === undefined ? {} : { repo }, origin };
|
|
5319
|
+
}
|
|
5320
|
+
async function executeDispatch(input) {
|
|
5321
|
+
const exec = input.exec ?? defaultExec;
|
|
5322
|
+
const prepared = await prepareDispatchCall({
|
|
5323
|
+
call: input.call,
|
|
5324
|
+
cwd: input.cwd,
|
|
5325
|
+
host: input.host,
|
|
5326
|
+
...input.sessionId === undefined ? {} : { sessionId: input.sessionId },
|
|
5327
|
+
...input.sessionTitle === undefined ? {} : { sessionTitle: input.sessionTitle },
|
|
5328
|
+
env: input.env ?? process.env,
|
|
5329
|
+
exec
|
|
5330
|
+
});
|
|
5331
|
+
return callDispatch({
|
|
5332
|
+
serviceUrl: input.serviceUrl,
|
|
5333
|
+
getToken: input.getToken ?? ghTokenGetter(input.cwd, exec),
|
|
5334
|
+
...input.fetchImpl ? { fetchImpl: input.fetchImpl } : {}
|
|
5335
|
+
}, prepared);
|
|
5336
|
+
}
|
|
5337
|
+
|
|
5338
|
+
// ../envoy-client/src/dispatch-config.ts
|
|
5339
|
+
import { readFileSync } from "fs";
|
|
5340
|
+
import { homedir } from "os";
|
|
5341
|
+
import * as path from "path";
|
|
5342
|
+
var DEFAULT_SERVER_URL = "http://localhost:8766";
|
|
5343
|
+
var EnvoyFileSchema = looseObject({
|
|
5344
|
+
$schema: string2().optional(),
|
|
5345
|
+
natsUrls: array(string2()).optional(),
|
|
5346
|
+
dispatch: strictObject({
|
|
5347
|
+
enabled: boolean2().optional(),
|
|
5348
|
+
serverUrl: url().optional()
|
|
5349
|
+
}).optional()
|
|
5350
|
+
});
|
|
5351
|
+
function describeSchemaIssue(filePath, error) {
|
|
5352
|
+
const issue = error.issues[0];
|
|
5353
|
+
if (!issue)
|
|
5354
|
+
return `${filePath}: invalid dispatch config`;
|
|
5355
|
+
if (issue.code === "unrecognized_keys") {
|
|
5356
|
+
const keys = issue.keys.map((key) => `dispatch.${key}`).join(", ");
|
|
5357
|
+
return `${filePath}: unrecognized dispatch key(s): ${keys}`;
|
|
5358
|
+
}
|
|
5359
|
+
return `${filePath}: ${issue.path.join(".")}: ${issue.message}`;
|
|
5360
|
+
}
|
|
5361
|
+
function readEnvoyFile(filePath) {
|
|
5362
|
+
let raw;
|
|
5363
|
+
try {
|
|
5364
|
+
raw = readFileSync(filePath, "utf-8");
|
|
5365
|
+
} catch {
|
|
5366
|
+
return { kind: "absent" };
|
|
5367
|
+
}
|
|
5368
|
+
let parsedJson;
|
|
5369
|
+
try {
|
|
5370
|
+
parsedJson = JSON.parse(raw);
|
|
5371
|
+
} catch (err) {
|
|
5372
|
+
return { kind: "invalid", reason: `${filePath}: invalid JSON (${messageFor(err)})` };
|
|
5373
|
+
}
|
|
5374
|
+
const parsed = EnvoyFileSchema.safeParse(parsedJson);
|
|
5375
|
+
if (!parsed.success) {
|
|
5376
|
+
return { kind: "invalid", reason: describeSchemaIssue(filePath, parsed.error) };
|
|
5377
|
+
}
|
|
5378
|
+
return { kind: "valid", settings: parsed.data.dispatch ?? null };
|
|
5379
|
+
}
|
|
5380
|
+
function resolveDispatchConfig(env, options = {}) {
|
|
5381
|
+
const explicit = env["DISPATCH_MCP_URL"];
|
|
5382
|
+
if (explicit)
|
|
5383
|
+
return { url: explicit, error: null };
|
|
5384
|
+
const home = options.home ?? env["HOME"] ?? homedir();
|
|
5385
|
+
const cwd = options.cwd ?? process.cwd();
|
|
5386
|
+
const userFile = readEnvoyFile(path.join(home, ".config", "opencode", "envoy.json"));
|
|
5387
|
+
const repoFile = readEnvoyFile(path.join(cwd, ".opencode", "envoy.json"));
|
|
5388
|
+
for (const file of [userFile, repoFile]) {
|
|
5389
|
+
if (file.kind === "invalid")
|
|
5390
|
+
return { url: null, error: file.reason };
|
|
5391
|
+
}
|
|
5392
|
+
const merged = {
|
|
5393
|
+
...userFile.kind === "valid" ? userFile.settings : null,
|
|
5394
|
+
...repoFile.kind === "valid" ? repoFile.settings : null
|
|
5395
|
+
};
|
|
5396
|
+
if (merged.enabled !== true)
|
|
5397
|
+
return { url: null, error: null };
|
|
5398
|
+
const baseUrl = (merged.serverUrl ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
|
|
5399
|
+
return { url: `${baseUrl}/mcp`, error: null };
|
|
5400
|
+
}
|
|
5401
|
+
|
|
4672
5402
|
// ../envoy-client/src/dispatch-subscribe.ts
|
|
4673
5403
|
var ISSUE_URL_RE = /https?:\/\/github\.com\/([^/\s"]+)\/([^/\s"]+)\/issues\/(\d+)/i;
|
|
4674
|
-
var DISPATCH_TOOL_RE = /(^|[-._])dispatch$/i;
|
|
4675
5404
|
function isDispatchTool(tool) {
|
|
4676
|
-
return
|
|
5405
|
+
return tool === DISPATCH_TOOL_NAME;
|
|
4677
5406
|
}
|
|
4678
5407
|
function dispatchThreadTopic(owner, repo, thread) {
|
|
4679
5408
|
return `notifications.github.${owner}.${repo}.issue.${thread}.>`;
|
|
@@ -4692,12 +5421,6 @@ function dispatchSubscriptionTopic(tool, output) {
|
|
|
4692
5421
|
return dispatchThreadTopic(owner, repo, thread);
|
|
4693
5422
|
}
|
|
4694
5423
|
|
|
4695
|
-
// ../envoy-client/src/machine.ts
|
|
4696
|
-
import { hostname } from "os";
|
|
4697
|
-
function machineID() {
|
|
4698
|
-
return process.env["ENVOY_MACHINE_ID"] || hostname();
|
|
4699
|
-
}
|
|
4700
|
-
|
|
4701
5424
|
// ../envoy-client/src/tool-contract.ts
|
|
4702
5425
|
var EnvoyToolOperation = {
|
|
4703
5426
|
subscribe: "subscribe",
|
|
@@ -4861,135 +5584,17 @@ function toEnvelope(value) {
|
|
|
4861
5584
|
}
|
|
4862
5585
|
|
|
4863
5586
|
// src/server.ts
|
|
4864
|
-
import { tool
|
|
4865
|
-
|
|
4866
|
-
// src/config/index.ts
|
|
4867
|
-
import { existsSync, readFileSync } from "fs";
|
|
4868
|
-
import os from "os";
|
|
4869
|
-
import path from "path";
|
|
4870
|
-
|
|
4871
|
-
// ../envoy-client/src/errors.ts
|
|
4872
|
-
function messageFor(error) {
|
|
4873
|
-
return error instanceof Error ? error.message : String(error);
|
|
4874
|
-
}
|
|
4875
|
-
|
|
4876
|
-
// src/config/schema.ts
|
|
4877
|
-
import { tool } from "@opencode-ai/plugin";
|
|
4878
|
-
var z = tool.schema;
|
|
4879
|
-
var DispatchConfigSchema = z.object({
|
|
4880
|
-
enabled: z.boolean().optional(),
|
|
4881
|
-
serverUrl: z.string().url().optional()
|
|
4882
|
-
}).strict();
|
|
4883
|
-
var EnvoyConfigSchema = z.object({
|
|
4884
|
-
$schema: z.string().optional(),
|
|
4885
|
-
natsUrls: z.array(z.string()).optional(),
|
|
4886
|
-
dispatch: DispatchConfigSchema.optional()
|
|
4887
|
-
}).passthrough();
|
|
4888
|
-
|
|
4889
|
-
// src/config/index.ts
|
|
4890
|
-
class EnvoyConfigError extends Error {
|
|
4891
|
-
filePath;
|
|
4892
|
-
constructor(filePath, detail) {
|
|
4893
|
-
super(`[envoy-plugin] invalid config at ${filePath}: ${detail}`);
|
|
4894
|
-
this.name = "EnvoyConfigError";
|
|
4895
|
-
this.filePath = filePath;
|
|
4896
|
-
}
|
|
4897
|
-
}
|
|
4898
|
-
function readConfigFile(filePath) {
|
|
4899
|
-
if (!existsSync(filePath))
|
|
4900
|
-
return null;
|
|
4901
|
-
let raw;
|
|
4902
|
-
try {
|
|
4903
|
-
raw = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
4904
|
-
} catch (error) {
|
|
4905
|
-
throw new EnvoyConfigError(filePath, messageFor(error));
|
|
4906
|
-
}
|
|
4907
|
-
const parsed = EnvoyConfigSchema.safeParse(raw);
|
|
4908
|
-
if (!parsed.success) {
|
|
4909
|
-
const issues = parsed.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join(", ");
|
|
4910
|
-
throw new EnvoyConfigError(filePath, issues);
|
|
4911
|
-
}
|
|
4912
|
-
return parsed.data;
|
|
4913
|
-
}
|
|
4914
|
-
function mergeConfig(base, override) {
|
|
4915
|
-
return {
|
|
4916
|
-
...base,
|
|
4917
|
-
...override,
|
|
4918
|
-
dispatch: base.dispatch || override.dispatch ? {
|
|
4919
|
-
...base.dispatch,
|
|
4920
|
-
...override.dispatch
|
|
4921
|
-
} : undefined
|
|
4922
|
-
};
|
|
4923
|
-
}
|
|
4924
|
-
async function loadEnvoyConfig(directory, options = {}) {
|
|
4925
|
-
const homeDir = options.homeDir ?? os.homedir();
|
|
4926
|
-
const userConfigPath = path.join(homeDir, ".config", "opencode", "envoy.json");
|
|
4927
|
-
const repoConfigPath = path.join(directory, ".opencode", "envoy.json");
|
|
4928
|
-
let merged = {};
|
|
4929
|
-
const userConfig = readConfigFile(userConfigPath);
|
|
4930
|
-
if (userConfig)
|
|
4931
|
-
merged = mergeConfig(merged, userConfig);
|
|
4932
|
-
const repoConfig = readConfigFile(repoConfigPath);
|
|
4933
|
-
if (repoConfig)
|
|
4934
|
-
merged = mergeConfig(merged, repoConfig);
|
|
4935
|
-
return merged;
|
|
4936
|
-
}
|
|
4937
|
-
|
|
4938
|
-
// src/dispatch-mcp.ts
|
|
4939
|
-
import { existsSync as existsSync2 } from "fs";
|
|
4940
|
-
import path2 from "path";
|
|
4941
|
-
var DEFAULT_SERVER_URL = "http://localhost:8766";
|
|
4942
|
-
function defaultShimPath() {
|
|
4943
|
-
const packageRoot = path2.join(import.meta.dir, "..");
|
|
4944
|
-
const candidates = [
|
|
4945
|
-
path2.join(packageRoot, "bin", "dispatch-mcp-shim.js"),
|
|
4946
|
-
path2.join(packageRoot, "bin", "dispatch-mcp-shim.ts")
|
|
4947
|
-
];
|
|
4948
|
-
const found = candidates.find((candidate) => existsSync2(candidate));
|
|
4949
|
-
if (!found) {
|
|
4950
|
-
throw new Error(`dispatch MCP shim not found; tried: ${candidates.join(", ")}`);
|
|
4951
|
-
}
|
|
4952
|
-
return found;
|
|
4953
|
-
}
|
|
4954
|
-
function buildDispatchMcpEntry(opts) {
|
|
4955
|
-
if (!opts.dispatch?.enabled)
|
|
4956
|
-
return null;
|
|
4957
|
-
const baseUrl = (opts.dispatch.serverUrl ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
|
|
4958
|
-
const shimPath = opts.shimPath ?? defaultShimPath();
|
|
4959
|
-
const runtime = opts.runtime ?? "bun";
|
|
4960
|
-
return {
|
|
4961
|
-
type: "local",
|
|
4962
|
-
command: [runtime, shimPath],
|
|
4963
|
-
environment: {
|
|
4964
|
-
DISPATCH_MCP_URL: `${baseUrl}/mcp`
|
|
4965
|
-
},
|
|
4966
|
-
enabled: true
|
|
4967
|
-
};
|
|
4968
|
-
}
|
|
4969
|
-
function injectEnvoyMcp(cfg, entry) {
|
|
4970
|
-
cfg.mcp = cfg.mcp ?? {};
|
|
4971
|
-
const existing = cfg.mcp.envoy;
|
|
4972
|
-
if (existing !== undefined) {
|
|
4973
|
-
if (JSON.stringify(existing) === JSON.stringify(entry)) {
|
|
4974
|
-
return {};
|
|
4975
|
-
}
|
|
4976
|
-
return {
|
|
4977
|
-
warning: "[envoy-plugin] envoy MCP entry already present in config; not overriding"
|
|
4978
|
-
};
|
|
4979
|
-
}
|
|
4980
|
-
cfg.mcp.envoy = entry;
|
|
4981
|
-
return {};
|
|
4982
|
-
}
|
|
5587
|
+
import { tool } from "@opencode-ai/plugin/tool";
|
|
4983
5588
|
|
|
4984
5589
|
// src/log.ts
|
|
4985
5590
|
import { appendFile, mkdir } from "fs/promises";
|
|
4986
|
-
import
|
|
4987
|
-
import
|
|
5591
|
+
import os from "os";
|
|
5592
|
+
import path2 from "path";
|
|
4988
5593
|
function defaultLogDir() {
|
|
4989
|
-
const home =
|
|
5594
|
+
const home = os.homedir();
|
|
4990
5595
|
if (!home)
|
|
4991
|
-
return
|
|
4992
|
-
return
|
|
5596
|
+
return path2.join(os.tmpdir(), "opencode-log");
|
|
5597
|
+
return path2.join(home, ".local", "share", "opencode", "log");
|
|
4993
5598
|
}
|
|
4994
5599
|
function format(level, message) {
|
|
4995
5600
|
return `${new Date().toISOString()} ${level} ${message}
|
|
@@ -4997,7 +5602,7 @@ function format(level, message) {
|
|
|
4997
5602
|
}
|
|
4998
5603
|
function createLogger(options = {}) {
|
|
4999
5604
|
const dir = options.logDir ?? defaultLogDir();
|
|
5000
|
-
const file =
|
|
5605
|
+
const file = path2.join(dir, options.fileName ?? "envoy-plugin.log");
|
|
5001
5606
|
let chain = Promise.resolve();
|
|
5002
5607
|
const append = (line) => {
|
|
5003
5608
|
chain = chain.then(() => mkdir(dir, { recursive: true })).then(() => appendFile(file, line)).catch(() => {});
|
|
@@ -5020,7 +5625,7 @@ function createLogger(options = {}) {
|
|
|
5020
5625
|
var logger = createLogger();
|
|
5021
5626
|
|
|
5022
5627
|
// src/port.ts
|
|
5023
|
-
import { execFile } from "child_process";
|
|
5628
|
+
import { execFile as execFile2 } from "child_process";
|
|
5024
5629
|
|
|
5025
5630
|
// src/ss.ts
|
|
5026
5631
|
function portFromSsOutput(output, pid) {
|
|
@@ -5042,15 +5647,15 @@ function portFromSsOutput(output, pid) {
|
|
|
5042
5647
|
}
|
|
5043
5648
|
|
|
5044
5649
|
// src/port.ts
|
|
5045
|
-
var
|
|
5046
|
-
|
|
5650
|
+
var defaultExec2 = (command, args, options) => new Promise((resolve, reject) => {
|
|
5651
|
+
execFile2(command, args, { encoding: options.encoding }, (error, stdout) => {
|
|
5047
5652
|
if (error)
|
|
5048
5653
|
reject(error);
|
|
5049
5654
|
else
|
|
5050
5655
|
resolve(stdout);
|
|
5051
5656
|
});
|
|
5052
5657
|
});
|
|
5053
|
-
async function resolvePort(serverUrl, exec =
|
|
5658
|
+
async function resolvePort(serverUrl, exec = defaultExec2) {
|
|
5054
5659
|
const urlPort = Number.parseInt(serverUrl.port, 10);
|
|
5055
5660
|
if (Number.isFinite(urlPort) && urlPort > 0)
|
|
5056
5661
|
return urlPort;
|
|
@@ -5064,11 +5669,11 @@ async function resolvePort(serverUrl, exec = defaultExec) {
|
|
|
5064
5669
|
}
|
|
5065
5670
|
|
|
5066
5671
|
// src/server.ts
|
|
5067
|
-
var moduleDirectory =
|
|
5672
|
+
var moduleDirectory = path3.dirname(fileURLToPath(import.meta.url));
|
|
5068
5673
|
var skillsDirectory = [
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
].find((dir) =>
|
|
5674
|
+
path3.resolve(moduleDirectory, "../../skills"),
|
|
5675
|
+
path3.resolve(moduleDirectory, "../../../skills")
|
|
5676
|
+
].find((dir) => existsSync(dir));
|
|
5072
5677
|
var [
|
|
5073
5678
|
subscribeSpec,
|
|
5074
5679
|
unsubscribeSpec,
|
|
@@ -5079,9 +5684,33 @@ var [
|
|
|
5079
5684
|
whoamiSpec,
|
|
5080
5685
|
sessionsSpec
|
|
5081
5686
|
] = envoyToolSpecs;
|
|
5687
|
+
var dispatchQuestionOption = tool.schema.strictObject({
|
|
5688
|
+
label: tool.schema.string().min(1),
|
|
5689
|
+
description: tool.schema.string().optional()
|
|
5690
|
+
});
|
|
5691
|
+
var dispatchQuestion = tool.schema.strictObject({
|
|
5692
|
+
question: tool.schema.string().min(1),
|
|
5693
|
+
header: tool.schema.string().optional(),
|
|
5694
|
+
options: tool.schema.array(dispatchQuestionOption).optional(),
|
|
5695
|
+
multiple: tool.schema.boolean().optional(),
|
|
5696
|
+
custom: tool.schema.boolean().optional()
|
|
5697
|
+
});
|
|
5698
|
+
var dispatchArgs = {
|
|
5699
|
+
subject: tool.schema.string().describe(DISPATCH_ARGUMENTS.subject).optional(),
|
|
5700
|
+
thread: tool.schema.string().describe(DISPATCH_ARGUMENTS.thread).optional(),
|
|
5701
|
+
context: tool.schema.string().describe(DISPATCH_ARGUMENTS.context),
|
|
5702
|
+
question: tool.schema.string().describe(DISPATCH_ARGUMENTS.question),
|
|
5703
|
+
ask: tool.schema.array(dispatchQuestion).describe(DISPATCH_ARGUMENTS.ask).optional(),
|
|
5704
|
+
urgency: tool.schema.enum(DISPATCH_URGENCIES).describe(DISPATCH_ARGUMENTS.urgency).optional(),
|
|
5705
|
+
repo: tool.schema.string().describe(DISPATCH_ARGUMENTS.repo).optional(),
|
|
5706
|
+
parent: tool.schema.string().describe(DISPATCH_ARGUMENTS.parent).optional()
|
|
5707
|
+
};
|
|
5082
5708
|
var server_default = async (input) => {
|
|
5083
5709
|
const cwd = process.cwd();
|
|
5084
|
-
const
|
|
5710
|
+
const dispatchConfig = resolveDispatchConfig(process.env, { cwd });
|
|
5711
|
+
if (dispatchConfig.error !== null)
|
|
5712
|
+
throw new Error(`[envoy-plugin] ${dispatchConfig.error}`);
|
|
5713
|
+
const dispatchServiceUrl = dispatchConfig.url;
|
|
5085
5714
|
const envoyDefaults = envoyDefaultsFromEnvironment(process.env);
|
|
5086
5715
|
const envoy = createEnvoyClient({ baseUrl: envoyDefaults.envoyUrl, fetch: globalThis.fetch });
|
|
5087
5716
|
let activeSessionID = null;
|
|
@@ -5152,6 +5781,25 @@ var server_default = async (input) => {
|
|
|
5152
5781
|
clearInterval(timer);
|
|
5153
5782
|
clearInterval(heartbeatInterval);
|
|
5154
5783
|
});
|
|
5784
|
+
const dispatchTool = dispatchServiceUrl === null ? {} : {
|
|
5785
|
+
[DISPATCH_TOOL_NAME]: tool({
|
|
5786
|
+
description: DISPATCH_TOOL_DESCRIPTION,
|
|
5787
|
+
args: dispatchArgs,
|
|
5788
|
+
async execute(args, ctx) {
|
|
5789
|
+
ctx.metadata({ title: "Dispatch" });
|
|
5790
|
+
const call = parseDispatchCall(args);
|
|
5791
|
+
const result = await executeDispatch({
|
|
5792
|
+
call,
|
|
5793
|
+
cwd: ctx.directory,
|
|
5794
|
+
host: "opencode",
|
|
5795
|
+
sessionId: ctx.sessionID,
|
|
5796
|
+
sessionTitle: await fetchTitle(ctx.sessionID) ?? undefined,
|
|
5797
|
+
serviceUrl: dispatchServiceUrl
|
|
5798
|
+
});
|
|
5799
|
+
return JSON.stringify(result);
|
|
5800
|
+
}
|
|
5801
|
+
})
|
|
5802
|
+
};
|
|
5155
5803
|
return {
|
|
5156
5804
|
config: (cfg) => {
|
|
5157
5805
|
if (skillsDirectory) {
|
|
@@ -5161,14 +5809,6 @@ var server_default = async (input) => {
|
|
|
5161
5809
|
cfg.skills.paths.push(skillsDirectory);
|
|
5162
5810
|
}
|
|
5163
5811
|
}
|
|
5164
|
-
const entry = buildDispatchMcpEntry({
|
|
5165
|
-
dispatch: config.dispatch
|
|
5166
|
-
});
|
|
5167
|
-
if (!entry)
|
|
5168
|
-
return;
|
|
5169
|
-
const { warning } = injectEnvoyMcp(cfg, entry);
|
|
5170
|
-
if (warning)
|
|
5171
|
-
logger.warn(warning);
|
|
5172
5812
|
},
|
|
5173
5813
|
event: async ({
|
|
5174
5814
|
event
|
|
@@ -5242,9 +5882,10 @@ var server_default = async (input) => {
|
|
|
5242
5882
|
clearInterval(heartbeatInterval);
|
|
5243
5883
|
},
|
|
5244
5884
|
tool: {
|
|
5245
|
-
|
|
5885
|
+
...dispatchTool,
|
|
5886
|
+
envoy_subscribe: tool({
|
|
5246
5887
|
description: subscribeSpec.description,
|
|
5247
|
-
args: { topics:
|
|
5888
|
+
args: { topics: tool.schema.array(tool.schema.string()) },
|
|
5248
5889
|
async execute(args, ctx) {
|
|
5249
5890
|
ctx.metadata({ title: "Envoy subscribe" });
|
|
5250
5891
|
return JSON.stringify(await envoy.subscribe({
|
|
@@ -5257,16 +5898,16 @@ var server_default = async (input) => {
|
|
|
5257
5898
|
}));
|
|
5258
5899
|
}
|
|
5259
5900
|
}),
|
|
5260
|
-
envoy_unsubscribe:
|
|
5901
|
+
envoy_unsubscribe: tool({
|
|
5261
5902
|
description: unsubscribeSpec.description,
|
|
5262
|
-
args: { topics:
|
|
5903
|
+
args: { topics: tool.schema.array(tool.schema.string()).optional() },
|
|
5263
5904
|
async execute(args, ctx) {
|
|
5264
5905
|
ctx.metadata({ title: "Envoy unsubscribe" });
|
|
5265
5906
|
await envoy.unsubscribe({ sessionID: ctx.sessionID, topics: args.topics ?? [] });
|
|
5266
5907
|
return "ok";
|
|
5267
5908
|
}
|
|
5268
5909
|
}),
|
|
5269
|
-
envoy_list:
|
|
5910
|
+
envoy_list: tool({
|
|
5270
5911
|
description: listSpec.description,
|
|
5271
5912
|
args: {},
|
|
5272
5913
|
async execute(_args, ctx) {
|
|
@@ -5274,9 +5915,9 @@ var server_default = async (input) => {
|
|
|
5274
5915
|
return JSON.stringify(await envoy.getInterest(ctx.sessionID));
|
|
5275
5916
|
}
|
|
5276
5917
|
}),
|
|
5277
|
-
envoy_send:
|
|
5918
|
+
envoy_send: tool({
|
|
5278
5919
|
description: sendSpec.description,
|
|
5279
|
-
args: { session_id:
|
|
5920
|
+
args: { session_id: tool.schema.string(), message: tool.schema.string() },
|
|
5280
5921
|
async execute(args, ctx) {
|
|
5281
5922
|
ctx.metadata({ title: "Envoy send" });
|
|
5282
5923
|
return JSON.stringify(await envoy.send({
|
|
@@ -5286,9 +5927,9 @@ var server_default = async (input) => {
|
|
|
5286
5927
|
}));
|
|
5287
5928
|
}
|
|
5288
5929
|
}),
|
|
5289
|
-
envoy_publish:
|
|
5930
|
+
envoy_publish: tool({
|
|
5290
5931
|
description: publishSpec.description,
|
|
5291
|
-
args: { topic:
|
|
5932
|
+
args: { topic: tool.schema.string(), message: tool.schema.string() },
|
|
5292
5933
|
async execute(args, ctx) {
|
|
5293
5934
|
ctx.metadata({ title: "Envoy publish" });
|
|
5294
5935
|
return JSON.stringify(await envoy.publish({
|
|
@@ -5298,15 +5939,15 @@ var server_default = async (input) => {
|
|
|
5298
5939
|
}));
|
|
5299
5940
|
}
|
|
5300
5941
|
}),
|
|
5301
|
-
envoy_role_set:
|
|
5942
|
+
envoy_role_set: tool({
|
|
5302
5943
|
description: roleSetSpec.description,
|
|
5303
|
-
args: { role:
|
|
5944
|
+
args: { role: tool.schema.string() },
|
|
5304
5945
|
async execute(args, ctx) {
|
|
5305
5946
|
ctx.metadata({ title: "Set Envoy role" });
|
|
5306
5947
|
return JSON.stringify(await envoy.setRole({ sessionID: ctx.sessionID, role: args.role }));
|
|
5307
5948
|
}
|
|
5308
5949
|
}),
|
|
5309
|
-
envoy_whoami:
|
|
5950
|
+
envoy_whoami: tool({
|
|
5310
5951
|
description: whoamiSpec.description,
|
|
5311
5952
|
args: {},
|
|
5312
5953
|
async execute(_args, ctx) {
|
|
@@ -5321,9 +5962,9 @@ var server_default = async (input) => {
|
|
|
5321
5962
|
}, null, 2);
|
|
5322
5963
|
}
|
|
5323
5964
|
}),
|
|
5324
|
-
envoy_sessions:
|
|
5965
|
+
envoy_sessions: tool({
|
|
5325
5966
|
description: sessionsSpec.description,
|
|
5326
|
-
args: { machine:
|
|
5967
|
+
args: { machine: tool.schema.string().optional() },
|
|
5327
5968
|
async execute(args, ctx) {
|
|
5328
5969
|
ctx.metadata({ title: "Envoy sessions" });
|
|
5329
5970
|
const sessions = await envoy.listSessions();
|