@sjawhar/pi-legion-envoy 1.59.0 → 1.60.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/dist/envoy.js +40 -0
- package/dist/legion.js +1138 -37
- package/package.json +3 -2
package/dist/envoy.js
CHANGED
|
@@ -34632,6 +34632,40 @@ function onEnvoyRoleRegained(listener) {
|
|
|
34632
34632
|
legionRoleClaimBridge().regained = listener;
|
|
34633
34633
|
}
|
|
34634
34634
|
|
|
34635
|
+
// src/subagent-session.ts
|
|
34636
|
+
import fs from "fs";
|
|
34637
|
+
import path2 from "path";
|
|
34638
|
+
import * as host from "@oh-my-pi/pi-coding-agent";
|
|
34639
|
+
var LEGION_BOOTSTRAPPED_SESSION = Symbol.for("legion.pi-envoy.bootstrapped-session");
|
|
34640
|
+
var bootstrappedSessionStore = globalThis;
|
|
34641
|
+
function recordBootstrappedSession(sessionFile) {
|
|
34642
|
+
bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION] = sessionFile;
|
|
34643
|
+
}
|
|
34644
|
+
async function isSubagentSession(context) {
|
|
34645
|
+
await context.sessionManager.ensureOnDisk();
|
|
34646
|
+
const sessionFile = context.sessionManager.getSessionFile();
|
|
34647
|
+
if (sessionFile !== undefined && fs.existsSync(sessionFile)) {
|
|
34648
|
+
return fs.existsSync(`${path2.dirname(sessionFile)}.jsonl`);
|
|
34649
|
+
}
|
|
34650
|
+
const bootstrapped = bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION];
|
|
34651
|
+
return bootstrapped !== undefined && bootstrapped !== sessionFile;
|
|
34652
|
+
}
|
|
34653
|
+
function isRegisteredSubagent(context) {
|
|
34654
|
+
const registry = host.AgentRegistry?.global();
|
|
34655
|
+
if (registry === undefined)
|
|
34656
|
+
return false;
|
|
34657
|
+
const sessionID = context.sessionManager.getSessionId();
|
|
34658
|
+
const sessionFile = context.sessionManager.getSessionFile();
|
|
34659
|
+
return registry.list().some((ref) => ref.kind !== "main" && (ref.session === null ? sessionFile !== undefined && ref.sessionFile === sessionFile : ref.session.sessionManager.getSessionId() === sessionID));
|
|
34660
|
+
}
|
|
34661
|
+
function subagentSessionCheck() {
|
|
34662
|
+
let subagentSession;
|
|
34663
|
+
return (context) => {
|
|
34664
|
+
subagentSession ??= isSubagentSession(context);
|
|
34665
|
+
return subagentSession;
|
|
34666
|
+
};
|
|
34667
|
+
}
|
|
34668
|
+
|
|
34635
34669
|
// src/tool-result.ts
|
|
34636
34670
|
function toolSuccess(text, details = {}) {
|
|
34637
34671
|
return { content: [{ type: "text", text }], details };
|
|
@@ -35133,7 +35167,11 @@ function envoyExtension(pi) {
|
|
|
35133
35167
|
sessionID: () => activeSessionContext?.sessionManager.getSessionId() ?? sessionID
|
|
35134
35168
|
};
|
|
35135
35169
|
bridge.instances.push(claimInstance);
|
|
35170
|
+
const isSubagentTranscript = subagentSessionCheck();
|
|
35171
|
+
const isSubagent = async (context) => await isSubagentTranscript(context) || isRegisteredSubagent(context);
|
|
35136
35172
|
pi.on("session_start", async (_event, context) => {
|
|
35173
|
+
if (await isSubagent(context))
|
|
35174
|
+
return;
|
|
35137
35175
|
const previousSessionID = sessionID;
|
|
35138
35176
|
restoreLocalSessionState(context);
|
|
35139
35177
|
if (dispatchConfig.error !== null) {
|
|
@@ -35169,6 +35207,8 @@ function envoyExtension(pi) {
|
|
|
35169
35207
|
}
|
|
35170
35208
|
});
|
|
35171
35209
|
const rebind = async (reason, context) => {
|
|
35210
|
+
if (await isSubagent(context))
|
|
35211
|
+
return;
|
|
35172
35212
|
const previousID = sessionID;
|
|
35173
35213
|
restoreLocalSessionState(context);
|
|
35174
35214
|
if (defaults.natsUrls.length === 0)
|
package/dist/legion.js
CHANGED
|
@@ -16113,8 +16113,7 @@ var require_mod4 = __commonJS(function(exports) {
|
|
|
16113
16113
|
|
|
16114
16114
|
// extensions/legion.ts
|
|
16115
16115
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
16116
|
-
import
|
|
16117
|
-
import path3 from "path";
|
|
16116
|
+
import path4 from "path";
|
|
16118
16117
|
|
|
16119
16118
|
// ../envoy-client/src/defaults.ts
|
|
16120
16119
|
var DEFAULT_ENVOY_URL = "http://127.0.0.1:9020";
|
|
@@ -16145,7 +16144,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
16145
16144
|
// package.json
|
|
16146
16145
|
var package_default = {
|
|
16147
16146
|
name: "@sjawhar/pi-legion-envoy",
|
|
16148
|
-
version: "1.
|
|
16147
|
+
version: "1.60.0",
|
|
16149
16148
|
type: "module",
|
|
16150
16149
|
omp: {
|
|
16151
16150
|
extensions: [
|
|
@@ -16157,7 +16156,8 @@ var package_default = {
|
|
|
16157
16156
|
]
|
|
16158
16157
|
},
|
|
16159
16158
|
legion: {
|
|
16160
|
-
daemonApiVersion: 8
|
|
16159
|
+
daemonApiVersion: 8,
|
|
16160
|
+
goDaemonApiVersion: 1
|
|
16161
16161
|
},
|
|
16162
16162
|
repository: {
|
|
16163
16163
|
type: "git",
|
|
@@ -16188,6 +16188,247 @@ var package_default = {
|
|
|
16188
16188
|
}
|
|
16189
16189
|
};
|
|
16190
16190
|
|
|
16191
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
16192
|
+
var exports_external = {};
|
|
16193
|
+
__export(exports_external, {
|
|
16194
|
+
$brand: () => $brand,
|
|
16195
|
+
$input: () => $input,
|
|
16196
|
+
$output: () => $output,
|
|
16197
|
+
NEVER: () => NEVER,
|
|
16198
|
+
TimePrecision: () => TimePrecision,
|
|
16199
|
+
ZodAny: () => ZodAny,
|
|
16200
|
+
ZodArray: () => ZodArray,
|
|
16201
|
+
ZodBase64: () => ZodBase64,
|
|
16202
|
+
ZodBase64URL: () => ZodBase64URL,
|
|
16203
|
+
ZodBigInt: () => ZodBigInt,
|
|
16204
|
+
ZodBigIntFormat: () => ZodBigIntFormat,
|
|
16205
|
+
ZodBoolean: () => ZodBoolean,
|
|
16206
|
+
ZodCIDRv4: () => ZodCIDRv4,
|
|
16207
|
+
ZodCIDRv6: () => ZodCIDRv6,
|
|
16208
|
+
ZodCUID: () => ZodCUID,
|
|
16209
|
+
ZodCUID2: () => ZodCUID2,
|
|
16210
|
+
ZodCatch: () => ZodCatch,
|
|
16211
|
+
ZodCodec: () => ZodCodec,
|
|
16212
|
+
ZodCustom: () => ZodCustom,
|
|
16213
|
+
ZodCustomStringFormat: () => ZodCustomStringFormat,
|
|
16214
|
+
ZodDate: () => ZodDate,
|
|
16215
|
+
ZodDefault: () => ZodDefault,
|
|
16216
|
+
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
16217
|
+
ZodE164: () => ZodE164,
|
|
16218
|
+
ZodEmail: () => ZodEmail,
|
|
16219
|
+
ZodEmoji: () => ZodEmoji,
|
|
16220
|
+
ZodEnum: () => ZodEnum,
|
|
16221
|
+
ZodError: () => ZodError,
|
|
16222
|
+
ZodExactOptional: () => ZodExactOptional,
|
|
16223
|
+
ZodFile: () => ZodFile,
|
|
16224
|
+
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
16225
|
+
ZodFunction: () => ZodFunction,
|
|
16226
|
+
ZodGUID: () => ZodGUID,
|
|
16227
|
+
ZodIPv4: () => ZodIPv4,
|
|
16228
|
+
ZodIPv6: () => ZodIPv6,
|
|
16229
|
+
ZodISODate: () => ZodISODate,
|
|
16230
|
+
ZodISODateTime: () => ZodISODateTime,
|
|
16231
|
+
ZodISODuration: () => ZodISODuration,
|
|
16232
|
+
ZodISOTime: () => ZodISOTime,
|
|
16233
|
+
ZodIntersection: () => ZodIntersection,
|
|
16234
|
+
ZodIssueCode: () => ZodIssueCode,
|
|
16235
|
+
ZodJWT: () => ZodJWT,
|
|
16236
|
+
ZodKSUID: () => ZodKSUID,
|
|
16237
|
+
ZodLazy: () => ZodLazy,
|
|
16238
|
+
ZodLiteral: () => ZodLiteral,
|
|
16239
|
+
ZodMAC: () => ZodMAC,
|
|
16240
|
+
ZodMap: () => ZodMap,
|
|
16241
|
+
ZodNaN: () => ZodNaN,
|
|
16242
|
+
ZodNanoID: () => ZodNanoID,
|
|
16243
|
+
ZodNever: () => ZodNever,
|
|
16244
|
+
ZodNonOptional: () => ZodNonOptional,
|
|
16245
|
+
ZodNull: () => ZodNull,
|
|
16246
|
+
ZodNullable: () => ZodNullable,
|
|
16247
|
+
ZodNumber: () => ZodNumber,
|
|
16248
|
+
ZodNumberFormat: () => ZodNumberFormat,
|
|
16249
|
+
ZodObject: () => ZodObject,
|
|
16250
|
+
ZodOptional: () => ZodOptional,
|
|
16251
|
+
ZodPipe: () => ZodPipe,
|
|
16252
|
+
ZodPrefault: () => ZodPrefault,
|
|
16253
|
+
ZodPromise: () => ZodPromise,
|
|
16254
|
+
ZodReadonly: () => ZodReadonly,
|
|
16255
|
+
ZodRealError: () => ZodRealError,
|
|
16256
|
+
ZodRecord: () => ZodRecord,
|
|
16257
|
+
ZodSet: () => ZodSet,
|
|
16258
|
+
ZodString: () => ZodString,
|
|
16259
|
+
ZodStringFormat: () => ZodStringFormat,
|
|
16260
|
+
ZodSuccess: () => ZodSuccess,
|
|
16261
|
+
ZodSymbol: () => ZodSymbol,
|
|
16262
|
+
ZodTemplateLiteral: () => ZodTemplateLiteral,
|
|
16263
|
+
ZodTransform: () => ZodTransform,
|
|
16264
|
+
ZodTuple: () => ZodTuple,
|
|
16265
|
+
ZodType: () => ZodType,
|
|
16266
|
+
ZodULID: () => ZodULID,
|
|
16267
|
+
ZodURL: () => ZodURL,
|
|
16268
|
+
ZodUUID: () => ZodUUID,
|
|
16269
|
+
ZodUndefined: () => ZodUndefined,
|
|
16270
|
+
ZodUnion: () => ZodUnion,
|
|
16271
|
+
ZodUnknown: () => ZodUnknown,
|
|
16272
|
+
ZodVoid: () => ZodVoid,
|
|
16273
|
+
ZodXID: () => ZodXID,
|
|
16274
|
+
ZodXor: () => ZodXor,
|
|
16275
|
+
_ZodString: () => _ZodString,
|
|
16276
|
+
_default: () => _default2,
|
|
16277
|
+
_function: () => _function,
|
|
16278
|
+
any: () => any,
|
|
16279
|
+
array: () => array,
|
|
16280
|
+
base64: () => base642,
|
|
16281
|
+
base64url: () => base64url2,
|
|
16282
|
+
bigint: () => bigint2,
|
|
16283
|
+
boolean: () => boolean2,
|
|
16284
|
+
catch: () => _catch2,
|
|
16285
|
+
check: () => check,
|
|
16286
|
+
cidrv4: () => cidrv42,
|
|
16287
|
+
cidrv6: () => cidrv62,
|
|
16288
|
+
clone: () => clone,
|
|
16289
|
+
codec: () => codec,
|
|
16290
|
+
coerce: () => exports_coerce,
|
|
16291
|
+
config: () => config,
|
|
16292
|
+
core: () => exports_core2,
|
|
16293
|
+
cuid: () => cuid3,
|
|
16294
|
+
cuid2: () => cuid22,
|
|
16295
|
+
custom: () => custom,
|
|
16296
|
+
date: () => date3,
|
|
16297
|
+
decode: () => decode2,
|
|
16298
|
+
decodeAsync: () => decodeAsync2,
|
|
16299
|
+
describe: () => describe2,
|
|
16300
|
+
discriminatedUnion: () => discriminatedUnion,
|
|
16301
|
+
e164: () => e1642,
|
|
16302
|
+
email: () => email2,
|
|
16303
|
+
emoji: () => emoji2,
|
|
16304
|
+
encode: () => encode2,
|
|
16305
|
+
encodeAsync: () => encodeAsync2,
|
|
16306
|
+
endsWith: () => _endsWith,
|
|
16307
|
+
enum: () => _enum2,
|
|
16308
|
+
exactOptional: () => exactOptional,
|
|
16309
|
+
file: () => file,
|
|
16310
|
+
flattenError: () => flattenError,
|
|
16311
|
+
float32: () => float32,
|
|
16312
|
+
float64: () => float64,
|
|
16313
|
+
formatError: () => formatError,
|
|
16314
|
+
fromJSONSchema: () => fromJSONSchema,
|
|
16315
|
+
function: () => _function,
|
|
16316
|
+
getErrorMap: () => getErrorMap,
|
|
16317
|
+
globalRegistry: () => globalRegistry,
|
|
16318
|
+
gt: () => _gt,
|
|
16319
|
+
gte: () => _gte,
|
|
16320
|
+
guid: () => guid2,
|
|
16321
|
+
hash: () => hash,
|
|
16322
|
+
hex: () => hex2,
|
|
16323
|
+
hostname: () => hostname2,
|
|
16324
|
+
httpUrl: () => httpUrl,
|
|
16325
|
+
includes: () => _includes,
|
|
16326
|
+
instanceof: () => _instanceof,
|
|
16327
|
+
int: () => int,
|
|
16328
|
+
int32: () => int32,
|
|
16329
|
+
int64: () => int64,
|
|
16330
|
+
intersection: () => intersection,
|
|
16331
|
+
ipv4: () => ipv42,
|
|
16332
|
+
ipv6: () => ipv62,
|
|
16333
|
+
iso: () => exports_iso,
|
|
16334
|
+
json: () => json,
|
|
16335
|
+
jwt: () => jwt,
|
|
16336
|
+
keyof: () => keyof,
|
|
16337
|
+
ksuid: () => ksuid2,
|
|
16338
|
+
lazy: () => lazy,
|
|
16339
|
+
length: () => _length,
|
|
16340
|
+
literal: () => literal,
|
|
16341
|
+
locales: () => exports_locales,
|
|
16342
|
+
looseObject: () => looseObject,
|
|
16343
|
+
looseRecord: () => looseRecord,
|
|
16344
|
+
lowercase: () => _lowercase,
|
|
16345
|
+
lt: () => _lt,
|
|
16346
|
+
lte: () => _lte,
|
|
16347
|
+
mac: () => mac2,
|
|
16348
|
+
map: () => map,
|
|
16349
|
+
maxLength: () => _maxLength,
|
|
16350
|
+
maxSize: () => _maxSize,
|
|
16351
|
+
meta: () => meta2,
|
|
16352
|
+
mime: () => _mime,
|
|
16353
|
+
minLength: () => _minLength,
|
|
16354
|
+
minSize: () => _minSize,
|
|
16355
|
+
multipleOf: () => _multipleOf,
|
|
16356
|
+
nan: () => nan,
|
|
16357
|
+
nanoid: () => nanoid2,
|
|
16358
|
+
nativeEnum: () => nativeEnum,
|
|
16359
|
+
negative: () => _negative,
|
|
16360
|
+
never: () => never,
|
|
16361
|
+
nonnegative: () => _nonnegative,
|
|
16362
|
+
nonoptional: () => nonoptional,
|
|
16363
|
+
nonpositive: () => _nonpositive,
|
|
16364
|
+
normalize: () => _normalize,
|
|
16365
|
+
null: () => _null3,
|
|
16366
|
+
nullable: () => nullable,
|
|
16367
|
+
nullish: () => nullish2,
|
|
16368
|
+
number: () => number2,
|
|
16369
|
+
object: () => object,
|
|
16370
|
+
optional: () => optional,
|
|
16371
|
+
overwrite: () => _overwrite,
|
|
16372
|
+
parse: () => parse3,
|
|
16373
|
+
parseAsync: () => parseAsync2,
|
|
16374
|
+
partialRecord: () => partialRecord,
|
|
16375
|
+
pipe: () => pipe,
|
|
16376
|
+
positive: () => _positive,
|
|
16377
|
+
prefault: () => prefault,
|
|
16378
|
+
preprocess: () => preprocess,
|
|
16379
|
+
prettifyError: () => prettifyError,
|
|
16380
|
+
promise: () => promise,
|
|
16381
|
+
property: () => _property,
|
|
16382
|
+
readonly: () => readonly,
|
|
16383
|
+
record: () => record,
|
|
16384
|
+
refine: () => refine,
|
|
16385
|
+
regex: () => _regex,
|
|
16386
|
+
regexes: () => exports_regexes,
|
|
16387
|
+
registry: () => registry,
|
|
16388
|
+
safeDecode: () => safeDecode2,
|
|
16389
|
+
safeDecodeAsync: () => safeDecodeAsync2,
|
|
16390
|
+
safeEncode: () => safeEncode2,
|
|
16391
|
+
safeEncodeAsync: () => safeEncodeAsync2,
|
|
16392
|
+
safeParse: () => safeParse2,
|
|
16393
|
+
safeParseAsync: () => safeParseAsync2,
|
|
16394
|
+
set: () => set,
|
|
16395
|
+
setErrorMap: () => setErrorMap,
|
|
16396
|
+
size: () => _size,
|
|
16397
|
+
slugify: () => _slugify,
|
|
16398
|
+
startsWith: () => _startsWith,
|
|
16399
|
+
strictObject: () => strictObject,
|
|
16400
|
+
string: () => string2,
|
|
16401
|
+
stringFormat: () => stringFormat,
|
|
16402
|
+
stringbool: () => stringbool,
|
|
16403
|
+
success: () => success,
|
|
16404
|
+
superRefine: () => superRefine,
|
|
16405
|
+
symbol: () => symbol,
|
|
16406
|
+
templateLiteral: () => templateLiteral,
|
|
16407
|
+
toJSONSchema: () => toJSONSchema,
|
|
16408
|
+
toLowerCase: () => _toLowerCase,
|
|
16409
|
+
toUpperCase: () => _toUpperCase,
|
|
16410
|
+
transform: () => transform,
|
|
16411
|
+
treeifyError: () => treeifyError,
|
|
16412
|
+
trim: () => _trim,
|
|
16413
|
+
tuple: () => tuple,
|
|
16414
|
+
uint32: () => uint32,
|
|
16415
|
+
uint64: () => uint64,
|
|
16416
|
+
ulid: () => ulid2,
|
|
16417
|
+
undefined: () => _undefined3,
|
|
16418
|
+
union: () => union,
|
|
16419
|
+
unknown: () => unknown,
|
|
16420
|
+
uppercase: () => _uppercase,
|
|
16421
|
+
url: () => url,
|
|
16422
|
+
util: () => exports_util,
|
|
16423
|
+
uuid: () => uuid2,
|
|
16424
|
+
uuidv4: () => uuidv4,
|
|
16425
|
+
uuidv6: () => uuidv6,
|
|
16426
|
+
uuidv7: () => uuidv7,
|
|
16427
|
+
void: () => _void2,
|
|
16428
|
+
xid: () => xid2,
|
|
16429
|
+
xor: () => xor
|
|
16430
|
+
});
|
|
16431
|
+
|
|
16191
16432
|
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/index.js
|
|
16192
16433
|
var exports_core2 = {};
|
|
16193
16434
|
__export(exports_core2, {
|
|
@@ -28967,6 +29208,518 @@ function json(params) {
|
|
|
28967
29208
|
function preprocess(fn, schema) {
|
|
28968
29209
|
return pipe(transform(fn), schema);
|
|
28969
29210
|
}
|
|
29211
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/compat.js
|
|
29212
|
+
var ZodIssueCode = {
|
|
29213
|
+
invalid_type: "invalid_type",
|
|
29214
|
+
too_big: "too_big",
|
|
29215
|
+
too_small: "too_small",
|
|
29216
|
+
invalid_format: "invalid_format",
|
|
29217
|
+
not_multiple_of: "not_multiple_of",
|
|
29218
|
+
unrecognized_keys: "unrecognized_keys",
|
|
29219
|
+
invalid_union: "invalid_union",
|
|
29220
|
+
invalid_key: "invalid_key",
|
|
29221
|
+
invalid_element: "invalid_element",
|
|
29222
|
+
invalid_value: "invalid_value",
|
|
29223
|
+
custom: "custom"
|
|
29224
|
+
};
|
|
29225
|
+
function setErrorMap(map) {
|
|
29226
|
+
config({
|
|
29227
|
+
customError: map
|
|
29228
|
+
});
|
|
29229
|
+
}
|
|
29230
|
+
function getErrorMap() {
|
|
29231
|
+
return config().customError;
|
|
29232
|
+
}
|
|
29233
|
+
var ZodFirstPartyTypeKind;
|
|
29234
|
+
(function(ZodFirstPartyTypeKind) {})(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
|
|
29235
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/from-json-schema.js
|
|
29236
|
+
var z = {
|
|
29237
|
+
...exports_schemas2,
|
|
29238
|
+
...exports_checks2,
|
|
29239
|
+
iso: exports_iso
|
|
29240
|
+
};
|
|
29241
|
+
var RECOGNIZED_KEYS = new Set([
|
|
29242
|
+
"$schema",
|
|
29243
|
+
"$ref",
|
|
29244
|
+
"$defs",
|
|
29245
|
+
"definitions",
|
|
29246
|
+
"$id",
|
|
29247
|
+
"id",
|
|
29248
|
+
"$comment",
|
|
29249
|
+
"$anchor",
|
|
29250
|
+
"$vocabulary",
|
|
29251
|
+
"$dynamicRef",
|
|
29252
|
+
"$dynamicAnchor",
|
|
29253
|
+
"type",
|
|
29254
|
+
"enum",
|
|
29255
|
+
"const",
|
|
29256
|
+
"anyOf",
|
|
29257
|
+
"oneOf",
|
|
29258
|
+
"allOf",
|
|
29259
|
+
"not",
|
|
29260
|
+
"properties",
|
|
29261
|
+
"required",
|
|
29262
|
+
"additionalProperties",
|
|
29263
|
+
"patternProperties",
|
|
29264
|
+
"propertyNames",
|
|
29265
|
+
"minProperties",
|
|
29266
|
+
"maxProperties",
|
|
29267
|
+
"items",
|
|
29268
|
+
"prefixItems",
|
|
29269
|
+
"additionalItems",
|
|
29270
|
+
"minItems",
|
|
29271
|
+
"maxItems",
|
|
29272
|
+
"uniqueItems",
|
|
29273
|
+
"contains",
|
|
29274
|
+
"minContains",
|
|
29275
|
+
"maxContains",
|
|
29276
|
+
"minLength",
|
|
29277
|
+
"maxLength",
|
|
29278
|
+
"pattern",
|
|
29279
|
+
"format",
|
|
29280
|
+
"minimum",
|
|
29281
|
+
"maximum",
|
|
29282
|
+
"exclusiveMinimum",
|
|
29283
|
+
"exclusiveMaximum",
|
|
29284
|
+
"multipleOf",
|
|
29285
|
+
"description",
|
|
29286
|
+
"default",
|
|
29287
|
+
"contentEncoding",
|
|
29288
|
+
"contentMediaType",
|
|
29289
|
+
"contentSchema",
|
|
29290
|
+
"unevaluatedItems",
|
|
29291
|
+
"unevaluatedProperties",
|
|
29292
|
+
"if",
|
|
29293
|
+
"then",
|
|
29294
|
+
"else",
|
|
29295
|
+
"dependentSchemas",
|
|
29296
|
+
"dependentRequired",
|
|
29297
|
+
"nullable",
|
|
29298
|
+
"readOnly"
|
|
29299
|
+
]);
|
|
29300
|
+
function detectVersion(schema, defaultTarget) {
|
|
29301
|
+
const $schema = schema.$schema;
|
|
29302
|
+
if ($schema === "https://json-schema.org/draft/2020-12/schema") {
|
|
29303
|
+
return "draft-2020-12";
|
|
29304
|
+
}
|
|
29305
|
+
if ($schema === "http://json-schema.org/draft-07/schema#") {
|
|
29306
|
+
return "draft-7";
|
|
29307
|
+
}
|
|
29308
|
+
if ($schema === "http://json-schema.org/draft-04/schema#") {
|
|
29309
|
+
return "draft-4";
|
|
29310
|
+
}
|
|
29311
|
+
return defaultTarget ?? "draft-2020-12";
|
|
29312
|
+
}
|
|
29313
|
+
function resolveRef(ref, ctx) {
|
|
29314
|
+
if (!ref.startsWith("#")) {
|
|
29315
|
+
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
29316
|
+
}
|
|
29317
|
+
const path = ref.slice(1).split("/").filter(Boolean);
|
|
29318
|
+
if (path.length === 0) {
|
|
29319
|
+
return ctx.rootSchema;
|
|
29320
|
+
}
|
|
29321
|
+
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
29322
|
+
if (path[0] === defsKey) {
|
|
29323
|
+
const key = path[1];
|
|
29324
|
+
if (!key || !ctx.defs[key]) {
|
|
29325
|
+
throw new Error(`Reference not found: ${ref}`);
|
|
29326
|
+
}
|
|
29327
|
+
return ctx.defs[key];
|
|
29328
|
+
}
|
|
29329
|
+
throw new Error(`Reference not found: ${ref}`);
|
|
29330
|
+
}
|
|
29331
|
+
function convertBaseSchema(schema, ctx) {
|
|
29332
|
+
if (schema.not !== undefined) {
|
|
29333
|
+
if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) {
|
|
29334
|
+
return z.never();
|
|
29335
|
+
}
|
|
29336
|
+
throw new Error("not is not supported in Zod (except { not: {} } for never)");
|
|
29337
|
+
}
|
|
29338
|
+
if (schema.unevaluatedItems !== undefined) {
|
|
29339
|
+
throw new Error("unevaluatedItems is not supported");
|
|
29340
|
+
}
|
|
29341
|
+
if (schema.unevaluatedProperties !== undefined) {
|
|
29342
|
+
throw new Error("unevaluatedProperties is not supported");
|
|
29343
|
+
}
|
|
29344
|
+
if (schema.if !== undefined || schema.then !== undefined || schema.else !== undefined) {
|
|
29345
|
+
throw new Error("Conditional schemas (if/then/else) are not supported");
|
|
29346
|
+
}
|
|
29347
|
+
if (schema.dependentSchemas !== undefined || schema.dependentRequired !== undefined) {
|
|
29348
|
+
throw new Error("dependentSchemas and dependentRequired are not supported");
|
|
29349
|
+
}
|
|
29350
|
+
if (schema.$ref) {
|
|
29351
|
+
const refPath = schema.$ref;
|
|
29352
|
+
if (ctx.refs.has(refPath)) {
|
|
29353
|
+
return ctx.refs.get(refPath);
|
|
29354
|
+
}
|
|
29355
|
+
if (ctx.processing.has(refPath)) {
|
|
29356
|
+
return z.lazy(() => {
|
|
29357
|
+
if (!ctx.refs.has(refPath)) {
|
|
29358
|
+
throw new Error(`Circular reference not resolved: ${refPath}`);
|
|
29359
|
+
}
|
|
29360
|
+
return ctx.refs.get(refPath);
|
|
29361
|
+
});
|
|
29362
|
+
}
|
|
29363
|
+
ctx.processing.add(refPath);
|
|
29364
|
+
const resolved = resolveRef(refPath, ctx);
|
|
29365
|
+
const zodSchema = convertSchema(resolved, ctx);
|
|
29366
|
+
ctx.refs.set(refPath, zodSchema);
|
|
29367
|
+
ctx.processing.delete(refPath);
|
|
29368
|
+
return zodSchema;
|
|
29369
|
+
}
|
|
29370
|
+
if (schema.enum !== undefined) {
|
|
29371
|
+
const enumValues = schema.enum;
|
|
29372
|
+
if (ctx.version === "openapi-3.0" && schema.nullable === true && enumValues.length === 1 && enumValues[0] === null) {
|
|
29373
|
+
return z.null();
|
|
29374
|
+
}
|
|
29375
|
+
if (enumValues.length === 0) {
|
|
29376
|
+
return z.never();
|
|
29377
|
+
}
|
|
29378
|
+
if (enumValues.length === 1) {
|
|
29379
|
+
return z.literal(enumValues[0]);
|
|
29380
|
+
}
|
|
29381
|
+
if (enumValues.every((v) => typeof v === "string")) {
|
|
29382
|
+
return z.enum(enumValues);
|
|
29383
|
+
}
|
|
29384
|
+
const literalSchemas = enumValues.map((v) => z.literal(v));
|
|
29385
|
+
if (literalSchemas.length < 2) {
|
|
29386
|
+
return literalSchemas[0];
|
|
29387
|
+
}
|
|
29388
|
+
return z.union([literalSchemas[0], literalSchemas[1], ...literalSchemas.slice(2)]);
|
|
29389
|
+
}
|
|
29390
|
+
if (schema.const !== undefined) {
|
|
29391
|
+
return z.literal(schema.const);
|
|
29392
|
+
}
|
|
29393
|
+
const type = schema.type;
|
|
29394
|
+
if (Array.isArray(type)) {
|
|
29395
|
+
const typeSchemas = type.map((t) => {
|
|
29396
|
+
const typeSchema = { ...schema, type: t };
|
|
29397
|
+
return convertBaseSchema(typeSchema, ctx);
|
|
29398
|
+
});
|
|
29399
|
+
if (typeSchemas.length === 0) {
|
|
29400
|
+
return z.never();
|
|
29401
|
+
}
|
|
29402
|
+
if (typeSchemas.length === 1) {
|
|
29403
|
+
return typeSchemas[0];
|
|
29404
|
+
}
|
|
29405
|
+
return z.union(typeSchemas);
|
|
29406
|
+
}
|
|
29407
|
+
if (!type) {
|
|
29408
|
+
return z.any();
|
|
29409
|
+
}
|
|
29410
|
+
let zodSchema;
|
|
29411
|
+
switch (type) {
|
|
29412
|
+
case "string": {
|
|
29413
|
+
let stringSchema = z.string();
|
|
29414
|
+
if (schema.format) {
|
|
29415
|
+
const format = schema.format;
|
|
29416
|
+
if (format === "email") {
|
|
29417
|
+
stringSchema = stringSchema.check(z.email());
|
|
29418
|
+
} else if (format === "uri" || format === "uri-reference") {
|
|
29419
|
+
stringSchema = stringSchema.check(z.url());
|
|
29420
|
+
} else if (format === "uuid" || format === "guid") {
|
|
29421
|
+
stringSchema = stringSchema.check(z.uuid());
|
|
29422
|
+
} else if (format === "date-time") {
|
|
29423
|
+
stringSchema = stringSchema.check(z.iso.datetime());
|
|
29424
|
+
} else if (format === "date") {
|
|
29425
|
+
stringSchema = stringSchema.check(z.iso.date());
|
|
29426
|
+
} else if (format === "time") {
|
|
29427
|
+
stringSchema = stringSchema.check(z.iso.time());
|
|
29428
|
+
} else if (format === "duration") {
|
|
29429
|
+
stringSchema = stringSchema.check(z.iso.duration());
|
|
29430
|
+
} else if (format === "ipv4") {
|
|
29431
|
+
stringSchema = stringSchema.check(z.ipv4());
|
|
29432
|
+
} else if (format === "ipv6") {
|
|
29433
|
+
stringSchema = stringSchema.check(z.ipv6());
|
|
29434
|
+
} else if (format === "mac") {
|
|
29435
|
+
stringSchema = stringSchema.check(z.mac());
|
|
29436
|
+
} else if (format === "cidr") {
|
|
29437
|
+
stringSchema = stringSchema.check(z.cidrv4());
|
|
29438
|
+
} else if (format === "cidr-v6") {
|
|
29439
|
+
stringSchema = stringSchema.check(z.cidrv6());
|
|
29440
|
+
} else if (format === "base64") {
|
|
29441
|
+
stringSchema = stringSchema.check(z.base64());
|
|
29442
|
+
} else if (format === "base64url") {
|
|
29443
|
+
stringSchema = stringSchema.check(z.base64url());
|
|
29444
|
+
} else if (format === "e164") {
|
|
29445
|
+
stringSchema = stringSchema.check(z.e164());
|
|
29446
|
+
} else if (format === "jwt") {
|
|
29447
|
+
stringSchema = stringSchema.check(z.jwt());
|
|
29448
|
+
} else if (format === "emoji") {
|
|
29449
|
+
stringSchema = stringSchema.check(z.emoji());
|
|
29450
|
+
} else if (format === "nanoid") {
|
|
29451
|
+
stringSchema = stringSchema.check(z.nanoid());
|
|
29452
|
+
} else if (format === "cuid") {
|
|
29453
|
+
stringSchema = stringSchema.check(z.cuid());
|
|
29454
|
+
} else if (format === "cuid2") {
|
|
29455
|
+
stringSchema = stringSchema.check(z.cuid2());
|
|
29456
|
+
} else if (format === "ulid") {
|
|
29457
|
+
stringSchema = stringSchema.check(z.ulid());
|
|
29458
|
+
} else if (format === "xid") {
|
|
29459
|
+
stringSchema = stringSchema.check(z.xid());
|
|
29460
|
+
} else if (format === "ksuid") {
|
|
29461
|
+
stringSchema = stringSchema.check(z.ksuid());
|
|
29462
|
+
}
|
|
29463
|
+
}
|
|
29464
|
+
if (typeof schema.minLength === "number") {
|
|
29465
|
+
stringSchema = stringSchema.min(schema.minLength);
|
|
29466
|
+
}
|
|
29467
|
+
if (typeof schema.maxLength === "number") {
|
|
29468
|
+
stringSchema = stringSchema.max(schema.maxLength);
|
|
29469
|
+
}
|
|
29470
|
+
if (schema.pattern) {
|
|
29471
|
+
stringSchema = stringSchema.regex(new RegExp(schema.pattern));
|
|
29472
|
+
}
|
|
29473
|
+
zodSchema = stringSchema;
|
|
29474
|
+
break;
|
|
29475
|
+
}
|
|
29476
|
+
case "number":
|
|
29477
|
+
case "integer": {
|
|
29478
|
+
let numberSchema = type === "integer" ? z.number().int() : z.number();
|
|
29479
|
+
if (typeof schema.minimum === "number") {
|
|
29480
|
+
numberSchema = numberSchema.min(schema.minimum);
|
|
29481
|
+
}
|
|
29482
|
+
if (typeof schema.maximum === "number") {
|
|
29483
|
+
numberSchema = numberSchema.max(schema.maximum);
|
|
29484
|
+
}
|
|
29485
|
+
if (typeof schema.exclusiveMinimum === "number") {
|
|
29486
|
+
numberSchema = numberSchema.gt(schema.exclusiveMinimum);
|
|
29487
|
+
} else if (schema.exclusiveMinimum === true && typeof schema.minimum === "number") {
|
|
29488
|
+
numberSchema = numberSchema.gt(schema.minimum);
|
|
29489
|
+
}
|
|
29490
|
+
if (typeof schema.exclusiveMaximum === "number") {
|
|
29491
|
+
numberSchema = numberSchema.lt(schema.exclusiveMaximum);
|
|
29492
|
+
} else if (schema.exclusiveMaximum === true && typeof schema.maximum === "number") {
|
|
29493
|
+
numberSchema = numberSchema.lt(schema.maximum);
|
|
29494
|
+
}
|
|
29495
|
+
if (typeof schema.multipleOf === "number") {
|
|
29496
|
+
numberSchema = numberSchema.multipleOf(schema.multipleOf);
|
|
29497
|
+
}
|
|
29498
|
+
zodSchema = numberSchema;
|
|
29499
|
+
break;
|
|
29500
|
+
}
|
|
29501
|
+
case "boolean": {
|
|
29502
|
+
zodSchema = z.boolean();
|
|
29503
|
+
break;
|
|
29504
|
+
}
|
|
29505
|
+
case "null": {
|
|
29506
|
+
zodSchema = z.null();
|
|
29507
|
+
break;
|
|
29508
|
+
}
|
|
29509
|
+
case "object": {
|
|
29510
|
+
const shape = {};
|
|
29511
|
+
const properties = schema.properties || {};
|
|
29512
|
+
const requiredSet = new Set(schema.required || []);
|
|
29513
|
+
for (const [key, propSchema] of Object.entries(properties)) {
|
|
29514
|
+
const propZodSchema = convertSchema(propSchema, ctx);
|
|
29515
|
+
shape[key] = requiredSet.has(key) ? propZodSchema : propZodSchema.optional();
|
|
29516
|
+
}
|
|
29517
|
+
if (schema.propertyNames) {
|
|
29518
|
+
const keySchema = convertSchema(schema.propertyNames, ctx);
|
|
29519
|
+
const valueSchema = schema.additionalProperties && typeof schema.additionalProperties === "object" ? convertSchema(schema.additionalProperties, ctx) : z.any();
|
|
29520
|
+
if (Object.keys(shape).length === 0) {
|
|
29521
|
+
zodSchema = z.record(keySchema, valueSchema);
|
|
29522
|
+
break;
|
|
29523
|
+
}
|
|
29524
|
+
const objectSchema = z.object(shape).passthrough();
|
|
29525
|
+
const recordSchema = z.looseRecord(keySchema, valueSchema);
|
|
29526
|
+
zodSchema = z.intersection(objectSchema, recordSchema);
|
|
29527
|
+
break;
|
|
29528
|
+
}
|
|
29529
|
+
if (schema.patternProperties) {
|
|
29530
|
+
const patternProps = schema.patternProperties;
|
|
29531
|
+
const patternKeys = Object.keys(patternProps);
|
|
29532
|
+
const looseRecords = [];
|
|
29533
|
+
for (const pattern of patternKeys) {
|
|
29534
|
+
const patternValue = convertSchema(patternProps[pattern], ctx);
|
|
29535
|
+
const keySchema = z.string().regex(new RegExp(pattern));
|
|
29536
|
+
looseRecords.push(z.looseRecord(keySchema, patternValue));
|
|
29537
|
+
}
|
|
29538
|
+
const schemasToIntersect = [];
|
|
29539
|
+
if (Object.keys(shape).length > 0) {
|
|
29540
|
+
schemasToIntersect.push(z.object(shape).passthrough());
|
|
29541
|
+
}
|
|
29542
|
+
schemasToIntersect.push(...looseRecords);
|
|
29543
|
+
if (schemasToIntersect.length === 0) {
|
|
29544
|
+
zodSchema = z.object({}).passthrough();
|
|
29545
|
+
} else if (schemasToIntersect.length === 1) {
|
|
29546
|
+
zodSchema = schemasToIntersect[0];
|
|
29547
|
+
} else {
|
|
29548
|
+
let result = z.intersection(schemasToIntersect[0], schemasToIntersect[1]);
|
|
29549
|
+
for (let i = 2;i < schemasToIntersect.length; i++) {
|
|
29550
|
+
result = z.intersection(result, schemasToIntersect[i]);
|
|
29551
|
+
}
|
|
29552
|
+
zodSchema = result;
|
|
29553
|
+
}
|
|
29554
|
+
break;
|
|
29555
|
+
}
|
|
29556
|
+
const objectSchema = z.object(shape);
|
|
29557
|
+
if (schema.additionalProperties === false) {
|
|
29558
|
+
zodSchema = objectSchema.strict();
|
|
29559
|
+
} else if (typeof schema.additionalProperties === "object") {
|
|
29560
|
+
zodSchema = objectSchema.catchall(convertSchema(schema.additionalProperties, ctx));
|
|
29561
|
+
} else {
|
|
29562
|
+
zodSchema = objectSchema.passthrough();
|
|
29563
|
+
}
|
|
29564
|
+
break;
|
|
29565
|
+
}
|
|
29566
|
+
case "array": {
|
|
29567
|
+
const prefixItems = schema.prefixItems;
|
|
29568
|
+
const items = schema.items;
|
|
29569
|
+
if (prefixItems && Array.isArray(prefixItems)) {
|
|
29570
|
+
const tupleItems = prefixItems.map((item) => convertSchema(item, ctx));
|
|
29571
|
+
const rest = items && typeof items === "object" && !Array.isArray(items) ? convertSchema(items, ctx) : undefined;
|
|
29572
|
+
if (rest) {
|
|
29573
|
+
zodSchema = z.tuple(tupleItems).rest(rest);
|
|
29574
|
+
} else {
|
|
29575
|
+
zodSchema = z.tuple(tupleItems);
|
|
29576
|
+
}
|
|
29577
|
+
if (typeof schema.minItems === "number") {
|
|
29578
|
+
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
|
29579
|
+
}
|
|
29580
|
+
if (typeof schema.maxItems === "number") {
|
|
29581
|
+
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
|
29582
|
+
}
|
|
29583
|
+
} else if (Array.isArray(items)) {
|
|
29584
|
+
const tupleItems = items.map((item) => convertSchema(item, ctx));
|
|
29585
|
+
const rest = schema.additionalItems && typeof schema.additionalItems === "object" ? convertSchema(schema.additionalItems, ctx) : undefined;
|
|
29586
|
+
if (rest) {
|
|
29587
|
+
zodSchema = z.tuple(tupleItems).rest(rest);
|
|
29588
|
+
} else {
|
|
29589
|
+
zodSchema = z.tuple(tupleItems);
|
|
29590
|
+
}
|
|
29591
|
+
if (typeof schema.minItems === "number") {
|
|
29592
|
+
zodSchema = zodSchema.check(z.minLength(schema.minItems));
|
|
29593
|
+
}
|
|
29594
|
+
if (typeof schema.maxItems === "number") {
|
|
29595
|
+
zodSchema = zodSchema.check(z.maxLength(schema.maxItems));
|
|
29596
|
+
}
|
|
29597
|
+
} else if (items !== undefined) {
|
|
29598
|
+
const element = convertSchema(items, ctx);
|
|
29599
|
+
let arraySchema = z.array(element);
|
|
29600
|
+
if (typeof schema.minItems === "number") {
|
|
29601
|
+
arraySchema = arraySchema.min(schema.minItems);
|
|
29602
|
+
}
|
|
29603
|
+
if (typeof schema.maxItems === "number") {
|
|
29604
|
+
arraySchema = arraySchema.max(schema.maxItems);
|
|
29605
|
+
}
|
|
29606
|
+
zodSchema = arraySchema;
|
|
29607
|
+
} else {
|
|
29608
|
+
zodSchema = z.array(z.any());
|
|
29609
|
+
}
|
|
29610
|
+
break;
|
|
29611
|
+
}
|
|
29612
|
+
default:
|
|
29613
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
29614
|
+
}
|
|
29615
|
+
if (schema.description) {
|
|
29616
|
+
zodSchema = zodSchema.describe(schema.description);
|
|
29617
|
+
}
|
|
29618
|
+
if (schema.default !== undefined) {
|
|
29619
|
+
zodSchema = zodSchema.default(schema.default);
|
|
29620
|
+
}
|
|
29621
|
+
return zodSchema;
|
|
29622
|
+
}
|
|
29623
|
+
function convertSchema(schema, ctx) {
|
|
29624
|
+
if (typeof schema === "boolean") {
|
|
29625
|
+
return schema ? z.any() : z.never();
|
|
29626
|
+
}
|
|
29627
|
+
let baseSchema = convertBaseSchema(schema, ctx);
|
|
29628
|
+
const hasExplicitType = schema.type || schema.enum !== undefined || schema.const !== undefined;
|
|
29629
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
29630
|
+
const options = schema.anyOf.map((s) => convertSchema(s, ctx));
|
|
29631
|
+
const anyOfUnion = z.union(options);
|
|
29632
|
+
baseSchema = hasExplicitType ? z.intersection(baseSchema, anyOfUnion) : anyOfUnion;
|
|
29633
|
+
}
|
|
29634
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
29635
|
+
const options = schema.oneOf.map((s) => convertSchema(s, ctx));
|
|
29636
|
+
const oneOfUnion = z.xor(options);
|
|
29637
|
+
baseSchema = hasExplicitType ? z.intersection(baseSchema, oneOfUnion) : oneOfUnion;
|
|
29638
|
+
}
|
|
29639
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
29640
|
+
if (schema.allOf.length === 0) {
|
|
29641
|
+
baseSchema = hasExplicitType ? baseSchema : z.any();
|
|
29642
|
+
} else {
|
|
29643
|
+
let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx);
|
|
29644
|
+
const startIdx = hasExplicitType ? 0 : 1;
|
|
29645
|
+
for (let i = startIdx;i < schema.allOf.length; i++) {
|
|
29646
|
+
result = z.intersection(result, convertSchema(schema.allOf[i], ctx));
|
|
29647
|
+
}
|
|
29648
|
+
baseSchema = result;
|
|
29649
|
+
}
|
|
29650
|
+
}
|
|
29651
|
+
if (schema.nullable === true && ctx.version === "openapi-3.0") {
|
|
29652
|
+
baseSchema = z.nullable(baseSchema);
|
|
29653
|
+
}
|
|
29654
|
+
if (schema.readOnly === true) {
|
|
29655
|
+
baseSchema = z.readonly(baseSchema);
|
|
29656
|
+
}
|
|
29657
|
+
const extraMeta = {};
|
|
29658
|
+
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
|
29659
|
+
for (const key of coreMetadataKeys) {
|
|
29660
|
+
if (key in schema) {
|
|
29661
|
+
extraMeta[key] = schema[key];
|
|
29662
|
+
}
|
|
29663
|
+
}
|
|
29664
|
+
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
|
29665
|
+
for (const key of contentMetadataKeys) {
|
|
29666
|
+
if (key in schema) {
|
|
29667
|
+
extraMeta[key] = schema[key];
|
|
29668
|
+
}
|
|
29669
|
+
}
|
|
29670
|
+
for (const key of Object.keys(schema)) {
|
|
29671
|
+
if (!RECOGNIZED_KEYS.has(key)) {
|
|
29672
|
+
extraMeta[key] = schema[key];
|
|
29673
|
+
}
|
|
29674
|
+
}
|
|
29675
|
+
if (Object.keys(extraMeta).length > 0) {
|
|
29676
|
+
ctx.registry.add(baseSchema, extraMeta);
|
|
29677
|
+
}
|
|
29678
|
+
return baseSchema;
|
|
29679
|
+
}
|
|
29680
|
+
function fromJSONSchema(schema, params) {
|
|
29681
|
+
if (typeof schema === "boolean") {
|
|
29682
|
+
return schema ? z.any() : z.never();
|
|
29683
|
+
}
|
|
29684
|
+
const version = detectVersion(schema, params?.defaultTarget);
|
|
29685
|
+
const defs = schema.$defs || schema.definitions || {};
|
|
29686
|
+
const ctx = {
|
|
29687
|
+
version,
|
|
29688
|
+
defs,
|
|
29689
|
+
refs: new Map,
|
|
29690
|
+
processing: new Set,
|
|
29691
|
+
rootSchema: schema,
|
|
29692
|
+
registry: params?.registry ?? globalRegistry
|
|
29693
|
+
};
|
|
29694
|
+
return convertSchema(schema, ctx);
|
|
29695
|
+
}
|
|
29696
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/coerce.js
|
|
29697
|
+
var exports_coerce = {};
|
|
29698
|
+
__export(exports_coerce, {
|
|
29699
|
+
bigint: () => bigint3,
|
|
29700
|
+
boolean: () => boolean3,
|
|
29701
|
+
date: () => date4,
|
|
29702
|
+
number: () => number3,
|
|
29703
|
+
string: () => string3
|
|
29704
|
+
});
|
|
29705
|
+
function string3(params) {
|
|
29706
|
+
return _coercedString(ZodString, params);
|
|
29707
|
+
}
|
|
29708
|
+
function number3(params) {
|
|
29709
|
+
return _coercedNumber(ZodNumber, params);
|
|
29710
|
+
}
|
|
29711
|
+
function boolean3(params) {
|
|
29712
|
+
return _coercedBoolean(ZodBoolean, params);
|
|
29713
|
+
}
|
|
29714
|
+
function bigint3(params) {
|
|
29715
|
+
return _coercedBigint(ZodBigInt, params);
|
|
29716
|
+
}
|
|
29717
|
+
function date4(params) {
|
|
29718
|
+
return _coercedDate(ZodDate, params);
|
|
29719
|
+
}
|
|
29720
|
+
|
|
29721
|
+
// ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
29722
|
+
config(en_default());
|
|
28970
29723
|
// ../contracts/src/dispatch-api.ts
|
|
28971
29724
|
function serviceSubjectLabel(subject) {
|
|
28972
29725
|
const parts = subject.split(":");
|
|
@@ -30500,6 +31253,220 @@ async function writeGrantFile(file, grantId) {
|
|
|
30500
31253
|
}
|
|
30501
31254
|
}
|
|
30502
31255
|
|
|
31256
|
+
// ../contracts/src/legion-go-api.ts
|
|
31257
|
+
var nonEmptyString2 = string2().min(1);
|
|
31258
|
+
var timestamp = exports_iso.datetime({ offset: true });
|
|
31259
|
+
var LEGION_GO_PHASES = [
|
|
31260
|
+
"admitted",
|
|
31261
|
+
"planning",
|
|
31262
|
+
"implementing",
|
|
31263
|
+
"testing",
|
|
31264
|
+
"reviewing",
|
|
31265
|
+
"retro",
|
|
31266
|
+
"merging",
|
|
31267
|
+
"awaiting_merge",
|
|
31268
|
+
"production_check",
|
|
31269
|
+
"done",
|
|
31270
|
+
"held"
|
|
31271
|
+
];
|
|
31272
|
+
var LEGION_GO_CLAIM_STATES = [
|
|
31273
|
+
"queued",
|
|
31274
|
+
"launch_uncertain",
|
|
31275
|
+
"launching",
|
|
31276
|
+
"shim_connected",
|
|
31277
|
+
"registered",
|
|
31278
|
+
"ready",
|
|
31279
|
+
"working",
|
|
31280
|
+
"idle",
|
|
31281
|
+
"suspended",
|
|
31282
|
+
"failed",
|
|
31283
|
+
"retired"
|
|
31284
|
+
];
|
|
31285
|
+
var legionGoLocator = discriminatedUnion("runtime", [
|
|
31286
|
+
strictObject({
|
|
31287
|
+
runtime: literal("tmux"),
|
|
31288
|
+
claim: nonEmptyString2,
|
|
31289
|
+
incarnation: nonEmptyString2,
|
|
31290
|
+
tmux: strictObject({ window: nonEmptyString2, pane: nonEmptyString2 })
|
|
31291
|
+
}),
|
|
31292
|
+
strictObject({
|
|
31293
|
+
runtime: literal("sandbox"),
|
|
31294
|
+
claim: nonEmptyString2,
|
|
31295
|
+
incarnation: nonEmptyString2,
|
|
31296
|
+
sandbox: strictObject({ namespace: nonEmptyString2, name: nonEmptyString2 })
|
|
31297
|
+
})
|
|
31298
|
+
]);
|
|
31299
|
+
var legionGoClaimView = strictObject({
|
|
31300
|
+
session: string2(),
|
|
31301
|
+
state: _enum2(LEGION_GO_CLAIM_STATES),
|
|
31302
|
+
locator: legionGoLocator.optional()
|
|
31303
|
+
});
|
|
31304
|
+
var legionGoPhaseView = strictObject({
|
|
31305
|
+
claim: legionGoClaimView,
|
|
31306
|
+
handoffCommit: nonEmptyString2.optional(),
|
|
31307
|
+
rounds: number2().int().nonnegative()
|
|
31308
|
+
});
|
|
31309
|
+
var legionGoPullRequestView = strictObject({
|
|
31310
|
+
number: number2().int().positive(),
|
|
31311
|
+
head: nonEmptyString2,
|
|
31312
|
+
checksVerdict: nonEmptyString2.optional(),
|
|
31313
|
+
reviewDecision: nonEmptyString2.optional(),
|
|
31314
|
+
fixAttempts: number2().int().nonnegative()
|
|
31315
|
+
});
|
|
31316
|
+
var legionGoGateView = strictObject({
|
|
31317
|
+
artifactId: nonEmptyString2,
|
|
31318
|
+
currentVersion: number2().int().positive(),
|
|
31319
|
+
approvedVersion: number2().int().positive().nullable()
|
|
31320
|
+
});
|
|
31321
|
+
var legionGoSlotView = strictObject({
|
|
31322
|
+
index: number2().int().nonnegative(),
|
|
31323
|
+
admittedAt: timestamp
|
|
31324
|
+
});
|
|
31325
|
+
var legionGoIssue = strictObject({
|
|
31326
|
+
key: nonEmptyString2,
|
|
31327
|
+
generation: number2().int().nonnegative(),
|
|
31328
|
+
phase: _enum2(LEGION_GO_PHASES),
|
|
31329
|
+
architect: legionGoClaimView.optional(),
|
|
31330
|
+
workers: partialRecord(_enum2(LEGION_ROLES), legionGoPhaseView),
|
|
31331
|
+
pullRequest: legionGoPullRequestView.optional(),
|
|
31332
|
+
designGate: legionGoGateView.optional(),
|
|
31333
|
+
slot: legionGoSlotView.optional()
|
|
31334
|
+
});
|
|
31335
|
+
var goDaemonInfo = strictObject({
|
|
31336
|
+
project: nonEmptyString2,
|
|
31337
|
+
schemaVersion: number2().int().nonnegative(),
|
|
31338
|
+
boots: number2().int().nonnegative(),
|
|
31339
|
+
firstBootAt: timestamp,
|
|
31340
|
+
startedAt: timestamp
|
|
31341
|
+
});
|
|
31342
|
+
var legionGoAdmission = strictObject({
|
|
31343
|
+
cap: number2().int().nonnegative(),
|
|
31344
|
+
active: array(nonEmptyString2),
|
|
31345
|
+
waiting: array(nonEmptyString2)
|
|
31346
|
+
});
|
|
31347
|
+
var LegionGoStateResponse = strictObject({
|
|
31348
|
+
daemon: goDaemonInfo,
|
|
31349
|
+
admission: legionGoAdmission,
|
|
31350
|
+
issues: record(string2(), legionGoIssue)
|
|
31351
|
+
});
|
|
31352
|
+
var LegionGoRegisterResponse = strictObject({
|
|
31353
|
+
claimToken: nonEmptyString2,
|
|
31354
|
+
tree: nonEmptyString2,
|
|
31355
|
+
issue: nonEmptyString2,
|
|
31356
|
+
role: _enum2(LEGION_ROLES),
|
|
31357
|
+
generation: number2().int().positive(),
|
|
31358
|
+
secret: nonEmptyString2
|
|
31359
|
+
});
|
|
31360
|
+
var LegionGoErrorResponse = strictObject({
|
|
31361
|
+
error: nonEmptyString2
|
|
31362
|
+
});
|
|
31363
|
+
var legionGoDeliveryView = strictObject({
|
|
31364
|
+
id: nonEmptyString2,
|
|
31365
|
+
task: nonEmptyString2,
|
|
31366
|
+
queuedAt: timestamp,
|
|
31367
|
+
deliveredAt: timestamp.optional(),
|
|
31368
|
+
confirmedAt: timestamp.optional()
|
|
31369
|
+
});
|
|
31370
|
+
var LegionGoOperatorClaimResponse = strictObject({
|
|
31371
|
+
token: nonEmptyString2,
|
|
31372
|
+
tree: nonEmptyString2,
|
|
31373
|
+
issue: nonEmptyString2,
|
|
31374
|
+
role: _enum2(LEGION_ROLES),
|
|
31375
|
+
generation: number2().int().nonnegative(),
|
|
31376
|
+
state: _enum2(LEGION_GO_CLAIM_STATES),
|
|
31377
|
+
session: string2(),
|
|
31378
|
+
sessionFile: string2(),
|
|
31379
|
+
locator: legionGoLocator.optional(),
|
|
31380
|
+
budgets: strictObject({
|
|
31381
|
+
launchFailures: number2().int().nonnegative(),
|
|
31382
|
+
promptFailures: number2().int().nonnegative(),
|
|
31383
|
+
promptRetires: number2().int().nonnegative()
|
|
31384
|
+
}),
|
|
31385
|
+
uncertainStreak: number2().int().nonnegative(),
|
|
31386
|
+
pending: legionGoDeliveryView.optional()
|
|
31387
|
+
});
|
|
31388
|
+
var LegionGoOperatorClaimsResponse = strictObject({
|
|
31389
|
+
claims: array(LegionGoOperatorClaimResponse)
|
|
31390
|
+
});
|
|
31391
|
+
|
|
31392
|
+
// src/legion/go-daemon-client.ts
|
|
31393
|
+
class LegionGoDaemonApiError extends Error {
|
|
31394
|
+
method;
|
|
31395
|
+
path;
|
|
31396
|
+
status;
|
|
31397
|
+
detail;
|
|
31398
|
+
constructor(method, path, status, detail) {
|
|
31399
|
+
super(`${method} ${path} failed with ${status}: ${detail}`);
|
|
31400
|
+
this.method = method;
|
|
31401
|
+
this.path = path;
|
|
31402
|
+
this.status = status;
|
|
31403
|
+
this.detail = detail;
|
|
31404
|
+
this.name = "LegionGoDaemonApiError";
|
|
31405
|
+
}
|
|
31406
|
+
}
|
|
31407
|
+
|
|
31408
|
+
class LegionGoDaemonContractError extends Error {
|
|
31409
|
+
method;
|
|
31410
|
+
path;
|
|
31411
|
+
status;
|
|
31412
|
+
constructor(method, path, status, problem) {
|
|
31413
|
+
super(`${method} ${path} answered ${status} with a body the Go daemon API contract does not describe: ${problem}`);
|
|
31414
|
+
this.method = method;
|
|
31415
|
+
this.path = path;
|
|
31416
|
+
this.status = status;
|
|
31417
|
+
this.name = "LegionGoDaemonContractError";
|
|
31418
|
+
}
|
|
31419
|
+
}
|
|
31420
|
+
function parseStrictly(schema, body) {
|
|
31421
|
+
let json;
|
|
31422
|
+
try {
|
|
31423
|
+
json = JSON.parse(body);
|
|
31424
|
+
} catch (error) {
|
|
31425
|
+
return { problem: `not JSON (${messageFor(error)})` };
|
|
31426
|
+
}
|
|
31427
|
+
const parsed = schema.safeParse(json);
|
|
31428
|
+
if (parsed.success)
|
|
31429
|
+
return { value: parsed.data };
|
|
31430
|
+
return {
|
|
31431
|
+
problem: parsed.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ")
|
|
31432
|
+
};
|
|
31433
|
+
}
|
|
31434
|
+
function createLegionGoDaemonClient(baseUrl, fetchFn = fetch) {
|
|
31435
|
+
const endpoint = baseUrl.replace(/\/+$/, "");
|
|
31436
|
+
const call = async (method, path, body) => {
|
|
31437
|
+
const response = await fetchFn(`${endpoint}${path}`, body === undefined ? undefined : {
|
|
31438
|
+
method,
|
|
31439
|
+
headers: { "Content-Type": "application/json" },
|
|
31440
|
+
body: JSON.stringify(body)
|
|
31441
|
+
});
|
|
31442
|
+
const text = await response.text();
|
|
31443
|
+
if (response.ok)
|
|
31444
|
+
return { status: response.status, text };
|
|
31445
|
+
const refusal = parseStrictly(LegionGoErrorResponse, text);
|
|
31446
|
+
throw new LegionGoDaemonApiError(method, path, response.status, "value" in refusal ? refusal.value.error : `${JSON.stringify(text)} is not the Go daemon's refusal shape (${refusal.problem})`);
|
|
31447
|
+
};
|
|
31448
|
+
const read = async (method, path, schema, body) => {
|
|
31449
|
+
const { status, text } = await call(method, path, body);
|
|
31450
|
+
const parsed = parseStrictly(schema, text);
|
|
31451
|
+
if ("problem" in parsed) {
|
|
31452
|
+
throw new LegionGoDaemonContractError(method, path, status, parsed.problem);
|
|
31453
|
+
}
|
|
31454
|
+
return parsed.value;
|
|
31455
|
+
};
|
|
31456
|
+
const acknowledge = async (path, body) => {
|
|
31457
|
+
const { status, text } = await call("POST", path, body);
|
|
31458
|
+
if (status !== 204 || text !== "") {
|
|
31459
|
+
throw new LegionGoDaemonContractError("POST", path, status, "the route answers 204 with no body");
|
|
31460
|
+
}
|
|
31461
|
+
};
|
|
31462
|
+
return {
|
|
31463
|
+
state: () => read("GET", "/legion/v1/state", LegionGoStateResponse),
|
|
31464
|
+
register: (input) => read("POST", "/legion/v1/claims/register", LegionGoRegisterResponse, input),
|
|
31465
|
+
ready: (input) => acknowledge("/legion/v1/claims/ready", input),
|
|
31466
|
+
exit: (input) => acknowledge("/legion/v1/claims/exit", input)
|
|
31467
|
+
};
|
|
31468
|
+
}
|
|
31469
|
+
|
|
30503
31470
|
// src/legion/jj-attribution.ts
|
|
30504
31471
|
import { execFile } from "child_process";
|
|
30505
31472
|
import { mkdir, rename as rename2, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -30547,6 +31514,114 @@ commit_trailers = '"Omp-Session: ${id}"'
|
|
|
30547
31514
|
}
|
|
30548
31515
|
}
|
|
30549
31516
|
|
|
31517
|
+
// src/legion/go-bootstrap.ts
|
|
31518
|
+
var READY_RETRY_ATTEMPTS = 3;
|
|
31519
|
+
var READY_RETRY_DELAY_MS = 1000;
|
|
31520
|
+
function isNetworkOrTimeoutError(error) {
|
|
31521
|
+
if (!(error instanceof Error))
|
|
31522
|
+
return false;
|
|
31523
|
+
if (error.name === "NetworkError" || error.name === "TimeoutError")
|
|
31524
|
+
return true;
|
|
31525
|
+
const code = "code" in error && typeof error.code === "string" ? error.code : undefined;
|
|
31526
|
+
return code === "ConnectionRefused" || code === "ConnectionTimeout" || code === "EAI_AGAIN" || code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EHOSTUNREACH" || code === "ENETUNREACH" || code === "ENOTFOUND" || code === "ETIMEDOUT" || error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed");
|
|
31527
|
+
}
|
|
31528
|
+
function exitOnGoRegistrationRefusal(error, exitProcess) {
|
|
31529
|
+
if (error instanceof LegionGoDaemonApiError) {
|
|
31530
|
+
console.error(`[legion] claims/register registration failed (${error.status}): ${error.detail}`);
|
|
31531
|
+
if (error.status >= 400 && error.status < 500)
|
|
31532
|
+
exitProcess(1);
|
|
31533
|
+
}
|
|
31534
|
+
throw error;
|
|
31535
|
+
}
|
|
31536
|
+
async function callGoReadyWithRetry(label, call) {
|
|
31537
|
+
for (let attempt = 1;; attempt++) {
|
|
31538
|
+
try {
|
|
31539
|
+
await call();
|
|
31540
|
+
return;
|
|
31541
|
+
} catch (error) {
|
|
31542
|
+
const retryable = error instanceof LegionGoDaemonApiError ? error.status >= 500 && error.status < 600 : isNetworkOrTimeoutError(error);
|
|
31543
|
+
if (!retryable)
|
|
31544
|
+
throw error;
|
|
31545
|
+
if (attempt === READY_RETRY_ATTEMPTS) {
|
|
31546
|
+
console.error(`[legion] ${label} failed after ${attempt} attempts: ${messageFor(error)}`);
|
|
31547
|
+
throw error;
|
|
31548
|
+
}
|
|
31549
|
+
console.error(`[legion] ${label} failed (attempt ${attempt}/${READY_RETRY_ATTEMPTS}), retrying: ${messageFor(error)}`);
|
|
31550
|
+
const retryDelay = Promise.withResolvers();
|
|
31551
|
+
setTimeout(retryDelay.resolve, READY_RETRY_DELAY_MS);
|
|
31552
|
+
await retryDelay.promise;
|
|
31553
|
+
}
|
|
31554
|
+
}
|
|
31555
|
+
}
|
|
31556
|
+
async function bootstrapGoClaim(context, state) {
|
|
31557
|
+
const classification = classifySession(process.env);
|
|
31558
|
+
if (classification.kind === "not-legion")
|
|
31559
|
+
return;
|
|
31560
|
+
if (classification.kind === "controller") {
|
|
31561
|
+
throw new Error("LEGION_DAEMON_API=go names the Go daemon, which launches no controller session");
|
|
31562
|
+
}
|
|
31563
|
+
const sessionID = context.sessionManager.getSessionId();
|
|
31564
|
+
const capability = state.capability();
|
|
31565
|
+
if (capability !== undefined && capability.sessionID !== sessionID)
|
|
31566
|
+
return;
|
|
31567
|
+
const existing = state.bootstrap();
|
|
31568
|
+
if (existing !== undefined)
|
|
31569
|
+
return existing;
|
|
31570
|
+
const bootToken = requiredSecret(process.env, "LEGION_BOOT_TOKEN");
|
|
31571
|
+
const daemon = createLegionGoDaemonClient(requiredEnvironment(process.env, "LEGION_DAEMON_URL"));
|
|
31572
|
+
const bootstrap = (async () => {
|
|
31573
|
+
const { sessionFile, agentId } = await state.persistedTranscript(context);
|
|
31574
|
+
state.recordBootstrappedSession(sessionFile);
|
|
31575
|
+
const claim = await daemon.register({
|
|
31576
|
+
bootToken,
|
|
31577
|
+
sessionId: sessionID,
|
|
31578
|
+
ompSessionFile: sessionFile,
|
|
31579
|
+
agentId,
|
|
31580
|
+
pluginContract: package_default.legion.goDaemonApiVersion
|
|
31581
|
+
}).catch((error) => exitOnGoRegistrationRefusal(error, state.exitProcess));
|
|
31582
|
+
const ready = {
|
|
31583
|
+
claimToken: claim.claimToken,
|
|
31584
|
+
sessionId: sessionID,
|
|
31585
|
+
secret: claim.secret,
|
|
31586
|
+
generation: claim.generation
|
|
31587
|
+
};
|
|
31588
|
+
try {
|
|
31589
|
+
await exportJjSessionAttribution(sessionFile, requiredEnvironment(process.env, "LEGION_STATE_DIR"));
|
|
31590
|
+
state.setCapability({
|
|
31591
|
+
kind: "phase-worker",
|
|
31592
|
+
sessionID,
|
|
31593
|
+
tree: claim.tree,
|
|
31594
|
+
issue: claim.issue,
|
|
31595
|
+
role: claim.role,
|
|
31596
|
+
roleToken: claim.claimToken,
|
|
31597
|
+
secret: claim.secret
|
|
31598
|
+
});
|
|
31599
|
+
await claimEnvoyRole(sessionID, claim.claimToken, context);
|
|
31600
|
+
await callGoReadyWithRetry("claims/ready", () => daemon.ready(ready));
|
|
31601
|
+
onEnvoyRoleRegained(async (role, reason) => {
|
|
31602
|
+
if (role !== claim.claimToken)
|
|
31603
|
+
return;
|
|
31604
|
+
try {
|
|
31605
|
+
await callGoReadyWithRetry("claims/ready after role regain", () => daemon.ready(ready));
|
|
31606
|
+
console.error(`[legion] re-ran claims/ready after role ${role} was ${reason}`);
|
|
31607
|
+
} catch (error) {
|
|
31608
|
+
console.error(`[legion] claims/ready after role ${role} was ${reason} failed; the daemon's queued task stays undelivered until the next regain or boot: ${messageFor(error)}`);
|
|
31609
|
+
}
|
|
31610
|
+
});
|
|
31611
|
+
} catch (error) {
|
|
31612
|
+
console.error(`[legion] Go claim boot failed after claims/register registered ${claim.claimToken}; exiting so the daemon launches it again: ${messageFor(error)}`);
|
|
31613
|
+
state.exitProcess(1);
|
|
31614
|
+
}
|
|
31615
|
+
})();
|
|
31616
|
+
state.setBootstrap(bootstrap);
|
|
31617
|
+
try {
|
|
31618
|
+
await bootstrap;
|
|
31619
|
+
} catch (error) {
|
|
31620
|
+
state.setBootstrap(undefined);
|
|
31621
|
+
throw error;
|
|
31622
|
+
}
|
|
31623
|
+
}
|
|
31624
|
+
|
|
30550
31625
|
// src/legion/tools.ts
|
|
30551
31626
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
30552
31627
|
|
|
@@ -30702,6 +31777,40 @@ function createLegionTool(deps) {
|
|
|
30702
31777
|
};
|
|
30703
31778
|
}
|
|
30704
31779
|
|
|
31780
|
+
// src/subagent-session.ts
|
|
31781
|
+
import fs from "fs";
|
|
31782
|
+
import path3 from "path";
|
|
31783
|
+
import * as host from "@oh-my-pi/pi-coding-agent";
|
|
31784
|
+
var LEGION_BOOTSTRAPPED_SESSION = Symbol.for("legion.pi-envoy.bootstrapped-session");
|
|
31785
|
+
var bootstrappedSessionStore = globalThis;
|
|
31786
|
+
function recordBootstrappedSession(sessionFile) {
|
|
31787
|
+
bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION] = sessionFile;
|
|
31788
|
+
}
|
|
31789
|
+
async function isSubagentSession(context) {
|
|
31790
|
+
await context.sessionManager.ensureOnDisk();
|
|
31791
|
+
const sessionFile = context.sessionManager.getSessionFile();
|
|
31792
|
+
if (sessionFile !== undefined && fs.existsSync(sessionFile)) {
|
|
31793
|
+
return fs.existsSync(`${path3.dirname(sessionFile)}.jsonl`);
|
|
31794
|
+
}
|
|
31795
|
+
const bootstrapped = bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION];
|
|
31796
|
+
return bootstrapped !== undefined && bootstrapped !== sessionFile;
|
|
31797
|
+
}
|
|
31798
|
+
function isRegisteredSubagent(context) {
|
|
31799
|
+
const registry = host.AgentRegistry?.global();
|
|
31800
|
+
if (registry === undefined)
|
|
31801
|
+
return false;
|
|
31802
|
+
const sessionID = context.sessionManager.getSessionId();
|
|
31803
|
+
const sessionFile = context.sessionManager.getSessionFile();
|
|
31804
|
+
return registry.list().some((ref) => ref.kind !== "main" && (ref.session === null ? sessionFile !== undefined && ref.sessionFile === sessionFile : ref.session.sessionManager.getSessionId() === sessionID));
|
|
31805
|
+
}
|
|
31806
|
+
function subagentSessionCheck() {
|
|
31807
|
+
let subagentSession;
|
|
31808
|
+
return (context) => {
|
|
31809
|
+
subagentSession ??= isSubagentSession(context);
|
|
31810
|
+
return subagentSession;
|
|
31811
|
+
};
|
|
31812
|
+
}
|
|
31813
|
+
|
|
30705
31814
|
// extensions/legion.ts
|
|
30706
31815
|
var exitProcess = (code) => process.exit(code);
|
|
30707
31816
|
function setLegionBootstrapExitForTests(hook) {
|
|
@@ -30715,9 +31824,9 @@ function exitOnRegistrationRefusal(route, error) {
|
|
|
30715
31824
|
}
|
|
30716
31825
|
throw error;
|
|
30717
31826
|
}
|
|
30718
|
-
var
|
|
30719
|
-
var
|
|
30720
|
-
function
|
|
31827
|
+
var READY_RETRY_ATTEMPTS2 = 3;
|
|
31828
|
+
var READY_RETRY_DELAY_MS2 = 1000;
|
|
31829
|
+
function isNetworkOrTimeoutError2(error) {
|
|
30721
31830
|
if (!(error instanceof Error))
|
|
30722
31831
|
return false;
|
|
30723
31832
|
if (error.name === "NetworkError" || error.name === "TimeoutError")
|
|
@@ -30726,21 +31835,21 @@ function isNetworkOrTimeoutError(error) {
|
|
|
30726
31835
|
return code === "ConnectionRefused" || code === "ConnectionTimeout" || code === "EAI_AGAIN" || code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EHOSTUNREACH" || code === "ENETUNREACH" || code === "ENOTFOUND" || code === "ETIMEDOUT" || error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed");
|
|
30727
31836
|
}
|
|
30728
31837
|
var callReadyWithRetry = async (label, call) => {
|
|
30729
|
-
for (let attempt = 1;attempt <=
|
|
31838
|
+
for (let attempt = 1;attempt <= READY_RETRY_ATTEMPTS2; attempt++) {
|
|
30730
31839
|
try {
|
|
30731
31840
|
await call();
|
|
30732
31841
|
return;
|
|
30733
31842
|
} catch (error) {
|
|
30734
|
-
const retryable = error instanceof LegionDaemonApiError ? error.status >= 500 && error.status < 600 :
|
|
31843
|
+
const retryable = error instanceof LegionDaemonApiError ? error.status >= 500 && error.status < 600 : isNetworkOrTimeoutError2(error);
|
|
30735
31844
|
if (!retryable)
|
|
30736
31845
|
throw error;
|
|
30737
|
-
if (attempt ===
|
|
31846
|
+
if (attempt === READY_RETRY_ATTEMPTS2) {
|
|
30738
31847
|
console.error(`[legion] ${label} failed after ${attempt} attempts: ${messageFor(error)}`);
|
|
30739
31848
|
throw error;
|
|
30740
31849
|
}
|
|
30741
|
-
console.error(`[legion] ${label} failed (attempt ${attempt}/${
|
|
31850
|
+
console.error(`[legion] ${label} failed (attempt ${attempt}/${READY_RETRY_ATTEMPTS2}), retrying: ${messageFor(error)}`);
|
|
30742
31851
|
const retryDelay = Promise.withResolvers();
|
|
30743
|
-
setTimeout(retryDelay.resolve,
|
|
31852
|
+
setTimeout(retryDelay.resolve, READY_RETRY_DELAY_MS2);
|
|
30744
31853
|
await retryDelay.promise;
|
|
30745
31854
|
}
|
|
30746
31855
|
}
|
|
@@ -30767,29 +31876,11 @@ async function persistedTranscript(context) {
|
|
|
30767
31876
|
if (!sessionFile?.endsWith(".jsonl")) {
|
|
30768
31877
|
throw new Error("Legion session must have a persisted transcript");
|
|
30769
31878
|
}
|
|
30770
|
-
const agentId =
|
|
31879
|
+
const agentId = path4.basename(sessionFile, ".jsonl");
|
|
30771
31880
|
if (!agentId)
|
|
30772
31881
|
throw new Error("Legion session transcript has no agent id");
|
|
30773
31882
|
return { sessionFile, agentId };
|
|
30774
31883
|
}
|
|
30775
|
-
var LEGION_BOOTSTRAPPED_SESSION = Symbol.for("legion.pi-envoy.bootstrapped-session");
|
|
30776
|
-
var bootstrappedSessionStore = globalThis;
|
|
30777
|
-
function recordBootstrappedSession(sessionFile) {
|
|
30778
|
-
bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION] = sessionFile;
|
|
30779
|
-
}
|
|
30780
|
-
function resetLegionBootstrappedSessionForTests() {
|
|
30781
|
-
delete bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION];
|
|
30782
|
-
}
|
|
30783
|
-
async function isSubagentSession(context) {
|
|
30784
|
-
await context.sessionManager.ensureOnDisk();
|
|
30785
|
-
const sessionFile = context.sessionManager.getSessionFile();
|
|
30786
|
-
if (sessionFile === undefined)
|
|
30787
|
-
return false;
|
|
30788
|
-
const bootstrapped = bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION];
|
|
30789
|
-
if (bootstrapped !== undefined && bootstrapped !== sessionFile)
|
|
30790
|
-
return true;
|
|
30791
|
-
return fs.existsSync(`${path3.dirname(sessionFile)}.jsonl`);
|
|
30792
|
-
}
|
|
30793
31884
|
function isSingleLegionCommand(command) {
|
|
30794
31885
|
if (typeof command !== "string")
|
|
30795
31886
|
return false;
|
|
@@ -30937,11 +32028,7 @@ function legionExtension(pi) {
|
|
|
30937
32028
|
const controlCodec = import_nats.StringCodec();
|
|
30938
32029
|
let capability;
|
|
30939
32030
|
let bootstrap;
|
|
30940
|
-
|
|
30941
|
-
const checkSubagentSession = (context) => {
|
|
30942
|
-
subagentSession ??= isSubagentSession(context);
|
|
30943
|
-
return subagentSession;
|
|
30944
|
-
};
|
|
32031
|
+
const checkSubagentSession = subagentSessionCheck();
|
|
30945
32032
|
let phaseWorkerPane;
|
|
30946
32033
|
let daemonClient;
|
|
30947
32034
|
const roleDaemon = () => {
|
|
@@ -31174,6 +32261,21 @@ function legionExtension(pi) {
|
|
|
31174
32261
|
pi.on("session_start", async (_event, context) => {
|
|
31175
32262
|
if (await checkSubagentSession(context))
|
|
31176
32263
|
return;
|
|
32264
|
+
if (process.env.LEGION_DAEMON_API === "go") {
|
|
32265
|
+
return bootstrapGoClaim(context, {
|
|
32266
|
+
capability: () => capability,
|
|
32267
|
+
setCapability: (next) => {
|
|
32268
|
+
capability = next;
|
|
32269
|
+
},
|
|
32270
|
+
bootstrap: () => bootstrap,
|
|
32271
|
+
setBootstrap: (next) => {
|
|
32272
|
+
bootstrap = next;
|
|
32273
|
+
},
|
|
32274
|
+
exitProcess,
|
|
32275
|
+
persistedTranscript,
|
|
32276
|
+
recordBootstrappedSession
|
|
32277
|
+
});
|
|
32278
|
+
}
|
|
31177
32279
|
const classification = classifySession(process.env);
|
|
31178
32280
|
switch (classification.kind) {
|
|
31179
32281
|
case "controller":
|
|
@@ -31305,6 +32407,5 @@ function legionExtension(pi) {
|
|
|
31305
32407
|
}
|
|
31306
32408
|
export {
|
|
31307
32409
|
legionExtension as default,
|
|
31308
|
-
resetLegionBootstrappedSessionForTests,
|
|
31309
32410
|
setLegionBootstrapExitForTests
|
|
31310
32411
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjawhar/pi-legion-envoy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.60.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"omp": {
|
|
6
6
|
"extensions": [
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
14
|
"legion": {
|
|
15
|
-
"daemonApiVersion": 8
|
|
15
|
+
"daemonApiVersion": 8,
|
|
16
|
+
"goDaemonApiVersion": 1
|
|
16
17
|
},
|
|
17
18
|
"repository": {
|
|
18
19
|
"type": "git",
|