@modelcontextprotocol/inspector 2.4.0 → 2.5.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 +47 -577
- package/clients/cli/build/index.js +1286 -49
- package/clients/tui/build/index.js +1887 -759
- package/clients/web/build/index.js +126 -37
- package/clients/web/dist/assets/index-ZYqA4f7P.js +1486 -0
- package/clients/web/dist/assets/{index-DQVN73FG.css → index-dqp8Sd8W.css} +1 -1
- package/clients/web/dist/assets/{prism-light-HLcnHJHw.js → prism-light-_bvDBTQE.js} +1 -1
- package/clients/web/dist/index.html +2 -2
- package/package.json +24 -12
- package/clients/web/dist/assets/index-JCsLrWVa.js +0 -1484
- package/clients/web/dist/assets/json-BJ8dCynk.js +0 -1
|
@@ -130,6 +130,491 @@ var SECRET_FIELD_OAUTH_CLIENT_SECRET = "oauth-client-secret";
|
|
|
130
130
|
var SECRET_FIELD_IDP_CLIENT_SECRET = "idp-client-secret";
|
|
131
131
|
var envSecretField = (envKey) => `env:${envKey}`;
|
|
132
132
|
|
|
133
|
+
// ../../core/json/nullableUnion.ts
|
|
134
|
+
var RENDERABLE_TYPES = [
|
|
135
|
+
"string",
|
|
136
|
+
"number",
|
|
137
|
+
"integer",
|
|
138
|
+
"boolean",
|
|
139
|
+
"array",
|
|
140
|
+
"object"
|
|
141
|
+
];
|
|
142
|
+
function isRenderableType(type) {
|
|
143
|
+
return RENDERABLE_TYPES.includes(type);
|
|
144
|
+
}
|
|
145
|
+
function toBranch(value) {
|
|
146
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
function isStringEnum(value) {
|
|
152
|
+
return Array.isArray(value) && value.length > 0 && value.every((member) => typeof member === "string");
|
|
153
|
+
}
|
|
154
|
+
function nullExcludedBySiblings(schema) {
|
|
155
|
+
if (Array.isArray(schema.enum) && !schema.enum.includes(null)) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return schema.const !== void 0 && schema.const !== null;
|
|
159
|
+
}
|
|
160
|
+
var ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
161
|
+
"title",
|
|
162
|
+
"description",
|
|
163
|
+
"default",
|
|
164
|
+
"enumNames",
|
|
165
|
+
"examples",
|
|
166
|
+
"deprecated",
|
|
167
|
+
"readOnly",
|
|
168
|
+
"writeOnly",
|
|
169
|
+
"$comment",
|
|
170
|
+
"$schema",
|
|
171
|
+
"$id"
|
|
172
|
+
]);
|
|
173
|
+
function wrapperCarriesConstraints(schema) {
|
|
174
|
+
return Object.keys(schema).some(
|
|
175
|
+
(key) => key !== "anyOf" && !ANNOTATION_KEYWORDS.has(key)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
function typeNamesNull(type) {
|
|
179
|
+
return Array.isArray(type) ? type.includes("null") : type === "null";
|
|
180
|
+
}
|
|
181
|
+
function hasOpaqueApplicator(schema) {
|
|
182
|
+
return schema.not !== void 0 || schema.allOf !== void 0 || schema.oneOf !== void 0 || // `$ref` points at a schema this module never resolves, and it applies
|
|
183
|
+
// *alongside* its siblings — `{ type: "string", $ref: "#/$defs/intOnly" }`
|
|
184
|
+
// can be unsatisfiable. The wrapper path already declines on it (it is not
|
|
185
|
+
// an annotation); this is the same rule for every other position.
|
|
186
|
+
schema.$ref !== void 0;
|
|
187
|
+
}
|
|
188
|
+
function hasUnevaluatedComposition(schema) {
|
|
189
|
+
return schema.anyOf !== void 0 || hasOpaqueApplicator(schema);
|
|
190
|
+
}
|
|
191
|
+
function stripNullEnumMembers(members, names) {
|
|
192
|
+
if (!Array.isArray(members)) {
|
|
193
|
+
return { kind: "unchanged" };
|
|
194
|
+
}
|
|
195
|
+
const kept = members.map((member, index) => ({ member, index })).filter((entry) => entry.member !== null);
|
|
196
|
+
if (kept.length === 0) {
|
|
197
|
+
return { kind: "unselectable" };
|
|
198
|
+
}
|
|
199
|
+
if (kept.length === members.length) {
|
|
200
|
+
return { kind: "unchanged" };
|
|
201
|
+
}
|
|
202
|
+
const wasParallel = Array.isArray(names) && names.length === members.length;
|
|
203
|
+
const aligned = wasParallel ? kept.map((entry) => names[entry.index]) : void 0;
|
|
204
|
+
return {
|
|
205
|
+
kind: "filtered",
|
|
206
|
+
members: kept.map((entry) => entry.member),
|
|
207
|
+
names: aligned
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function collapsed(schema, branch, type) {
|
|
211
|
+
const merged = { ...schema, ...branch };
|
|
212
|
+
const strip = stripNullEnumMembers(
|
|
213
|
+
merged.enum,
|
|
214
|
+
merged.enumNames
|
|
215
|
+
);
|
|
216
|
+
if (strip.kind === "unselectable") {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
...merged,
|
|
221
|
+
type,
|
|
222
|
+
anyOf: void 0,
|
|
223
|
+
// Read off the ORIGINAL schema, not the merge: a hoisted branch `enum` is
|
|
224
|
+
// not a sibling constraint, and treating it as one would mark the very
|
|
225
|
+
// shape #1928 is about as non-nullable. See `nullExcludedBySiblings`.
|
|
226
|
+
nullable: admitsNull(schema),
|
|
227
|
+
...strip.kind === "filtered" ? { enum: strip.members, enumNames: strip.names } : {}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function typeAdmitsNull(type) {
|
|
231
|
+
return type === void 0 || typeNamesNull(type);
|
|
232
|
+
}
|
|
233
|
+
function admitsNull(schema) {
|
|
234
|
+
if (nullExcludedBySiblings(schema)) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
if (hasOpaqueApplicator(schema)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (schema.const === null) {
|
|
241
|
+
if (schema.nullable !== true && !typeAdmitsNull(schema.type)) return false;
|
|
242
|
+
return schema.anyOf === void 0 || anyOfAdmitsNull(schema);
|
|
243
|
+
}
|
|
244
|
+
if (Array.isArray(schema.enum) && schema.enum.includes(null)) {
|
|
245
|
+
return (schema.nullable === true || typeAdmitsNull(schema.type)) && (schema.anyOf === void 0 || anyOfAdmitsNull(schema));
|
|
246
|
+
}
|
|
247
|
+
if (schema.nullable === true) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
if (schema.type !== void 0) {
|
|
251
|
+
if (schema.anyOf !== void 0) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
return typeNamesNull(schema.type);
|
|
255
|
+
}
|
|
256
|
+
return anyOfAdmitsNull(schema);
|
|
257
|
+
}
|
|
258
|
+
var ANNOTATION_ONLY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
259
|
+
"title",
|
|
260
|
+
"description",
|
|
261
|
+
"examples",
|
|
262
|
+
"default",
|
|
263
|
+
"deprecated",
|
|
264
|
+
"readOnly",
|
|
265
|
+
"writeOnly",
|
|
266
|
+
"$comment",
|
|
267
|
+
// Core keywords that identify or declare rather than assert. `$ref` is
|
|
268
|
+
// deliberately absent: it applies whatever it points at, which is exactly an
|
|
269
|
+
// assertion this module cannot see.
|
|
270
|
+
"$defs",
|
|
271
|
+
"$id",
|
|
272
|
+
"$schema",
|
|
273
|
+
"$anchor",
|
|
274
|
+
"$dynamicAnchor",
|
|
275
|
+
"$vocabulary"
|
|
276
|
+
]);
|
|
277
|
+
function constrainsNothing(schema) {
|
|
278
|
+
return Object.keys(schema).every(
|
|
279
|
+
(keyword) => ANNOTATION_ONLY_KEYWORDS.has(keyword)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
function anyOfAdmitsNull(schema) {
|
|
283
|
+
const branches = schema.anyOf;
|
|
284
|
+
if (!Array.isArray(branches)) return false;
|
|
285
|
+
return branches.some((entry) => {
|
|
286
|
+
if (typeof entry === "boolean") return entry;
|
|
287
|
+
const branch = toBranch(entry);
|
|
288
|
+
if (branch === null) return false;
|
|
289
|
+
const branchSchema = branch;
|
|
290
|
+
if (hasUnevaluatedComposition(branchSchema)) return false;
|
|
291
|
+
if (constrainsNothing(branchSchema)) return true;
|
|
292
|
+
return admitsNull(branchSchema);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
function normalizeNullableUnion(schema) {
|
|
296
|
+
if (schema.anyOf?.length === 2) {
|
|
297
|
+
const branches = schema.anyOf.map(toBranch);
|
|
298
|
+
const nullBranch = branches.find((entry) => entry?.type === "null");
|
|
299
|
+
const branch = branches.find(
|
|
300
|
+
(entry) => entry !== null && entry.type !== "null"
|
|
301
|
+
);
|
|
302
|
+
if (nullBranch && branch && !wrapperCarriesConstraints(schema) && !hasUnevaluatedComposition(branch)) {
|
|
303
|
+
const type = branch.type ?? (isStringEnum(branch.enum) ? "string" : void 0);
|
|
304
|
+
if (isRenderableType(type)) {
|
|
305
|
+
const result = collapsed(schema, branch, type);
|
|
306
|
+
if (result !== null) {
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (Array.isArray(schema.type) && schema.type.length === 2 && schema.type.includes("null") && // This path keeps the schema's own keywords, but `collapsed` clears `anyOf`
|
|
313
|
+
// and the renderers ignore the other applicators — so a compound schema
|
|
314
|
+
// like `{ type: ["string", "null"], anyOf: [{ const: "a" }] }` would be
|
|
315
|
+
// widened into an unconstrained string field. Leave it for the JSON editor.
|
|
316
|
+
!hasUnevaluatedComposition(schema)) {
|
|
317
|
+
const type = schema.type.find((member) => member !== "null");
|
|
318
|
+
if (isRenderableType(type)) {
|
|
319
|
+
const result = collapsed(schema, void 0, type);
|
|
320
|
+
if (result !== null) {
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return schema;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ../../core/json/rootUnion.ts
|
|
329
|
+
function membersOf(value) {
|
|
330
|
+
return Array.isArray(value) ? value : [];
|
|
331
|
+
}
|
|
332
|
+
function requiredOf(schema) {
|
|
333
|
+
const { required } = schema;
|
|
334
|
+
return Array.isArray(required) ? required.filter((name) => typeof name === "string") : [];
|
|
335
|
+
}
|
|
336
|
+
function toBranch2(value) {
|
|
337
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
return value;
|
|
341
|
+
}
|
|
342
|
+
function admitsObject(schema) {
|
|
343
|
+
const { type } = schema;
|
|
344
|
+
if (type === void 0) return true;
|
|
345
|
+
return Array.isArray(type) ? type.includes("object") : type === "object";
|
|
346
|
+
}
|
|
347
|
+
function hasReadableProperties(schema) {
|
|
348
|
+
const { properties } = schema;
|
|
349
|
+
return typeof properties === "object" && properties !== null && !Array.isArray(properties);
|
|
350
|
+
}
|
|
351
|
+
function propertiesOf(schema) {
|
|
352
|
+
return hasReadableProperties(schema) ? schema.properties : {};
|
|
353
|
+
}
|
|
354
|
+
function isOfferable(branch, merged) {
|
|
355
|
+
if (branch.properties !== void 0 && !hasReadableProperties(branch)) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
if (!admitsObject(branch)) return false;
|
|
359
|
+
const properties = Object.values(propertiesOf(merged));
|
|
360
|
+
return properties.length > 0 && // Every value has to be something a renderer can read AND something a
|
|
361
|
+
// caller can satisfy. A `null` or an array is not a schema at all, and the
|
|
362
|
+
// web form dereferences one on the way to choosing a widget. JSON Schema's
|
|
363
|
+
// boolean form is legal, but only `true` is harmless — it constrains
|
|
364
|
+
// nothing and answers every keyword lookup with `undefined`, while `false`
|
|
365
|
+
// admits no value whatsoever, so a field declared with it can never be
|
|
366
|
+
// filled and a required one makes the whole branch unsatisfiable. Either
|
|
367
|
+
// way the branch is declined rather than offered as a callable shape.
|
|
368
|
+
properties.every(
|
|
369
|
+
(property) => property === true || typeof property === "object" && property !== null && !Array.isArray(property)
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
var ANNOTATION_KEYWORDS2 = /* @__PURE__ */ new Set([
|
|
373
|
+
"title",
|
|
374
|
+
"description",
|
|
375
|
+
"examples",
|
|
376
|
+
"deprecated",
|
|
377
|
+
"readOnly",
|
|
378
|
+
"writeOnly",
|
|
379
|
+
"$comment",
|
|
380
|
+
// An annotation too: a suggested initial value constrains nothing, so two
|
|
381
|
+
// declarations suggesting different ones still accept the same values.
|
|
382
|
+
"default"
|
|
383
|
+
]);
|
|
384
|
+
function canonicalJson(value) {
|
|
385
|
+
if (Array.isArray(value)) {
|
|
386
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
387
|
+
}
|
|
388
|
+
if (typeof value === "object" && value !== null) {
|
|
389
|
+
const entries = Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(
|
|
390
|
+
([key, member]) => `${JSON.stringify(key)}:${canonicalJson(member)}`
|
|
391
|
+
);
|
|
392
|
+
return `{${entries.join(",")}}`;
|
|
393
|
+
}
|
|
394
|
+
return JSON.stringify(value) ?? "undefined";
|
|
395
|
+
}
|
|
396
|
+
function sameJsonValue(a, b) {
|
|
397
|
+
return sameValue(a, b);
|
|
398
|
+
}
|
|
399
|
+
function sameValue(a, b) {
|
|
400
|
+
return a === b || canonicalJson(a) === canonicalJson(b);
|
|
401
|
+
}
|
|
402
|
+
function conflicts(baseProperty, branchProperty) {
|
|
403
|
+
const a = toBranch2(baseProperty);
|
|
404
|
+
const b = toBranch2(branchProperty);
|
|
405
|
+
if (a === null || b === null) {
|
|
406
|
+
return !sameValue(baseProperty, branchProperty);
|
|
407
|
+
}
|
|
408
|
+
const left = a;
|
|
409
|
+
const right = b;
|
|
410
|
+
if (Object.keys(right).some(
|
|
411
|
+
(keyword) => !ANNOTATION_KEYWORDS2.has(keyword) && keyword in left && !sameValue(left[keyword], right[keyword])
|
|
412
|
+
)) {
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
return !constSatisfiesSiblings({ ...left, ...right });
|
|
416
|
+
}
|
|
417
|
+
function jsonTypeOf(value) {
|
|
418
|
+
if (value === null) return "null";
|
|
419
|
+
if (Array.isArray(value)) return "array";
|
|
420
|
+
if (typeof value === "number") {
|
|
421
|
+
return Number.isInteger(value) ? "integer" : "number";
|
|
422
|
+
}
|
|
423
|
+
return typeof value;
|
|
424
|
+
}
|
|
425
|
+
var CONST_CHECKABLE = /* @__PURE__ */ new Set(["const", "type", "enum"]);
|
|
426
|
+
function constSatisfiesSiblings(schema) {
|
|
427
|
+
if (!("const" in schema)) return true;
|
|
428
|
+
const value = schema.const;
|
|
429
|
+
const { type, enum: allowed } = schema;
|
|
430
|
+
if (Object.keys(schema).some(
|
|
431
|
+
(keyword) => !CONST_CHECKABLE.has(keyword) && !ANNOTATION_KEYWORDS2.has(keyword)
|
|
432
|
+
)) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
const actual = jsonTypeOf(value);
|
|
436
|
+
const admits = (name) => name === actual || name === "number" && actual === "integer";
|
|
437
|
+
if (typeof type === "string" && !admits(type)) return false;
|
|
438
|
+
if (Array.isArray(type) && !type.some(admits)) return false;
|
|
439
|
+
if (Array.isArray(allowed) && !allowed.some((member) => sameValue(member, value))) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
function mergeProperty(baseProperty, branchProperty) {
|
|
445
|
+
const a = toBranch2(baseProperty);
|
|
446
|
+
const b = toBranch2(branchProperty);
|
|
447
|
+
if (a === null || b === null) {
|
|
448
|
+
return branchProperty;
|
|
449
|
+
}
|
|
450
|
+
return { ...a, ...b };
|
|
451
|
+
}
|
|
452
|
+
var MERGEABLE_KEYWORDS = /* @__PURE__ */ new Set(["type", "properties", "required"]);
|
|
453
|
+
function isFlattenable(member) {
|
|
454
|
+
const branch = toBranch2(member);
|
|
455
|
+
if (branch === null || !admitsObject(branch)) return false;
|
|
456
|
+
return Object.keys(branch).every(
|
|
457
|
+
(keyword) => MERGEABLE_KEYWORDS.has(keyword) || ANNOTATION_KEYWORDS2.has(keyword)
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
function conflictsWithBase(base, branch) {
|
|
461
|
+
const baseProperties = propertiesOf(base);
|
|
462
|
+
const branchProperties = propertiesOf(branch);
|
|
463
|
+
return Object.entries(branchProperties).some(
|
|
464
|
+
([name, branchProperty]) => (
|
|
465
|
+
// `hasOwn`, not `in`: `properties` is a JSON record, so `constructor` and
|
|
466
|
+
// `toString` are legal argument names that `in` would find on
|
|
467
|
+
// `Object.prototype` and report as collisions the root never declared.
|
|
468
|
+
Object.hasOwn(baseProperties, name) && conflicts(baseProperties[name], branchProperty)
|
|
469
|
+
)
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
function hasDiscriminator(members, named, rootRequired) {
|
|
473
|
+
const first = propertiesOf(members[0] ?? {});
|
|
474
|
+
const candidates = named !== void 0 ? [named] : Object.keys(first);
|
|
475
|
+
return candidates.some((name) => {
|
|
476
|
+
const constants = members.map((member) => {
|
|
477
|
+
if (!rootRequired.includes(name) && !requiredOf(member).includes(name)) {
|
|
478
|
+
return void 0;
|
|
479
|
+
}
|
|
480
|
+
const property = toBranch2(propertiesOf(member)[name]);
|
|
481
|
+
return property?.const;
|
|
482
|
+
});
|
|
483
|
+
if (constants.some((value) => value === void 0)) return false;
|
|
484
|
+
const seen = new Set(constants.map(canonicalJson));
|
|
485
|
+
return seen.size === constants.length;
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
function restrictsAdditional(schema) {
|
|
489
|
+
const additional = schema.additionalProperties;
|
|
490
|
+
return additional === false || typeof additional === "object" && additional !== null && Object.keys(additional).some(
|
|
491
|
+
(keyword) => !ANNOTATION_KEYWORDS2.has(keyword)
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
function addsForbiddenNames(base, member) {
|
|
495
|
+
if (!restrictsAdditional(base)) return false;
|
|
496
|
+
const baseNames = propertiesOf(base);
|
|
497
|
+
return Object.keys(propertiesOf(member)).some(
|
|
498
|
+
(name) => !Object.hasOwn(baseNames, name)
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
function mergeBranch(base, branch) {
|
|
502
|
+
const baseProperties = propertiesOf(base);
|
|
503
|
+
const branchProperties = propertiesOf(branch);
|
|
504
|
+
const properties = Object.fromEntries([
|
|
505
|
+
...Object.entries(baseProperties),
|
|
506
|
+
...Object.entries(branchProperties).map(([name, branchProperty]) => [
|
|
507
|
+
name,
|
|
508
|
+
Object.hasOwn(baseProperties, name) ? mergeProperty(baseProperties[name], branchProperty) : branchProperty
|
|
509
|
+
])
|
|
510
|
+
]);
|
|
511
|
+
const baseRequired = requiredOf(base);
|
|
512
|
+
const required = [
|
|
513
|
+
...baseRequired,
|
|
514
|
+
...requiredOf(branch).filter((name) => !baseRequired.includes(name))
|
|
515
|
+
];
|
|
516
|
+
return {
|
|
517
|
+
...base,
|
|
518
|
+
...Object.keys(properties).length > 0 ? { properties } : {},
|
|
519
|
+
...required.length > 0 ? { required } : {}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function withoutComposition(schema) {
|
|
523
|
+
const { allOf: _allOf, anyOf: _anyOf, oneOf: _oneOf, ...rest } = schema;
|
|
524
|
+
return rest;
|
|
525
|
+
}
|
|
526
|
+
function branchLabel(branch, index, discriminatorProperty) {
|
|
527
|
+
if (typeof branch.title === "string" && branch.title.trim() !== "") {
|
|
528
|
+
return branch.title;
|
|
529
|
+
}
|
|
530
|
+
const properties = propertiesOf(branch);
|
|
531
|
+
const constOf2 = (name) => {
|
|
532
|
+
const property = toBranch2(properties[name]);
|
|
533
|
+
if (property === null || !("const" in property)) return void 0;
|
|
534
|
+
const value = property.const;
|
|
535
|
+
return value === null || typeof value !== "object" ? String(value) : void 0;
|
|
536
|
+
};
|
|
537
|
+
if (discriminatorProperty !== void 0) {
|
|
538
|
+
const value = constOf2(discriminatorProperty);
|
|
539
|
+
if (value !== void 0) return value;
|
|
540
|
+
}
|
|
541
|
+
const constants = Object.keys(properties).map((name) => constOf2(name)).filter((value) => value !== void 0);
|
|
542
|
+
if (constants.length === 1) return constants[0];
|
|
543
|
+
return `Option ${index + 1}`;
|
|
544
|
+
}
|
|
545
|
+
function resolveRootUnion(schema) {
|
|
546
|
+
const allOfMembers = membersOf(schema.allOf);
|
|
547
|
+
let merged = schema;
|
|
548
|
+
for (const member of allOfMembers) {
|
|
549
|
+
const branch = toBranch2(member);
|
|
550
|
+
if (branch === null || !isFlattenable(member) || conflictsWithBase(merged, branch) || addsForbiddenNames(merged, branch)) {
|
|
551
|
+
return { base: schema, branches: [] };
|
|
552
|
+
}
|
|
553
|
+
merged = mergeBranch(merged, branch);
|
|
554
|
+
}
|
|
555
|
+
const base = withoutComposition(merged);
|
|
556
|
+
if (schema.oneOf !== void 0 && schema.anyOf !== void 0) {
|
|
557
|
+
return { base, branches: [] };
|
|
558
|
+
}
|
|
559
|
+
const isExclusiveUnion = schema.oneOf !== void 0;
|
|
560
|
+
const members = membersOf(schema.oneOf ?? schema.anyOf);
|
|
561
|
+
const branches = members.map(toBranch2);
|
|
562
|
+
if (branches.length === 0 || branches.some(
|
|
563
|
+
(branch) => branch === null || !isOfferable(branch, mergeBranch(base, branch)) || // The same faithfulness test the `allOf` fold applies: a member
|
|
564
|
+
// carrying a constraint the merge does not copy — a nested `allOf`, a
|
|
565
|
+
// `not`, a `$ref` — would have it erased along with the union keyword,
|
|
566
|
+
// which can present an unsatisfiable branch as a callable one.
|
|
567
|
+
!isFlattenable(branch) || conflictsWithBase(base, branch)
|
|
568
|
+
)) {
|
|
569
|
+
return { base, branches: [] };
|
|
570
|
+
}
|
|
571
|
+
if (branches.some(
|
|
572
|
+
(branch) => addsForbiddenNames(base, branch)
|
|
573
|
+
)) {
|
|
574
|
+
return { base, branches: [] };
|
|
575
|
+
}
|
|
576
|
+
if (isExclusiveUnion && !hasDiscriminator(
|
|
577
|
+
branches,
|
|
578
|
+
schema.discriminator?.propertyName,
|
|
579
|
+
requiredOf(base)
|
|
580
|
+
)) {
|
|
581
|
+
return { base, branches: [] };
|
|
582
|
+
}
|
|
583
|
+
const discriminatorProperty = schema.discriminator?.propertyName;
|
|
584
|
+
return {
|
|
585
|
+
base,
|
|
586
|
+
branches: branches.filter((branch) => branch !== null).map((branch, index) => ({
|
|
587
|
+
// `base` is already composition-free and `mergeBranch` copies only
|
|
588
|
+
// `properties`/`required` off the branch, so the merge stays that way.
|
|
589
|
+
schema: mergeBranch(base, branch),
|
|
590
|
+
label: branchLabel(branch, index, discriminatorProperty),
|
|
591
|
+
declaredFields: Object.keys(propertiesOf(branch))
|
|
592
|
+
}))
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
function narrowBySuppliedNames(branches, candidates, suppliedNames) {
|
|
596
|
+
if (candidates.length === 1) return candidates[0];
|
|
597
|
+
if (candidates.length === 0 || suppliedNames.length === 0) return null;
|
|
598
|
+
const supplied = new Set(suppliedNames);
|
|
599
|
+
const satisfied = candidates.filter((index) => {
|
|
600
|
+
const branch = branches[index];
|
|
601
|
+
const required = requiredOf(branch.schema);
|
|
602
|
+
const own = required.filter((name) => branch.declaredFields.includes(name));
|
|
603
|
+
return own.length > 0 && own.every((name) => supplied.has(name));
|
|
604
|
+
});
|
|
605
|
+
if (satisfied.length === 1) return satisfied[0];
|
|
606
|
+
const exclusiveTo = /* @__PURE__ */ new Map();
|
|
607
|
+
for (const index of candidates) {
|
|
608
|
+
for (const name of branches[index].declaredFields) {
|
|
609
|
+
exclusiveTo.set(name, exclusiveTo.has(name) ? -1 : index);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const named = new Set(
|
|
613
|
+
suppliedNames.map((name) => exclusiveTo.get(name)).filter((index) => index !== void 0 && index >= 0)
|
|
614
|
+
);
|
|
615
|
+
return named.size === 1 ? [...named][0] : null;
|
|
616
|
+
}
|
|
617
|
+
|
|
133
618
|
// ../../core/json/jsonUtils.ts
|
|
134
619
|
function isSerializableJson(value) {
|
|
135
620
|
if (value === null) return true;
|
|
@@ -169,16 +654,90 @@ function convertParameterValue(value, schema) {
|
|
|
169
654
|
}
|
|
170
655
|
return value;
|
|
171
656
|
}
|
|
657
|
+
function coercionProperties(base, branches, params) {
|
|
658
|
+
if (branches.length === 0) {
|
|
659
|
+
return { ...base.properties };
|
|
660
|
+
}
|
|
661
|
+
const candidates = branches.map((branch, index) => ({ branch, index })).filter(
|
|
662
|
+
({ branch }) => matchesConstants(branch.schema.properties ?? {}, params)
|
|
663
|
+
).map(({ index }) => index);
|
|
664
|
+
const selected = narrowBySuppliedNames(
|
|
665
|
+
branches,
|
|
666
|
+
candidates,
|
|
667
|
+
Object.keys(params)
|
|
668
|
+
);
|
|
669
|
+
if (selected !== null) {
|
|
670
|
+
return { ...branches[selected].schema.properties };
|
|
671
|
+
}
|
|
672
|
+
const properties = Object.fromEntries(
|
|
673
|
+
Object.entries(base.properties ?? {})
|
|
674
|
+
);
|
|
675
|
+
const pool = candidates.length > 0 ? candidates.map((i) => branches[i]) : branches;
|
|
676
|
+
for (const name of new Set(pool.flatMap((b) => b.declaredFields))) {
|
|
677
|
+
const declarations = pool.filter((branch) => branch.declaredFields.includes(name)).map((branch) => branch.schema.properties?.[name]).filter((schema) => typeof schema === "object" && schema !== null).map((schema) => normalizeNullableUnion(schema));
|
|
678
|
+
const types = new Set(declarations.map((schema) => typeNameOf(schema)));
|
|
679
|
+
const pinnedOf = (schema) => typeof schema === "object" && schema !== null && "const" in schema ? schema.const : void 0;
|
|
680
|
+
const constsAgree = declarations.every(
|
|
681
|
+
(schema) => sameJsonValue(pinnedOf(schema), pinnedOf(declarations[0]))
|
|
682
|
+
);
|
|
683
|
+
if (types.size === 1 && constsAgree && declarations.length > 0) {
|
|
684
|
+
Object.defineProperty(properties, name, {
|
|
685
|
+
value: declarations[0],
|
|
686
|
+
writable: true,
|
|
687
|
+
enumerable: true,
|
|
688
|
+
configurable: true
|
|
689
|
+
});
|
|
690
|
+
} else {
|
|
691
|
+
delete properties[name];
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return properties;
|
|
695
|
+
}
|
|
696
|
+
function typeNameOf(schema) {
|
|
697
|
+
if (typeof schema !== "object" || schema === null) return "";
|
|
698
|
+
const { type } = schema;
|
|
699
|
+
return Array.isArray(type) ? [...type].map(String).sort().join(",") : typeof type === "string" ? type : "";
|
|
700
|
+
}
|
|
701
|
+
function matchesConstants(properties, params) {
|
|
702
|
+
return Object.entries(properties).every(([name, schema]) => {
|
|
703
|
+
if (typeof schema !== "object" || schema === null) return true;
|
|
704
|
+
const constValue = schema.const;
|
|
705
|
+
if (constValue === void 0) return true;
|
|
706
|
+
if (!Object.hasOwn(params, name)) return true;
|
|
707
|
+
const supplied = params[name];
|
|
708
|
+
return supplied === void 0 || suppliedMatchesConst(supplied, constValue);
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
function suppliedMatchesConst(value, constValue) {
|
|
712
|
+
if (constValue === null || typeof constValue !== "object") {
|
|
713
|
+
return value === String(constValue);
|
|
714
|
+
}
|
|
715
|
+
try {
|
|
716
|
+
return sameJsonValue(JSON.parse(value), constValue);
|
|
717
|
+
} catch {
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
172
721
|
function convertToolParameters(tool, params) {
|
|
722
|
+
return convertParametersForSchema(tool.inputSchema, params);
|
|
723
|
+
}
|
|
724
|
+
function convertParametersForSchema(inputSchema, params) {
|
|
173
725
|
const result = {};
|
|
174
|
-
const
|
|
726
|
+
const { base, branches } = resolveRootUnion(
|
|
727
|
+
inputSchema ?? {}
|
|
728
|
+
);
|
|
729
|
+
const properties = coercionProperties(base, branches, params);
|
|
175
730
|
for (const [key, value] of Object.entries(params)) {
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
731
|
+
const declared = properties[key];
|
|
732
|
+
const paramSchema = typeof declared === "object" && declared !== null ? normalizeNullableUnion(declared) : declared;
|
|
733
|
+
const pinned = paramSchema?.const;
|
|
734
|
+
const converted = pinned !== void 0 && suppliedMatchesConst(value, pinned) ? pinned : paramSchema ? convertParameterValue(value, paramSchema) : value;
|
|
735
|
+
Object.defineProperty(result, key, {
|
|
736
|
+
value: converted,
|
|
737
|
+
writable: true,
|
|
738
|
+
enumerable: true,
|
|
739
|
+
configurable: true
|
|
740
|
+
});
|
|
182
741
|
}
|
|
183
742
|
return result;
|
|
184
743
|
}
|
|
@@ -415,6 +974,9 @@ function storedFieldsToInspectorSettings(stored) {
|
|
|
415
974
|
if (stored.oauth?.requestRefreshToken === false) {
|
|
416
975
|
settings.oauthRequestRefreshToken = false;
|
|
417
976
|
}
|
|
977
|
+
if (stored.oauth?.revokeOnClear === false) {
|
|
978
|
+
settings.oauthRevokeOnClear = false;
|
|
979
|
+
}
|
|
418
980
|
if (stored.cwd) settings.cwd = stored.cwd;
|
|
419
981
|
return settings;
|
|
420
982
|
}
|
|
@@ -3360,11 +3922,11 @@ function formatRunnerOAuthRedirectUrl(config) {
|
|
|
3360
3922
|
|
|
3361
3923
|
// src/App.tsx
|
|
3362
3924
|
import {
|
|
3363
|
-
useState as
|
|
3925
|
+
useState as useState16,
|
|
3364
3926
|
useMemo as useMemo4,
|
|
3365
|
-
useEffect as
|
|
3366
|
-
useCallback as
|
|
3367
|
-
useRef as
|
|
3927
|
+
useEffect as useEffect13,
|
|
3928
|
+
useCallback as useCallback12,
|
|
3929
|
+
useRef as useRef14
|
|
3368
3930
|
} from "react";
|
|
3369
3931
|
import { Box as Box27, Text as Text24, useInput as useInput21, useApp } from "ink";
|
|
3370
3932
|
|
|
@@ -3528,6 +4090,20 @@ function mcpParamHeadersForTool(tool, args) {
|
|
|
3528
4090
|
return buildMcpParamHeaders(scan.declarations, args);
|
|
3529
4091
|
}
|
|
3530
4092
|
|
|
4093
|
+
// ../../core/mcp/subscriptionAck.ts
|
|
4094
|
+
import { SdkError, SdkErrorCode } from "@modelcontextprotocol/client";
|
|
4095
|
+
var NEVER_ACKNOWLEDGED_SDK_MESSAGE = "closed the subscription gracefully before acknowledging";
|
|
4096
|
+
var NEVER_ACKNOWLEDGED_SUBSCRIPTION_MESSAGE = "The server closed the subscription without acknowledging it. A subscriptions/listen request must first be answered with a notifications/subscriptions/acknowledged notification; a JSON-RPC result for the listen id means graceful closure. Not retrying \u2014 the server would answer the same way again.";
|
|
4097
|
+
function isNeverAcknowledgedSubscriptionClose(error) {
|
|
4098
|
+
return SdkError.isInstance(error) && error.code === SdkErrorCode.ConnectionClosed && error.message.includes(NEVER_ACKNOWLEDGED_SDK_MESSAGE);
|
|
4099
|
+
}
|
|
4100
|
+
function subscriptionFailureMessage(error) {
|
|
4101
|
+
if (isNeverAcknowledgedSubscriptionClose(error)) {
|
|
4102
|
+
return NEVER_ACKNOWLEDGED_SUBSCRIPTION_MESSAGE;
|
|
4103
|
+
}
|
|
4104
|
+
return error instanceof Error ? error.message : String(error);
|
|
4105
|
+
}
|
|
4106
|
+
|
|
3531
4107
|
// ../../core/mcp/messageTrackingTransport.ts
|
|
3532
4108
|
var MessageTrackingTransport = class {
|
|
3533
4109
|
baseTransport;
|
|
@@ -3619,6 +4195,29 @@ var MessageTrackingTransport = class {
|
|
|
3619
4195
|
get sessionId() {
|
|
3620
4196
|
return this.baseTransport.sessionId;
|
|
3621
4197
|
}
|
|
4198
|
+
/**
|
|
4199
|
+
* Forward the base transport's per-request-stream capability (#2140).
|
|
4200
|
+
*
|
|
4201
|
+
* The SDK's `Protocol.request` reads this off the transport it was handed —
|
|
4202
|
+
* which is always this wrapper — to decide how a cancelled request is
|
|
4203
|
+
* signalled: abort that request's own stream (the 2026-07-28 signal for
|
|
4204
|
+
* Streamable HTTP) or POST a `notifications/cancelled` (the stdio one).
|
|
4205
|
+
*
|
|
4206
|
+
* Not forwarding it made the wrapper *answer* the question, `undefined`, for
|
|
4207
|
+
* every client. So the Cancel button POSTed a notification even on a modern
|
|
4208
|
+
* Streamable HTTP connection, where a spec-compliant server acknowledges it
|
|
4209
|
+
* `202` and drops it — the tool kept running and only a disconnect really
|
|
4210
|
+
* cancelled anything. That hit the CLI and TUI as much as the web client:
|
|
4211
|
+
* their real `StreamableHTTPClientTransport` advertises the flag correctly
|
|
4212
|
+
* and this wrapper hid it.
|
|
4213
|
+
*
|
|
4214
|
+
* A base transport that says nothing stays `undefined` rather than becoming
|
|
4215
|
+
* `false`, since the SDK's check is `=== true` either way and inventing a
|
|
4216
|
+
* value here would misreport what the transport claimed.
|
|
4217
|
+
*/
|
|
4218
|
+
get hasPerRequestStream() {
|
|
4219
|
+
return this.baseTransport.hasPerRequestStream;
|
|
4220
|
+
}
|
|
3622
4221
|
// Implemented as a concrete method (rather than delegating the base
|
|
3623
4222
|
// transport's optional `setProtocolVersion`) so the SDK Client always
|
|
3624
4223
|
// invokes it after the initialize handshake — including for stdio, whose
|
|
@@ -3847,7 +4446,7 @@ function validateToolOutput(provider, tool, result) {
|
|
|
3847
4446
|
|
|
3848
4447
|
// ../../core/mcp/listSalvage.ts
|
|
3849
4448
|
import { z as z3 } from "zod/v4";
|
|
3850
|
-
import { SdkError, SdkErrorCode } from "@modelcontextprotocol/client";
|
|
4449
|
+
import { SdkError as SdkError2, SdkErrorCode as SdkErrorCode2 } from "@modelcontextprotocol/client";
|
|
3851
4450
|
import { ToolSchema } from "@modelcontextprotocol/core";
|
|
3852
4451
|
var LIST_MAX_PAGES = 64;
|
|
3853
4452
|
function listPaginationExceeded(method) {
|
|
@@ -3856,10 +4455,10 @@ function listPaginationExceeded(method) {
|
|
|
3856
4455
|
);
|
|
3857
4456
|
}
|
|
3858
4457
|
function isClientDecodeRejection(err) {
|
|
3859
|
-
return
|
|
4458
|
+
return SdkError2.isInstance(err) && (err.code === SdkErrorCode2.InvalidResult || err.code === SdkErrorCode2.UnsupportedResultType);
|
|
3860
4459
|
}
|
|
3861
4460
|
function isSalvageableRejection(err) {
|
|
3862
|
-
return
|
|
4461
|
+
return SdkError2.isInstance(err) && err.code === SdkErrorCode2.InvalidResult;
|
|
3863
4462
|
}
|
|
3864
4463
|
function lenientListPageSchema(resultSchema, itemsKey) {
|
|
3865
4464
|
return resultSchema.extend({ [itemsKey]: z3.array(z3.unknown()) });
|
|
@@ -4214,6 +4813,52 @@ var TypedEventGeneric = class extends CustomEvent {
|
|
|
4214
4813
|
}
|
|
4215
4814
|
};
|
|
4216
4815
|
var TypedEventTarget = class extends EventTarget {
|
|
4816
|
+
/**
|
|
4817
|
+
* Per-event-type dispatch counter. Read through `getEventRevision` by
|
|
4818
|
+
* `useStoreSnapshot` (core/react) to tell "nothing has happened on this
|
|
4819
|
+
* event since I last looked" from "something has", without comparing the
|
|
4820
|
+
* snapshot's contents (#1955).
|
|
4821
|
+
*/
|
|
4822
|
+
eventRevisions = /* @__PURE__ */ new Map();
|
|
4823
|
+
/**
|
|
4824
|
+
* How many times an event of this type has been dispatched from this
|
|
4825
|
+
* target. Monotonic per type, and per type only: an `errorChange` does not
|
|
4826
|
+
* advance `toolsChange`, so a subscriber to one is not re-read because of
|
|
4827
|
+
* the other.
|
|
4828
|
+
*
|
|
4829
|
+
* The counter — not the list's contents — is what a `useSyncExternalStore`
|
|
4830
|
+
* snapshot is cached against. That distinction is load-bearing rather than
|
|
4831
|
+
* an optimization: these stores hand out a defensive copy, so comparing
|
|
4832
|
+
* contents is the only alternative, and a contents comparison cannot see an
|
|
4833
|
+
* in-place mutation of an entry the list already holds. `MessageLogState`
|
|
4834
|
+
* does exactly that when a response is folded into its request entry
|
|
4835
|
+
* (filling in `response`/`duration`), and it dispatches — so the counter
|
|
4836
|
+
* moves and the fold reaches the UI, where a shallow compare would report
|
|
4837
|
+
* "unchanged" and never re-render it.
|
|
4838
|
+
*/
|
|
4839
|
+
getEventRevision(type) {
|
|
4840
|
+
return this.eventRevisions.get(type) ?? 0;
|
|
4841
|
+
}
|
|
4842
|
+
/**
|
|
4843
|
+
* Overridden solely to advance the counter. It sits on `dispatchEvent`
|
|
4844
|
+
* rather than on `dispatchTypedEvent` because that is the one funnel every
|
|
4845
|
+
* dispatch passes through — the typed helper below delegates to it, and so
|
|
4846
|
+
* does a hand-rolled `dispatchEvent(new CustomEvent(...))`, which the tests
|
|
4847
|
+
* use extensively. A counter bumped only in the typed helper would be
|
|
4848
|
+
* silently stale for those, i.e. exactly where nobody would look for it.
|
|
4849
|
+
*
|
|
4850
|
+
* Bumped BEFORE dispatching: the state mutation always precedes the
|
|
4851
|
+
* dispatch, so by the time a listener runs the counter must already reflect
|
|
4852
|
+
* it, or a snapshot read from inside that listener would return the cached
|
|
4853
|
+
* pre-change value.
|
|
4854
|
+
*/
|
|
4855
|
+
dispatchEvent(event) {
|
|
4856
|
+
this.eventRevisions.set(
|
|
4857
|
+
event.type,
|
|
4858
|
+
(this.eventRevisions.get(event.type) ?? 0) + 1
|
|
4859
|
+
);
|
|
4860
|
+
return super.dispatchEvent(event);
|
|
4861
|
+
}
|
|
4217
4862
|
dispatchTypedEvent(type, ...args) {
|
|
4218
4863
|
const detail = args[0] ?? void 0;
|
|
4219
4864
|
this.dispatchEvent(new TypedEventGeneric(type, detail));
|
|
@@ -4602,6 +5247,115 @@ function withOAuthEndpointOverrides(fetchFn, getOverrides) {
|
|
|
4602
5247
|
};
|
|
4603
5248
|
}
|
|
4604
5249
|
|
|
5250
|
+
// ../../core/auth/oidcDiscoveryCompat.ts
|
|
5251
|
+
import {
|
|
5252
|
+
OAuthMetadataSchema,
|
|
5253
|
+
OpenIdProviderDiscoveryMetadataSchema
|
|
5254
|
+
} from "@modelcontextprotocol/core";
|
|
5255
|
+
var RFC8414_WELL_KNOWN = "/.well-known/oauth-authorization-server";
|
|
5256
|
+
var OIDC_WELL_KNOWN = "/.well-known/openid-configuration";
|
|
5257
|
+
var COMPAT_SOURCE_HEADER = "x-inspector-oauth-metadata-source";
|
|
5258
|
+
function oidcDiscoveryCandidates(rfc8414Url) {
|
|
5259
|
+
let url;
|
|
5260
|
+
try {
|
|
5261
|
+
url = new URL(rfc8414Url);
|
|
5262
|
+
} catch {
|
|
5263
|
+
return [];
|
|
5264
|
+
}
|
|
5265
|
+
if (!url.pathname.startsWith(RFC8414_WELL_KNOWN)) return [];
|
|
5266
|
+
const path6 = url.pathname.slice(RFC8414_WELL_KNOWN.length);
|
|
5267
|
+
if (path6 !== "" && !path6.startsWith("/")) return [];
|
|
5268
|
+
if (path6 === "") return [new URL(OIDC_WELL_KNOWN, url.origin).href];
|
|
5269
|
+
return [
|
|
5270
|
+
new URL(`${OIDC_WELL_KNOWN}${path6}`, url.origin).href,
|
|
5271
|
+
new URL(`${path6}${OIDC_WELL_KNOWN}`, url.origin).href
|
|
5272
|
+
];
|
|
5273
|
+
}
|
|
5274
|
+
function continuesDiscovery(status) {
|
|
5275
|
+
return status >= 400 && status < 500 || status === 502;
|
|
5276
|
+
}
|
|
5277
|
+
async function releaseBody(response) {
|
|
5278
|
+
await response.body?.cancel().catch(() => {
|
|
5279
|
+
});
|
|
5280
|
+
}
|
|
5281
|
+
function isRfc8414OnlyMetadata(value) {
|
|
5282
|
+
if (!OAuthMetadataSchema.safeParse(value).success) return false;
|
|
5283
|
+
return !OpenIdProviderDiscoveryMetadataSchema.safeParse(value).success;
|
|
5284
|
+
}
|
|
5285
|
+
function requestUrlOf2(input) {
|
|
5286
|
+
if (typeof input === "string") return input;
|
|
5287
|
+
if (input instanceof URL) return input.href;
|
|
5288
|
+
return input.url;
|
|
5289
|
+
}
|
|
5290
|
+
function discoveryHeaders(input, init) {
|
|
5291
|
+
if (init?.headers) return new Headers(init.headers);
|
|
5292
|
+
if (typeof input !== "string" && !(input instanceof URL)) {
|
|
5293
|
+
return new Headers(input.headers);
|
|
5294
|
+
}
|
|
5295
|
+
return new Headers();
|
|
5296
|
+
}
|
|
5297
|
+
function requestMethodOf(input, init) {
|
|
5298
|
+
if (init?.method) return init.method.toUpperCase();
|
|
5299
|
+
if (typeof input !== "string" && !(input instanceof URL)) {
|
|
5300
|
+
return input.method.toUpperCase();
|
|
5301
|
+
}
|
|
5302
|
+
return "GET";
|
|
5303
|
+
}
|
|
5304
|
+
function withRfc8414OidcCompat(fetchFn) {
|
|
5305
|
+
return async (input, init) => {
|
|
5306
|
+
const response = await fetchFn(input, init);
|
|
5307
|
+
if (response.ok) return response;
|
|
5308
|
+
if (!continuesDiscovery(response.status)) return response;
|
|
5309
|
+
if (requestMethodOf(input, init) !== "GET") return response;
|
|
5310
|
+
const candidates = oidcDiscoveryCandidates(requestUrlOf2(input));
|
|
5311
|
+
if (candidates.length === 0) return response;
|
|
5312
|
+
const headers = discoveryHeaders(input, init);
|
|
5313
|
+
for (const candidate of candidates) {
|
|
5314
|
+
let probe;
|
|
5315
|
+
try {
|
|
5316
|
+
probe = await fetchFn(candidate, { headers });
|
|
5317
|
+
} catch {
|
|
5318
|
+
return response;
|
|
5319
|
+
}
|
|
5320
|
+
if (!probe.ok) {
|
|
5321
|
+
await releaseBody(probe);
|
|
5322
|
+
if (continuesDiscovery(probe.status)) continue;
|
|
5323
|
+
return response;
|
|
5324
|
+
}
|
|
5325
|
+
let parsed;
|
|
5326
|
+
let body;
|
|
5327
|
+
try {
|
|
5328
|
+
body = await probe.text();
|
|
5329
|
+
parsed = JSON.parse(body);
|
|
5330
|
+
} catch {
|
|
5331
|
+
return response;
|
|
5332
|
+
}
|
|
5333
|
+
if (!isRfc8414OnlyMetadata(parsed)) {
|
|
5334
|
+
return response;
|
|
5335
|
+
}
|
|
5336
|
+
const source = probe.url || candidate;
|
|
5337
|
+
await releaseBody(response);
|
|
5338
|
+
console.warn(
|
|
5339
|
+
`[oauth] ${source} returned RFC 8414 OAuth 2.0 authorization server metadata, not an OpenID provider document. The MCP TypeScript SDK validates that path as OpenID Connect Discovery and would reject it (modelcontextprotocol/typescript-sdk#2733), so the Inspector is handing it to discovery as the RFC 8414 document it is.`
|
|
5340
|
+
);
|
|
5341
|
+
return new Response(body, {
|
|
5342
|
+
status: 200,
|
|
5343
|
+
statusText: "OK",
|
|
5344
|
+
headers: {
|
|
5345
|
+
"content-type": "application/json",
|
|
5346
|
+
// The substituted response is what the fetch trackers above this
|
|
5347
|
+
// wrapper record, so it says where its body actually came from
|
|
5348
|
+
// rather than letting the Network tab imply the RFC 8414 path
|
|
5349
|
+
// answered. Named on the response, not logged only, so it survives
|
|
5350
|
+
// into the captured entry.
|
|
5351
|
+
[COMPAT_SOURCE_HEADER]: source
|
|
5352
|
+
}
|
|
5353
|
+
});
|
|
5354
|
+
}
|
|
5355
|
+
return response;
|
|
5356
|
+
};
|
|
5357
|
+
}
|
|
5358
|
+
|
|
4605
5359
|
// ../../core/logging/logger.ts
|
|
4606
5360
|
var noop = () => {
|
|
4607
5361
|
};
|
|
@@ -4953,49 +5707,331 @@ var BaseOAuthClientProvider = class {
|
|
|
4953
5707
|
await this.storage.clearDiscoveryState(this.serverUrl);
|
|
4954
5708
|
return;
|
|
4955
5709
|
}
|
|
4956
|
-
}
|
|
4957
|
-
};
|
|
4958
|
-
|
|
4959
|
-
// ../../core/auth/types.ts
|
|
4960
|
-
function authProtocolFromEnterpriseManaged(enterpriseManaged) {
|
|
4961
|
-
return enterpriseManaged ? "ema" : "standard";
|
|
4962
|
-
}
|
|
4963
|
-
var EMPTY_OAUTH_FLOW_STATE = {
|
|
4964
|
-
completedAt: null,
|
|
4965
|
-
isInitiatingAuth: false,
|
|
4966
|
-
oauthTokens: null,
|
|
4967
|
-
oauthStep: "authorization_code",
|
|
4968
|
-
oauthMetadata: null,
|
|
4969
|
-
resourceMetadata: null,
|
|
4970
|
-
resourceMetadataError: null,
|
|
4971
|
-
resource: null,
|
|
4972
|
-
authServerUrl: null,
|
|
4973
|
-
oauthClientInfo: null,
|
|
4974
|
-
authorizationUrl: null,
|
|
4975
|
-
authorizationCode: "",
|
|
4976
|
-
latestError: null,
|
|
4977
|
-
statusMessage: null,
|
|
4978
|
-
validationError: null
|
|
4979
|
-
};
|
|
4980
|
-
|
|
4981
|
-
// ../../core/auth/mcpAuth.ts
|
|
4982
|
-
import { auth as sdkAuth } from "@modelcontextprotocol/client";
|
|
4983
|
-
async function mcpAuth(provider, options) {
|
|
4984
|
-
if (options.forceReauthorization && options.authorizationCode !== void 0) {
|
|
4985
|
-
throw new Error(
|
|
4986
|
-
"forceReauthorization cannot be combined with authorizationCode"
|
|
5710
|
+
}
|
|
5711
|
+
};
|
|
5712
|
+
|
|
5713
|
+
// ../../core/auth/types.ts
|
|
5714
|
+
function authProtocolFromEnterpriseManaged(enterpriseManaged) {
|
|
5715
|
+
return enterpriseManaged ? "ema" : "standard";
|
|
5716
|
+
}
|
|
5717
|
+
var EMPTY_OAUTH_FLOW_STATE = {
|
|
5718
|
+
completedAt: null,
|
|
5719
|
+
isInitiatingAuth: false,
|
|
5720
|
+
oauthTokens: null,
|
|
5721
|
+
oauthStep: "authorization_code",
|
|
5722
|
+
oauthMetadata: null,
|
|
5723
|
+
resourceMetadata: null,
|
|
5724
|
+
resourceMetadataError: null,
|
|
5725
|
+
resource: null,
|
|
5726
|
+
authServerUrl: null,
|
|
5727
|
+
oauthClientInfo: null,
|
|
5728
|
+
authorizationUrl: null,
|
|
5729
|
+
authorizationCode: "",
|
|
5730
|
+
latestError: null,
|
|
5731
|
+
statusMessage: null,
|
|
5732
|
+
validationError: null
|
|
5733
|
+
};
|
|
5734
|
+
|
|
5735
|
+
// ../../core/auth/mcpAuth.ts
|
|
5736
|
+
import { auth as sdkAuth } from "@modelcontextprotocol/client";
|
|
5737
|
+
async function mcpAuth(provider, options) {
|
|
5738
|
+
if (options.forceReauthorization && options.authorizationCode !== void 0) {
|
|
5739
|
+
throw new Error(
|
|
5740
|
+
"forceReauthorization cannot be combined with authorizationCode"
|
|
5741
|
+
);
|
|
5742
|
+
}
|
|
5743
|
+
return sdkAuth(provider, {
|
|
5744
|
+
serverUrl: options.serverUrl,
|
|
5745
|
+
authorizationCode: options.authorizationCode,
|
|
5746
|
+
iss: options.iss,
|
|
5747
|
+
scope: options.scope,
|
|
5748
|
+
resourceMetadataUrl: options.resourceMetadataUrl,
|
|
5749
|
+
fetchFn: options.fetchFn,
|
|
5750
|
+
skipIssuerMetadataValidation: options.skipIssuerMetadataValidation,
|
|
5751
|
+
forceReauthorization: options.forceReauthorization
|
|
5752
|
+
});
|
|
5753
|
+
}
|
|
5754
|
+
|
|
5755
|
+
// ../../core/auth/revocation.ts
|
|
5756
|
+
import { selectClientAuthMethod } from "@modelcontextprotocol/client";
|
|
5757
|
+
import {
|
|
5758
|
+
OAuthClientInformationSchema,
|
|
5759
|
+
OAuthTokensSchema
|
|
5760
|
+
} from "@modelcontextprotocol/core";
|
|
5761
|
+
var DEFAULT_REVOCATION_TIMEOUT_MS = 5e3;
|
|
5762
|
+
function selectRevocableToken(tokens) {
|
|
5763
|
+
if (!tokens) return null;
|
|
5764
|
+
if (tokens.refresh_token) {
|
|
5765
|
+
return { token: tokens.refresh_token, tokenTypeHint: "refresh_token" };
|
|
5766
|
+
}
|
|
5767
|
+
if (tokens.access_token) {
|
|
5768
|
+
return { token: tokens.access_token, tokenTypeHint: "access_token" };
|
|
5769
|
+
}
|
|
5770
|
+
return null;
|
|
5771
|
+
}
|
|
5772
|
+
function revocationAuthMethods(metadata) {
|
|
5773
|
+
return metadata.revocation_endpoint_auth_methods_supported ?? [
|
|
5774
|
+
"client_secret_basic"
|
|
5775
|
+
];
|
|
5776
|
+
}
|
|
5777
|
+
function buildRevocationRequest(params) {
|
|
5778
|
+
const body = new URLSearchParams({
|
|
5779
|
+
token: params.token,
|
|
5780
|
+
token_type_hint: params.tokenTypeHint
|
|
5781
|
+
});
|
|
5782
|
+
const headers = {
|
|
5783
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
5784
|
+
Accept: "application/json"
|
|
5785
|
+
};
|
|
5786
|
+
const client = params.clientInformation;
|
|
5787
|
+
if (client) {
|
|
5788
|
+
const method = selectClientAuthMethod(client, params.supportedAuthMethods);
|
|
5789
|
+
if (method === "client_secret_basic" && client.client_secret) {
|
|
5790
|
+
const credentials = `${encodeURIComponent(client.client_id)}:${encodeURIComponent(client.client_secret)}`;
|
|
5791
|
+
headers.Authorization = `Basic ${base64Encode(credentials)}`;
|
|
5792
|
+
} else if (method === "client_secret_post" && client.client_secret) {
|
|
5793
|
+
body.set("client_id", client.client_id);
|
|
5794
|
+
body.set("client_secret", client.client_secret);
|
|
5795
|
+
} else {
|
|
5796
|
+
body.set("client_id", client.client_id);
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5799
|
+
return {
|
|
5800
|
+
url: params.endpoint,
|
|
5801
|
+
init: { method: "POST", headers, body: body.toString() }
|
|
5802
|
+
};
|
|
5803
|
+
}
|
|
5804
|
+
function base64Encode(value) {
|
|
5805
|
+
if (typeof btoa === "function") return btoa(value);
|
|
5806
|
+
return Buffer.from(value, "utf8").toString("base64");
|
|
5807
|
+
}
|
|
5808
|
+
async function revokeToken(params) {
|
|
5809
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_REVOCATION_TIMEOUT_MS;
|
|
5810
|
+
try {
|
|
5811
|
+
const { url, init } = buildRevocationRequest(params);
|
|
5812
|
+
const response = await withDeadline(
|
|
5813
|
+
params.fetchFn(url, { ...init, signal: AbortSignal.timeout(timeoutMs) }),
|
|
5814
|
+
timeoutMs
|
|
5815
|
+
);
|
|
5816
|
+
if (!response.ok) {
|
|
5817
|
+
return {
|
|
5818
|
+
status: "failed",
|
|
5819
|
+
endpoint: url,
|
|
5820
|
+
detail: `revocation endpoint responded ${response.status} ${response.statusText}`.trim()
|
|
5821
|
+
};
|
|
5822
|
+
}
|
|
5823
|
+
return {
|
|
5824
|
+
status: "revoked",
|
|
5825
|
+
tokenTypeHint: params.tokenTypeHint,
|
|
5826
|
+
endpoint: url
|
|
5827
|
+
};
|
|
5828
|
+
} catch (err) {
|
|
5829
|
+
return {
|
|
5830
|
+
// `params.endpoint`, not the built `url`: construction is inside the try
|
|
5831
|
+
// now, so `url` may not exist on this path.
|
|
5832
|
+
status: "failed",
|
|
5833
|
+
endpoint: params.endpoint,
|
|
5834
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
5835
|
+
};
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
async function withDeadline(promise, timeoutMs) {
|
|
5839
|
+
let timer;
|
|
5840
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
5841
|
+
timer = setTimeout(
|
|
5842
|
+
() => reject(new Error(`revocation request timed out after ${timeoutMs}ms`)),
|
|
5843
|
+
timeoutMs
|
|
5844
|
+
);
|
|
5845
|
+
});
|
|
5846
|
+
try {
|
|
5847
|
+
return await Promise.race([promise, deadline]);
|
|
5848
|
+
} finally {
|
|
5849
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
function emptyPlan(serverUrl, outcome, failures = []) {
|
|
5853
|
+
return {
|
|
5854
|
+
serverUrl,
|
|
5855
|
+
grants: [],
|
|
5856
|
+
failures,
|
|
5857
|
+
supportedAuthMethods: [],
|
|
5858
|
+
outcome: failures.length > 0 ? aggregateOutcomes([...failures, outcome]) : outcome
|
|
5859
|
+
};
|
|
5860
|
+
}
|
|
5861
|
+
async function clearAndPlanRevocation(params) {
|
|
5862
|
+
const { serverUrl, storage } = params;
|
|
5863
|
+
let snapshot;
|
|
5864
|
+
try {
|
|
5865
|
+
snapshot = await storage.takeRevocationSnapshot(serverUrl);
|
|
5866
|
+
} catch (err) {
|
|
5867
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
5868
|
+
}
|
|
5869
|
+
if (params.enabled === false) {
|
|
5870
|
+
return emptyPlan(serverUrl, { status: "skipped", reason: "disabled" });
|
|
5871
|
+
}
|
|
5872
|
+
try {
|
|
5873
|
+
const { grants, failures } = await collectGrants(snapshot);
|
|
5874
|
+
if (grants.length === 0) {
|
|
5875
|
+
return emptyPlan(
|
|
5876
|
+
serverUrl,
|
|
5877
|
+
{ status: "skipped", reason: "no_tokens" },
|
|
5878
|
+
failures
|
|
5879
|
+
);
|
|
5880
|
+
}
|
|
5881
|
+
const metadata = parseServerMetadata(snapshot.serverMetadata);
|
|
5882
|
+
if (!metadata) {
|
|
5883
|
+
return emptyPlan(
|
|
5884
|
+
serverUrl,
|
|
5885
|
+
{ status: "skipped", reason: "no_metadata" },
|
|
5886
|
+
failures
|
|
5887
|
+
);
|
|
5888
|
+
}
|
|
5889
|
+
if (!metadata.revocation_endpoint) {
|
|
5890
|
+
return emptyPlan(
|
|
5891
|
+
serverUrl,
|
|
5892
|
+
{ status: "skipped", reason: "no_endpoint" },
|
|
5893
|
+
failures
|
|
5894
|
+
);
|
|
5895
|
+
}
|
|
5896
|
+
return {
|
|
5897
|
+
serverUrl,
|
|
5898
|
+
grants,
|
|
5899
|
+
failures,
|
|
5900
|
+
endpoint: metadata.revocation_endpoint,
|
|
5901
|
+
supportedAuthMethods: revocationAuthMethods(metadata),
|
|
5902
|
+
metadataIssuer: metadata.issuer
|
|
5903
|
+
};
|
|
5904
|
+
} catch (err) {
|
|
5905
|
+
return emptyPlan(serverUrl, {
|
|
5906
|
+
status: "failed",
|
|
5907
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
5908
|
+
});
|
|
5909
|
+
}
|
|
5910
|
+
}
|
|
5911
|
+
function parseServerMetadata(raw) {
|
|
5912
|
+
if (raw === null || typeof raw !== "object") return void 0;
|
|
5913
|
+
return raw;
|
|
5914
|
+
}
|
|
5915
|
+
async function executeOAuthRevocation(plan, params) {
|
|
5916
|
+
const outcome = await runPlan(plan, params);
|
|
5917
|
+
const { logger } = params;
|
|
5918
|
+
if (outcome.status === "failed") {
|
|
5919
|
+
logger?.warn(
|
|
5920
|
+
{
|
|
5921
|
+
serverUrl: plan.serverUrl,
|
|
5922
|
+
endpoint: outcome.endpoint,
|
|
5923
|
+
detail: outcome.detail
|
|
5924
|
+
},
|
|
5925
|
+
"Token revocation failed; local OAuth state was cleared anyway"
|
|
5926
|
+
);
|
|
5927
|
+
} else if (outcome.status === "skipped" && outcome.reason === "no_endpoint") {
|
|
5928
|
+
logger?.debug(
|
|
5929
|
+
{ serverUrl: plan.serverUrl },
|
|
5930
|
+
"Skipping token revocation: authorization server metadata has no revocation_endpoint"
|
|
5931
|
+
);
|
|
5932
|
+
}
|
|
5933
|
+
return outcome;
|
|
5934
|
+
}
|
|
5935
|
+
async function collectGrants(snapshot) {
|
|
5936
|
+
const grants = [];
|
|
5937
|
+
const failures = [];
|
|
5938
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
5939
|
+
let preregistered;
|
|
5940
|
+
try {
|
|
5941
|
+
preregistered = await parseClient(snapshot.preregisteredClientInformation);
|
|
5942
|
+
} catch (err) {
|
|
5943
|
+
failures.push({
|
|
5944
|
+
status: "failed",
|
|
5945
|
+
detail: `could not read the preconfigured client registration: ${err instanceof Error ? err.message : String(err)}`
|
|
5946
|
+
});
|
|
5947
|
+
}
|
|
5948
|
+
const add2 = async (issuer, rawTokens, rawClient) => {
|
|
5949
|
+
const revocable = selectRevocableToken(await parseTokens(rawTokens));
|
|
5950
|
+
if (!revocable) return;
|
|
5951
|
+
const key = `${issuer ?? "\0legacy"}\0${revocable.token}`;
|
|
5952
|
+
if (seenKeys.has(key)) return;
|
|
5953
|
+
seenKeys.add(key);
|
|
5954
|
+
const bound = await parseClient(rawClient);
|
|
5955
|
+
grants.push({
|
|
5956
|
+
issuer,
|
|
5957
|
+
...revocable,
|
|
5958
|
+
clientInformation: bound ?? preregistered
|
|
5959
|
+
});
|
|
5960
|
+
};
|
|
5961
|
+
const addSafely = async (issuer, rawTokens, rawClient) => {
|
|
5962
|
+
try {
|
|
5963
|
+
await add2(issuer, rawTokens, rawClient);
|
|
5964
|
+
} catch (err) {
|
|
5965
|
+
const where = issuer === void 0 ? "the unkeyed slot" : `issuer ${issuer}`;
|
|
5966
|
+
failures.push({
|
|
5967
|
+
status: "failed",
|
|
5968
|
+
detail: `could not read the stored grant for ${where}: ${err instanceof Error ? err.message : String(err)}`
|
|
5969
|
+
});
|
|
5970
|
+
}
|
|
5971
|
+
};
|
|
5972
|
+
for (const [issuer, slot] of Object.entries(snapshot.byIssuer)) {
|
|
5973
|
+
await addSafely(issuer, slot?.tokens, slot?.clientInformation);
|
|
5974
|
+
}
|
|
5975
|
+
await addSafely(
|
|
5976
|
+
void 0,
|
|
5977
|
+
snapshot.legacyTokens,
|
|
5978
|
+
snapshot.legacyClientInformation
|
|
5979
|
+
);
|
|
5980
|
+
return { grants, failures };
|
|
5981
|
+
}
|
|
5982
|
+
async function parseTokens(raw) {
|
|
5983
|
+
return raw === void 0 || raw === null ? void 0 : await OAuthTokensSchema.parseAsync(raw);
|
|
5984
|
+
}
|
|
5985
|
+
async function parseClient(raw) {
|
|
5986
|
+
return raw === void 0 || raw === null ? void 0 : await OAuthClientInformationSchema.parseAsync(raw);
|
|
5987
|
+
}
|
|
5988
|
+
function aggregateOutcomes(outcomes) {
|
|
5989
|
+
return outcomes.find((o) => o.status === "failed") ?? outcomes.find((o) => o.status === "revoked") ?? outcomes[0] ?? { status: "skipped", reason: "no_tokens" };
|
|
5990
|
+
}
|
|
5991
|
+
async function runPlan(plan, params) {
|
|
5992
|
+
if (plan.outcome) return plan.outcome;
|
|
5993
|
+
const endpoint = plan.endpoint;
|
|
5994
|
+
if (!endpoint) return { status: "skipped", reason: "no_endpoint" };
|
|
5995
|
+
const outcomes = [...plan.failures];
|
|
5996
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_REVOCATION_TIMEOUT_MS;
|
|
5997
|
+
const deadlineAt = Date.now() + timeoutMs;
|
|
5998
|
+
for (const grant of plan.grants) {
|
|
5999
|
+
if (grant.issuer === void 0) {
|
|
6000
|
+
outcomes.push({
|
|
6001
|
+
status: "failed",
|
|
6002
|
+
detail: "the stored grant is not bound to an authorization server (it predates issuer binding), so it could not be matched to this revocation endpoint and was cleared without revocation \u2014 re-authorize to make future clears revocable"
|
|
6003
|
+
});
|
|
6004
|
+
continue;
|
|
6005
|
+
}
|
|
6006
|
+
if (plan.metadataIssuer !== grant.issuer) {
|
|
6007
|
+
outcomes.push({
|
|
6008
|
+
status: "failed",
|
|
6009
|
+
detail: plan.metadataIssuer === void 0 ? `the cached authorization-server metadata names no issuer, so the grant bound to ${grant.issuer} could not be matched to this revocation endpoint and was cleared without revocation` : `the cached authorization-server metadata is for ${plan.metadataIssuer}, so the grant bound to ${grant.issuer} was cleared without revocation`
|
|
6010
|
+
});
|
|
6011
|
+
continue;
|
|
6012
|
+
}
|
|
6013
|
+
const remainingMs = deadlineAt - Date.now();
|
|
6014
|
+
if (remainingMs <= 0) {
|
|
6015
|
+
outcomes.push({
|
|
6016
|
+
status: "failed",
|
|
6017
|
+
endpoint,
|
|
6018
|
+
detail: `the ${timeoutMs}ms revocation budget was exhausted before this grant was attempted${grant.issuer === void 0 ? "" : ` (issuer ${grant.issuer})`}`
|
|
6019
|
+
});
|
|
6020
|
+
continue;
|
|
6021
|
+
}
|
|
6022
|
+
outcomes.push(
|
|
6023
|
+
await revokeToken({
|
|
6024
|
+
endpoint,
|
|
6025
|
+
token: grant.token,
|
|
6026
|
+
tokenTypeHint: grant.tokenTypeHint,
|
|
6027
|
+
clientInformation: grant.clientInformation,
|
|
6028
|
+
supportedAuthMethods: plan.supportedAuthMethods,
|
|
6029
|
+
fetchFn: params.fetchFn,
|
|
6030
|
+
timeoutMs: remainingMs
|
|
6031
|
+
})
|
|
4987
6032
|
);
|
|
4988
6033
|
}
|
|
4989
|
-
return
|
|
4990
|
-
serverUrl: options.serverUrl,
|
|
4991
|
-
authorizationCode: options.authorizationCode,
|
|
4992
|
-
iss: options.iss,
|
|
4993
|
-
scope: options.scope,
|
|
4994
|
-
resourceMetadataUrl: options.resourceMetadataUrl,
|
|
4995
|
-
fetchFn: options.fetchFn,
|
|
4996
|
-
skipIssuerMetadataValidation: options.skipIssuerMetadataValidation,
|
|
4997
|
-
forceReauthorization: options.forceReauthorization
|
|
4998
|
-
});
|
|
6034
|
+
return aggregateOutcomes(outcomes);
|
|
4999
6035
|
}
|
|
5000
6036
|
|
|
5001
6037
|
// ../../core/auth/ema/clientConfigError.ts
|
|
@@ -5023,7 +6059,7 @@ import {
|
|
|
5023
6059
|
exchangeAuthorization,
|
|
5024
6060
|
startAuthorization
|
|
5025
6061
|
} from "@modelcontextprotocol/client";
|
|
5026
|
-
import { OAuthMetadataSchema } from "@modelcontextprotocol/core";
|
|
6062
|
+
import { OAuthMetadataSchema as OAuthMetadataSchema2 } from "@modelcontextprotocol/core";
|
|
5027
6063
|
|
|
5028
6064
|
// ../../core/auth/ema/constants.ts
|
|
5029
6065
|
var GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
|
@@ -5072,7 +6108,7 @@ function idpOAuthStorageKey(issuer) {
|
|
|
5072
6108
|
}
|
|
5073
6109
|
|
|
5074
6110
|
// ../../core/auth/ema/tokenEndpoint.ts
|
|
5075
|
-
import { selectClientAuthMethod } from "@modelcontextprotocol/client";
|
|
6111
|
+
import { selectClientAuthMethod as selectClientAuthMethod2 } from "@modelcontextprotocol/client";
|
|
5076
6112
|
async function parseOAuthTokenErrorResponse(response, step) {
|
|
5077
6113
|
let body;
|
|
5078
6114
|
try {
|
|
@@ -5093,7 +6129,7 @@ async function parseOAuthTokenErrorResponse(response, step) {
|
|
|
5093
6129
|
}
|
|
5094
6130
|
function applyClientAuth(metadata, clientInformation, headers, body) {
|
|
5095
6131
|
const supported = metadata?.token_endpoint_auth_methods_supported ?? [];
|
|
5096
|
-
const method =
|
|
6132
|
+
const method = selectClientAuthMethod2(clientInformation, supported);
|
|
5097
6133
|
if (method === "client_secret_basic" && clientInformation.client_secret) {
|
|
5098
6134
|
const credentials = btoa(
|
|
5099
6135
|
`${clientInformation.client_id}:${clientInformation.client_secret}`
|
|
@@ -5147,7 +6183,7 @@ async function discoverIdpMetadata(issuer, fetchFn) {
|
|
|
5147
6183
|
`Failed to discover OIDC metadata for IdP issuer ${issuer}`
|
|
5148
6184
|
);
|
|
5149
6185
|
}
|
|
5150
|
-
return
|
|
6186
|
+
return OAuthMetadataSchema2.parse(metadata);
|
|
5151
6187
|
}
|
|
5152
6188
|
async function startIdpOidcAuthorization(params) {
|
|
5153
6189
|
const issuer = normalizeIdpIssuer(params.idp.issuer);
|
|
@@ -5403,7 +6439,7 @@ async function discoverResourceAsMetadata(resourceAsUrl, fetchFn) {
|
|
|
5403
6439
|
|
|
5404
6440
|
// ../../core/auth/ema/wire.ts
|
|
5405
6441
|
import { discoverAndRequestJwtAuthGrant } from "@modelcontextprotocol/client";
|
|
5406
|
-
import { OAuthTokensSchema } from "@modelcontextprotocol/core";
|
|
6442
|
+
import { OAuthTokensSchema as OAuthTokensSchema2 } from "@modelcontextprotocol/core";
|
|
5407
6443
|
async function exchangeIdJag(params) {
|
|
5408
6444
|
const issuer = normalizeIdpIssuer(params.idp.issuer);
|
|
5409
6445
|
const resource = params.resource.trim();
|
|
@@ -5482,7 +6518,7 @@ async function redeemIdJagForAccessToken(params) {
|
|
|
5482
6518
|
"EMA leg 3 (resource AS JWT bearer grant)"
|
|
5483
6519
|
);
|
|
5484
6520
|
}
|
|
5485
|
-
return
|
|
6521
|
+
return OAuthTokensSchema2.parse(await response.json());
|
|
5486
6522
|
}
|
|
5487
6523
|
|
|
5488
6524
|
// ../../core/auth/ema/emaFlow.ts
|
|
@@ -6229,14 +7265,41 @@ var OAuthManager = class {
|
|
|
6229
7265
|
return void 0;
|
|
6230
7266
|
}
|
|
6231
7267
|
}
|
|
6232
|
-
|
|
7268
|
+
/**
|
|
7269
|
+
* Drop this server's local OAuth state, and revoke the grant at the
|
|
7270
|
+
* authorization server (RFC 7009).
|
|
7271
|
+
*
|
|
7272
|
+
* The state is taken and deleted in one atomic step, and the requests are
|
|
7273
|
+
* sent afterwards from what was taken. Both halves matter: the requests need
|
|
7274
|
+
* state the clear destroys, and the clear must not wait on the network, or a
|
|
7275
|
+
* fresh authorization completing during a five-second revocation would be
|
|
7276
|
+
* deleted by a clear reasoning about the grant it replaced.
|
|
7277
|
+
*
|
|
7278
|
+
* Best-effort by construction: every failure is reported through the returned
|
|
7279
|
+
* outcome and the clear has already happened regardless, because forgetting
|
|
7280
|
+
* the tokens is what the caller actually asked for (#2144).
|
|
7281
|
+
*
|
|
7282
|
+
* `options.revoke === false` skips the request. That is not only an escape
|
|
7283
|
+
* hatch for an authorization server that mishandles it — disconnecting while
|
|
7284
|
+
* still holding live tokens is a case a user may want to reproduce
|
|
7285
|
+
* deliberately, to watch how a server under test copes with it.
|
|
7286
|
+
*/
|
|
7287
|
+
async clearOAuthTokens(options) {
|
|
6233
7288
|
if (!this.oauthConfig?.storage) {
|
|
6234
|
-
return;
|
|
7289
|
+
return { status: "skipped", reason: "no_tokens" };
|
|
6235
7290
|
}
|
|
6236
7291
|
const serverUrl = this.getServerUrl();
|
|
6237
|
-
await
|
|
7292
|
+
const plan = await clearAndPlanRevocation({
|
|
7293
|
+
serverUrl,
|
|
7294
|
+
storage: this.oauthConfig.storage,
|
|
7295
|
+
enabled: options?.revoke
|
|
7296
|
+
});
|
|
6238
7297
|
this.oauthFlowState = null;
|
|
6239
7298
|
this.pendingAuthorizationScope = void 0;
|
|
7299
|
+
return executeOAuthRevocation(plan, {
|
|
7300
|
+
fetchFn: this.params.effectiveAuthFetch,
|
|
7301
|
+
logger: this.params.logger
|
|
7302
|
+
});
|
|
6240
7303
|
}
|
|
6241
7304
|
async isOAuthAuthorized() {
|
|
6242
7305
|
const tokens = await this.getOAuthTokens();
|
|
@@ -6563,10 +7626,11 @@ var OAuthManager = class {
|
|
|
6563
7626
|
await this.params.onBeforeOAuthRedirect(parsedState.authId);
|
|
6564
7627
|
}
|
|
6565
7628
|
}
|
|
6566
|
-
this.requireNavigation()
|
|
7629
|
+
const navigation = this.requireNavigation();
|
|
6567
7630
|
const provider = await this.createOAuthProvider();
|
|
6568
7631
|
const clientInfo = await provider.clientInformation();
|
|
6569
7632
|
await this.recordAuthorizationCodeFlowState(authorizationUrl, clientInfo);
|
|
7633
|
+
navigation.navigateToAuthorization(authorizationUrl);
|
|
6570
7634
|
this.params.dispatchOAuthAuthorizationRequired({ url: authorizationUrl });
|
|
6571
7635
|
}
|
|
6572
7636
|
requireNavigation() {
|
|
@@ -6723,6 +7787,24 @@ var RemoteClientTransport = class {
|
|
|
6723
7787
|
sseResponseWaits = /* @__PURE__ */ new Map();
|
|
6724
7788
|
options;
|
|
6725
7789
|
config;
|
|
7790
|
+
/**
|
|
7791
|
+
* Whether the upstream connection gives each request its own response stream
|
|
7792
|
+
* (#2140). The SDK's `Protocol.request` reads this: on a 2026-era connection
|
|
7793
|
+
* a transport advertising it has its per-request stream **aborted** as the
|
|
7794
|
+
* spec's cancellation signal, and no `notifications/cancelled` is sent; a
|
|
7795
|
+
* transport that does not gets the stdio mechanism instead.
|
|
7796
|
+
*
|
|
7797
|
+
* The real upstream transport lives on the backend, so this transport has to
|
|
7798
|
+
* answer for it. Streamable HTTP opens one POST — and one SSE response
|
|
7799
|
+
* stream — per request, so it qualifies; stdio and SSE multiplex every
|
|
7800
|
+
* request over one shared channel and must keep sending the notification.
|
|
7801
|
+
*
|
|
7802
|
+
* Advertising it is only half the fix: `requestSend` applies the SDK's
|
|
7803
|
+
* `requestSignal` to the browser-to-backend fetch, and `/api/mcp/send`
|
|
7804
|
+
* forwards that disconnect to the upstream `transport.send`, which is what
|
|
7805
|
+
* actually closes the stream the server is watching.
|
|
7806
|
+
*/
|
|
7807
|
+
hasPerRequestStream;
|
|
6726
7808
|
/**
|
|
6727
7809
|
* Intentionally returns undefined. The MCP Client checks transport.sessionId to detect
|
|
6728
7810
|
* reconnects and skip initialize. Our _sessionId is the remote server's session ID, not
|
|
@@ -6767,6 +7849,7 @@ var RemoteClientTransport = class {
|
|
|
6767
7849
|
constructor(options, config) {
|
|
6768
7850
|
this.options = options;
|
|
6769
7851
|
this.config = config;
|
|
7852
|
+
this.hasPerRequestStream = config.type === "streamable-http";
|
|
6770
7853
|
}
|
|
6771
7854
|
setAuthRecovery(handlers) {
|
|
6772
7855
|
this.options.authRecovery = handlers;
|
|
@@ -7131,7 +8214,8 @@ var RemoteClientTransport = class {
|
|
|
7131
8214
|
const res = await this.fetchFn(`${this.baseUrl}/api/mcp/send`, {
|
|
7132
8215
|
method: "POST",
|
|
7133
8216
|
headers: this.headers,
|
|
7134
|
-
body: JSON.stringify(body)
|
|
8217
|
+
body: JSON.stringify(body),
|
|
8218
|
+
...options?.requestSignal && { signal: options.requestSignal }
|
|
7135
8219
|
});
|
|
7136
8220
|
if (!res.ok) {
|
|
7137
8221
|
const text = await res.text();
|
|
@@ -7368,6 +8452,13 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
7368
8452
|
// pending re-listen timer.
|
|
7369
8453
|
modernReconnectAttempts = 0;
|
|
7370
8454
|
modernReconnectTimer;
|
|
8455
|
+
// Set when the last `listen()` was rejected because the server answered it
|
|
8456
|
+
// with a bare graceful-closure result instead of acknowledging (#2097). That
|
|
8457
|
+
// condition is deterministic, so the reconnect machinery must not treat it as
|
|
8458
|
+
// a drop to retry; the flag is what carries the distinction from the rejection
|
|
8459
|
+
// site to the two failure handlers. Cleared by any user-initiated refresh (a
|
|
8460
|
+
// subscribe/unsubscribe is a fresh attempt, and the server may have changed).
|
|
8461
|
+
modernNeverAcknowledged = false;
|
|
7371
8462
|
// Task ids the user explicitly cancelled. A cancel makes the in-flight
|
|
7372
8463
|
// `callToolStream` reject with a generic -32603 error, which the stream's
|
|
7373
8464
|
// error path would otherwise report as a *failed* task — flashing "failed"
|
|
@@ -7389,9 +8480,12 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
7389
8480
|
pendingRawWireRequests = /* @__PURE__ */ new Map();
|
|
7390
8481
|
rawWireRequestCounter = 0;
|
|
7391
8482
|
// Abort controller for the in-flight ordinary (non-task) tool call. Aborting
|
|
7392
|
-
// it
|
|
7393
|
-
//
|
|
7394
|
-
//
|
|
8483
|
+
// it hands the SDK the MCP cancellation flow for that request and rejects the
|
|
8484
|
+
// pending call, which `callTool` surfaces as a `ToolCallCancelledError`. Which
|
|
8485
|
+
// signal reaches the server is the transport's business, not ours: a
|
|
8486
|
+
// per-request-stream transport on a 2026-era connection has that request's
|
|
8487
|
+
// stream aborted, and everything else gets `notifications/cancelled` (#2140).
|
|
8488
|
+
// Undefined when no ordinary call is in flight.
|
|
7395
8489
|
// Task-augmented calls have a server-side task and are cancelled via
|
|
7396
8490
|
// `cancelRequestorTask` instead, so they don't use this (#1458).
|
|
7397
8491
|
activeToolCallAbortController;
|
|
@@ -7498,6 +8592,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
7498
8592
|
this.fetchFn ?? fetch,
|
|
7499
8593
|
() => this.oauthManager?.getEndpointOverrides()
|
|
7500
8594
|
);
|
|
8595
|
+
this.fetchFn = withRfc8414OidcCompat(this.fetchFn);
|
|
7501
8596
|
this.effectiveAuthFetch = this.buildEffectiveAuthFetch();
|
|
7502
8597
|
this.sessionId = options.sessionId;
|
|
7503
8598
|
if (options.oauth || options.environment.oauth) {
|
|
@@ -7517,6 +8612,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
7517
8612
|
return Promise.resolve();
|
|
7518
8613
|
},
|
|
7519
8614
|
initialConfig: oauthConfig,
|
|
8615
|
+
logger: this.logger,
|
|
7520
8616
|
enterpriseManagedAuth: options.enterpriseManagedAuth,
|
|
7521
8617
|
installEnterpriseManagedAuth: options.installEnterpriseManagedAuth,
|
|
7522
8618
|
dispatchOAuthComplete: (detail) => this.dispatchTypedEvent("oauthComplete", detail),
|
|
@@ -8207,6 +9303,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
8207
9303
|
this.modernListenGeneration++;
|
|
8208
9304
|
this.clearModernReconnectTimer();
|
|
8209
9305
|
this.modernReconnectAttempts = 0;
|
|
9306
|
+
this.modernNeverAcknowledged = false;
|
|
8210
9307
|
this.modernSubscription = null;
|
|
8211
9308
|
this.setModernStreamState(INACTIVE_SUBSCRIPTION_STREAM_STATE);
|
|
8212
9309
|
this.dispatchSubscriptionsChange();
|
|
@@ -8993,10 +10090,13 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
8993
10090
|
}
|
|
8994
10091
|
/**
|
|
8995
10092
|
* Cancel the in-flight ordinary (non-task) tool call started by
|
|
8996
|
-
* {@link callTool}. Aborting its request
|
|
8997
|
-
*
|
|
8998
|
-
*
|
|
8999
|
-
*
|
|
10093
|
+
* {@link callTool}. Aborting its request runs the MCP cancellation flow and
|
|
10094
|
+
* rejects the pending call, which `callTool` surfaces as a
|
|
10095
|
+
* {@link ToolCallCancelledError}. The SDK chooses the wire signal from the
|
|
10096
|
+
* transport: on a 2026-era Streamable HTTP connection it aborts that
|
|
10097
|
+
* request's own SSE response stream — the spec's cancellation signal —
|
|
10098
|
+
* rather than sending `notifications/cancelled`, which is the stdio
|
|
10099
|
+
* mechanism and remains in use there (#2140).
|
|
9000
10100
|
*
|
|
9001
10101
|
* Task-augmented calls have a server-side task and are cancelled via
|
|
9002
10102
|
* {@link cancelRequestorTask} instead — this is a no-op for them (and whenever
|
|
@@ -11212,6 +12312,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11212
12312
|
if (!fromReconnect) {
|
|
11213
12313
|
this.clearModernReconnectTimer();
|
|
11214
12314
|
this.modernReconnectAttempts = 0;
|
|
12315
|
+
this.modernNeverAcknowledged = false;
|
|
11215
12316
|
}
|
|
11216
12317
|
const generation = ++this.modernListenGeneration;
|
|
11217
12318
|
const previous = this.modernSubscription;
|
|
@@ -11223,10 +12324,18 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11223
12324
|
this.setModernStreamState(INACTIVE_SUBSCRIPTION_STREAM_STATE);
|
|
11224
12325
|
return;
|
|
11225
12326
|
}
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
this.
|
|
11229
|
-
|
|
12327
|
+
let subscription;
|
|
12328
|
+
try {
|
|
12329
|
+
subscription = await this.client.listen(
|
|
12330
|
+
this.buildSubscriptionFilter(),
|
|
12331
|
+
this.getRequestOptions()
|
|
12332
|
+
);
|
|
12333
|
+
} catch (error) {
|
|
12334
|
+
if (generation === this.modernListenGeneration && isNeverAcknowledgedSubscriptionClose(error)) {
|
|
12335
|
+
this.modernNeverAcknowledged = true;
|
|
12336
|
+
}
|
|
12337
|
+
throw error;
|
|
12338
|
+
}
|
|
11230
12339
|
if (generation !== this.modernListenGeneration) {
|
|
11231
12340
|
await closeSubscriptionBestEffort(subscription);
|
|
11232
12341
|
return;
|
|
@@ -11308,8 +12417,34 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11308
12417
|
this.setModernStreamState(INACTIVE_SUBSCRIPTION_STREAM_STATE);
|
|
11309
12418
|
return;
|
|
11310
12419
|
}
|
|
12420
|
+
if (this.modernNeverAcknowledged) {
|
|
12421
|
+
this.endModernStreamNeverAcknowledged();
|
|
12422
|
+
return;
|
|
12423
|
+
}
|
|
11311
12424
|
this.scheduleModernReconnect();
|
|
11312
12425
|
}
|
|
12426
|
+
/**
|
|
12427
|
+
* Settle the stream on the never-acknowledged close (#2097): a status of its
|
|
12428
|
+
* own so the UI can say what happened, no reconnect, and a log line carrying
|
|
12429
|
+
* the same sentence the UI shows.
|
|
12430
|
+
*
|
|
12431
|
+
* The state is *not* `"ended"` — that badge covers the two expected closes (a
|
|
12432
|
+
* server shutting an established stream down, and reconnection abandoned after
|
|
12433
|
+
* repeated failures), and reading this case as either of them is exactly the
|
|
12434
|
+
* silence #2063 reported.
|
|
12435
|
+
*/
|
|
12436
|
+
endModernStreamNeverAcknowledged() {
|
|
12437
|
+
this.clearModernReconnectTimer();
|
|
12438
|
+
this.logger.warn(
|
|
12439
|
+
{ message: NEVER_ACKNOWLEDGED_SUBSCRIPTION_MESSAGE },
|
|
12440
|
+
"subscriptions/listen closed without an acknowledgement"
|
|
12441
|
+
);
|
|
12442
|
+
this.setModernStreamState({
|
|
12443
|
+
active: this.modernStreamActive(),
|
|
12444
|
+
status: "never-acknowledged",
|
|
12445
|
+
honoredUris: []
|
|
12446
|
+
});
|
|
12447
|
+
}
|
|
11313
12448
|
/**
|
|
11314
12449
|
* Schedule a reconnect re-listen after the current backoff delay (#1630).
|
|
11315
12450
|
* `modernReconnectAttempts` reflects the number of *consecutive failed*
|
|
@@ -11343,6 +12478,10 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11343
12478
|
* stream ended (re-subscribing resets the run and tries again).
|
|
11344
12479
|
*/
|
|
11345
12480
|
onModernReconnectFailed() {
|
|
12481
|
+
if (this.modernNeverAcknowledged && !isTerminalStatus(this.status) && this.wantsModernStream()) {
|
|
12482
|
+
this.endModernStreamNeverAcknowledged();
|
|
12483
|
+
return;
|
|
12484
|
+
}
|
|
11346
12485
|
this.modernReconnectAttempts += 1;
|
|
11347
12486
|
if (this.modernReconnectAttempts > MODERN_RECONNECT_MAX_ATTEMPTS || isTerminalStatus(this.status) || !this.wantsModernStream()) {
|
|
11348
12487
|
this.setModernStreamState({
|
|
@@ -11399,7 +12538,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11399
12538
|
this.dispatchSubscriptionsChange();
|
|
11400
12539
|
} catch (error) {
|
|
11401
12540
|
throw new Error(
|
|
11402
|
-
`Failed to subscribe to resource: ${
|
|
12541
|
+
`Failed to subscribe to resource: ${subscriptionFailureMessage(error)}`,
|
|
11403
12542
|
{ cause: error }
|
|
11404
12543
|
);
|
|
11405
12544
|
}
|
|
@@ -11444,7 +12583,7 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11444
12583
|
}
|
|
11445
12584
|
} catch (error) {
|
|
11446
12585
|
throw new Error(
|
|
11447
|
-
`Failed to unsubscribe from resource: ${
|
|
12586
|
+
`Failed to unsubscribe from resource: ${subscriptionFailureMessage(error)}`,
|
|
11448
12587
|
{ cause: error }
|
|
11449
12588
|
);
|
|
11450
12589
|
}
|
|
@@ -11715,10 +12854,23 @@ var InspectorClient = class _InspectorClient extends InspectorClientEventTarget
|
|
|
11715
12854
|
return this.oauthManager.getOAuthTokens();
|
|
11716
12855
|
}
|
|
11717
12856
|
/**
|
|
11718
|
-
*
|
|
12857
|
+
* Drop this server's stored OAuth state and revoke the grant at the
|
|
12858
|
+
* authorization server (RFC 7009, #2144).
|
|
12859
|
+
*
|
|
12860
|
+
* The request is planned from the stored state, the state is cleared, and
|
|
12861
|
+
* only then is the request sent — so the clear never waits on the network.
|
|
12862
|
+
*
|
|
12863
|
+
* The revocation is best-effort — an authorization server that advertises no
|
|
12864
|
+
* `revocation_endpoint` is left behaving exactly as before, and a network
|
|
12865
|
+
* error, a non-2xx or a timeout is reported in the returned outcome rather
|
|
12866
|
+
* than thrown — so the local clear always completes. Pass
|
|
12867
|
+
* `{ revoke: false }` to skip it.
|
|
11719
12868
|
*/
|
|
11720
|
-
async clearOAuthTokens() {
|
|
11721
|
-
await this.oauthManager?.clearOAuthTokens()
|
|
12869
|
+
async clearOAuthTokens(options) {
|
|
12870
|
+
return await this.oauthManager?.clearOAuthTokens(options) ?? {
|
|
12871
|
+
status: "skipped",
|
|
12872
|
+
reason: "no_tokens"
|
|
12873
|
+
};
|
|
11722
12874
|
}
|
|
11723
12875
|
/**
|
|
11724
12876
|
* Checks if client is currently OAuth authorized
|
|
@@ -12361,158 +13513,131 @@ var ManagedPromptsState = class extends ManagedListState {
|
|
|
12361
13513
|
};
|
|
12362
13514
|
|
|
12363
13515
|
// ../../core/react/useInspectorClient.ts
|
|
12364
|
-
import {
|
|
13516
|
+
import { useCallback as useCallback2, useEffect, useState } from "react";
|
|
13517
|
+
|
|
13518
|
+
// ../../core/react/useStoreSnapshot.ts
|
|
13519
|
+
import { useCallback, useRef, useSyncExternalStore } from "react";
|
|
13520
|
+
function useStoreSnapshot(store, event, read, whenAbsent) {
|
|
13521
|
+
const cache = useRef(null);
|
|
13522
|
+
const subscribe = useCallback(
|
|
13523
|
+
(onStoreChange) => {
|
|
13524
|
+
if (!store) return () => {
|
|
13525
|
+
};
|
|
13526
|
+
store.addEventListener(event, onStoreChange);
|
|
13527
|
+
return () => {
|
|
13528
|
+
store.removeEventListener(event, onStoreChange);
|
|
13529
|
+
};
|
|
13530
|
+
},
|
|
13531
|
+
[store, event]
|
|
13532
|
+
);
|
|
13533
|
+
const getSnapshot = useCallback(() => {
|
|
13534
|
+
const revision = store ? store.getEventRevision(event) : 0;
|
|
13535
|
+
const cached = cache.current;
|
|
13536
|
+
if (cached && Object.is(cached.store, store) && cached.event === event && cached.read === read && Object.is(cached.whenAbsent, whenAbsent) && cached.revision === revision) {
|
|
13537
|
+
return cached.value;
|
|
13538
|
+
}
|
|
13539
|
+
const value = store ? read(store) : whenAbsent;
|
|
13540
|
+
cache.current = { store, event, read, whenAbsent, revision, value };
|
|
13541
|
+
return value;
|
|
13542
|
+
}, [store, event, read, whenAbsent]);
|
|
13543
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
13544
|
+
}
|
|
13545
|
+
|
|
13546
|
+
// ../../core/react/useInspectorClient.ts
|
|
12365
13547
|
var EMPTY_CLIENT_CAPABILITIES = Object.freeze({});
|
|
13548
|
+
var NO_EXCLUDED_TOOLS = [];
|
|
13549
|
+
var NO_MALFORMED_LIST_ITEMS = [];
|
|
13550
|
+
var readStatus = (client) => client.getStatus();
|
|
13551
|
+
var readCapabilities = (client) => client.getCapabilities();
|
|
13552
|
+
var readServerInfo = (client) => client.getServerInfo();
|
|
13553
|
+
var readInstructions = (client) => client.getInstructions();
|
|
13554
|
+
var readProtocolVersion = (client) => client.getProtocolVersion();
|
|
13555
|
+
var readProtocolEra = (client) => client.getProtocolEra();
|
|
13556
|
+
var readDiscoverResult = (client) => client.getDiscoverResult();
|
|
13557
|
+
var readExcludedTools = (client) => client.getExcludedTools();
|
|
13558
|
+
var readMalformedListItems = (client) => client.getMalformedListItems();
|
|
12366
13559
|
function useInspectorClient(inspectorClient) {
|
|
12367
|
-
const
|
|
12368
|
-
inspectorClient
|
|
13560
|
+
const status = useStoreSnapshot(
|
|
13561
|
+
inspectorClient,
|
|
13562
|
+
"statusChange",
|
|
13563
|
+
readStatus,
|
|
13564
|
+
"disconnected"
|
|
13565
|
+
);
|
|
13566
|
+
const capabilities = useStoreSnapshot(
|
|
13567
|
+
inspectorClient,
|
|
13568
|
+
"capabilitiesChange",
|
|
13569
|
+
readCapabilities,
|
|
13570
|
+
void 0
|
|
13571
|
+
);
|
|
13572
|
+
const serverInfo = useStoreSnapshot(
|
|
13573
|
+
inspectorClient,
|
|
13574
|
+
"serverInfoChange",
|
|
13575
|
+
readServerInfo,
|
|
13576
|
+
void 0
|
|
12369
13577
|
);
|
|
12370
|
-
const
|
|
12371
|
-
|
|
12372
|
-
|
|
13578
|
+
const instructions = useStoreSnapshot(
|
|
13579
|
+
inspectorClient,
|
|
13580
|
+
"instructionsChange",
|
|
13581
|
+
readInstructions,
|
|
13582
|
+
void 0
|
|
12373
13583
|
);
|
|
12374
|
-
const
|
|
12375
|
-
inspectorClient
|
|
13584
|
+
const protocolVersion = useStoreSnapshot(
|
|
13585
|
+
inspectorClient,
|
|
13586
|
+
"protocolVersionChange",
|
|
13587
|
+
readProtocolVersion,
|
|
13588
|
+
void 0
|
|
12376
13589
|
);
|
|
12377
|
-
const
|
|
12378
|
-
inspectorClient
|
|
13590
|
+
const protocolEra = useStoreSnapshot(
|
|
13591
|
+
inspectorClient,
|
|
13592
|
+
"protocolEraChange",
|
|
13593
|
+
readProtocolEra,
|
|
13594
|
+
void 0
|
|
12379
13595
|
);
|
|
12380
|
-
const
|
|
12381
|
-
inspectorClient
|
|
13596
|
+
const discoverResult = useStoreSnapshot(
|
|
13597
|
+
inspectorClient,
|
|
13598
|
+
"discoverResultChange",
|
|
13599
|
+
readDiscoverResult,
|
|
13600
|
+
void 0
|
|
12382
13601
|
);
|
|
12383
|
-
const
|
|
12384
|
-
|
|
12385
|
-
|
|
13602
|
+
const excludedTools = useStoreSnapshot(
|
|
13603
|
+
inspectorClient,
|
|
13604
|
+
"excludedToolsChange",
|
|
13605
|
+
readExcludedTools,
|
|
13606
|
+
NO_EXCLUDED_TOOLS
|
|
12386
13607
|
);
|
|
12387
|
-
const
|
|
12388
|
-
|
|
13608
|
+
const malformedListItems = useStoreSnapshot(
|
|
13609
|
+
inspectorClient,
|
|
13610
|
+
"malformedListItemsChange",
|
|
13611
|
+
readMalformedListItems,
|
|
13612
|
+
NO_MALFORMED_LIST_ITEMS
|
|
13613
|
+
);
|
|
13614
|
+
const [errorState, setErrorState] = useState({ client: inspectorClient });
|
|
13615
|
+
if (errorState.client !== inspectorClient) {
|
|
13616
|
+
setErrorState({ client: inspectorClient });
|
|
13617
|
+
}
|
|
13618
|
+
const lastError = errorState.client === inspectorClient ? errorState.message : void 0;
|
|
12389
13619
|
useEffect(() => {
|
|
12390
|
-
if (!inspectorClient)
|
|
12391
|
-
setStatus("disconnected");
|
|
12392
|
-
setCapabilities(void 0);
|
|
12393
|
-
setServerInfo(void 0);
|
|
12394
|
-
setInstructions(void 0);
|
|
12395
|
-
setProtocolVersion(void 0);
|
|
12396
|
-
setProtocolEra(void 0);
|
|
12397
|
-
setDiscoverResult(void 0);
|
|
12398
|
-
setExcludedTools([]);
|
|
12399
|
-
setMalformedListItems([]);
|
|
12400
|
-
setLastError(void 0);
|
|
12401
|
-
return;
|
|
12402
|
-
}
|
|
12403
|
-
setStatus(inspectorClient.getStatus());
|
|
12404
|
-
setCapabilities(inspectorClient.getCapabilities());
|
|
12405
|
-
setServerInfo(inspectorClient.getServerInfo());
|
|
12406
|
-
setInstructions(inspectorClient.getInstructions());
|
|
12407
|
-
setProtocolVersion(inspectorClient.getProtocolVersion());
|
|
12408
|
-
setProtocolEra(inspectorClient.getProtocolEra());
|
|
12409
|
-
setDiscoverResult(inspectorClient.getDiscoverResult());
|
|
12410
|
-
setExcludedTools(inspectorClient.getExcludedTools());
|
|
12411
|
-
setMalformedListItems(inspectorClient.getMalformedListItems());
|
|
12412
|
-
setLastError(void 0);
|
|
13620
|
+
if (!inspectorClient) return;
|
|
12413
13621
|
const onStatusChange = (event) => {
|
|
12414
|
-
setStatus(event.detail);
|
|
12415
13622
|
if (event.detail === "connecting") {
|
|
12416
|
-
|
|
13623
|
+
setErrorState({ client: inspectorClient });
|
|
12417
13624
|
}
|
|
12418
13625
|
};
|
|
12419
13626
|
const onError = (event) => {
|
|
12420
|
-
|
|
12421
|
-
};
|
|
12422
|
-
const onCapabilitiesChange = (event) => {
|
|
12423
|
-
setCapabilities(event.detail);
|
|
12424
|
-
};
|
|
12425
|
-
const onServerInfoChange = (event) => {
|
|
12426
|
-
setServerInfo(event.detail);
|
|
12427
|
-
};
|
|
12428
|
-
const onInstructionsChange = (event) => {
|
|
12429
|
-
setInstructions(event.detail);
|
|
12430
|
-
};
|
|
12431
|
-
const onProtocolVersionChange = (event) => {
|
|
12432
|
-
setProtocolVersion(event.detail);
|
|
12433
|
-
};
|
|
12434
|
-
const onProtocolEraChange = (event) => {
|
|
12435
|
-
setProtocolEra(event.detail);
|
|
12436
|
-
};
|
|
12437
|
-
const onDiscoverResultChange = (event) => {
|
|
12438
|
-
setDiscoverResult(event.detail);
|
|
12439
|
-
};
|
|
12440
|
-
const onMalformedListItemsChange = (event) => {
|
|
12441
|
-
setMalformedListItems(event.detail);
|
|
12442
|
-
};
|
|
12443
|
-
const onExcludedToolsChange = (event) => {
|
|
12444
|
-
setExcludedTools(event.detail);
|
|
13627
|
+
setErrorState({ client: inspectorClient, message: event.detail.message });
|
|
12445
13628
|
};
|
|
12446
13629
|
inspectorClient.addEventListener("statusChange", onStatusChange);
|
|
12447
13630
|
inspectorClient.addEventListener("error", onError);
|
|
12448
|
-
inspectorClient.addEventListener(
|
|
12449
|
-
"capabilitiesChange",
|
|
12450
|
-
onCapabilitiesChange
|
|
12451
|
-
);
|
|
12452
|
-
inspectorClient.addEventListener("serverInfoChange", onServerInfoChange);
|
|
12453
|
-
inspectorClient.addEventListener(
|
|
12454
|
-
"instructionsChange",
|
|
12455
|
-
onInstructionsChange
|
|
12456
|
-
);
|
|
12457
|
-
inspectorClient.addEventListener(
|
|
12458
|
-
"protocolVersionChange",
|
|
12459
|
-
onProtocolVersionChange
|
|
12460
|
-
);
|
|
12461
|
-
inspectorClient.addEventListener("protocolEraChange", onProtocolEraChange);
|
|
12462
|
-
inspectorClient.addEventListener(
|
|
12463
|
-
"discoverResultChange",
|
|
12464
|
-
onDiscoverResultChange
|
|
12465
|
-
);
|
|
12466
|
-
inspectorClient.addEventListener(
|
|
12467
|
-
"excludedToolsChange",
|
|
12468
|
-
onExcludedToolsChange
|
|
12469
|
-
);
|
|
12470
|
-
inspectorClient.addEventListener(
|
|
12471
|
-
"malformedListItemsChange",
|
|
12472
|
-
onMalformedListItemsChange
|
|
12473
|
-
);
|
|
12474
13631
|
return () => {
|
|
12475
13632
|
inspectorClient.removeEventListener("statusChange", onStatusChange);
|
|
12476
13633
|
inspectorClient.removeEventListener("error", onError);
|
|
12477
|
-
inspectorClient.removeEventListener(
|
|
12478
|
-
"capabilitiesChange",
|
|
12479
|
-
onCapabilitiesChange
|
|
12480
|
-
);
|
|
12481
|
-
inspectorClient.removeEventListener(
|
|
12482
|
-
"serverInfoChange",
|
|
12483
|
-
onServerInfoChange
|
|
12484
|
-
);
|
|
12485
|
-
inspectorClient.removeEventListener(
|
|
12486
|
-
"instructionsChange",
|
|
12487
|
-
onInstructionsChange
|
|
12488
|
-
);
|
|
12489
|
-
inspectorClient.removeEventListener(
|
|
12490
|
-
"protocolVersionChange",
|
|
12491
|
-
onProtocolVersionChange
|
|
12492
|
-
);
|
|
12493
|
-
inspectorClient.removeEventListener(
|
|
12494
|
-
"protocolEraChange",
|
|
12495
|
-
onProtocolEraChange
|
|
12496
|
-
);
|
|
12497
|
-
inspectorClient.removeEventListener(
|
|
12498
|
-
"discoverResultChange",
|
|
12499
|
-
onDiscoverResultChange
|
|
12500
|
-
);
|
|
12501
|
-
inspectorClient.removeEventListener(
|
|
12502
|
-
"excludedToolsChange",
|
|
12503
|
-
onExcludedToolsChange
|
|
12504
|
-
);
|
|
12505
|
-
inspectorClient.removeEventListener(
|
|
12506
|
-
"malformedListItemsChange",
|
|
12507
|
-
onMalformedListItemsChange
|
|
12508
|
-
);
|
|
12509
13634
|
};
|
|
12510
13635
|
}, [inspectorClient]);
|
|
12511
|
-
const connect =
|
|
13636
|
+
const connect = useCallback2(async () => {
|
|
12512
13637
|
if (!inspectorClient) return;
|
|
12513
13638
|
await inspectorClient.connect();
|
|
12514
13639
|
}, [inspectorClient]);
|
|
12515
|
-
const disconnect =
|
|
13640
|
+
const disconnect = useCallback2(async () => {
|
|
12516
13641
|
if (!inspectorClient) return;
|
|
12517
13642
|
await inspectorClient.disconnect();
|
|
12518
13643
|
}, [inspectorClient]);
|
|
@@ -12540,12 +13665,12 @@ function useInspectorClient(inspectorClient) {
|
|
|
12540
13665
|
}
|
|
12541
13666
|
|
|
12542
13667
|
// ../../core/react/useManagedTools.ts
|
|
12543
|
-
import {
|
|
13668
|
+
import { useCallback as useCallback4 } from "react";
|
|
12544
13669
|
|
|
12545
13670
|
// ../../core/react/useListError.ts
|
|
12546
|
-
import { useCallback as
|
|
13671
|
+
import { useCallback as useCallback3, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
12547
13672
|
function useListError(state) {
|
|
12548
|
-
const subscribe =
|
|
13673
|
+
const subscribe = useCallback3(
|
|
12549
13674
|
(onStoreChange) => {
|
|
12550
13675
|
if (!state) return () => {
|
|
12551
13676
|
};
|
|
@@ -12557,277 +13682,156 @@ function useListError(state) {
|
|
|
12557
13682
|
},
|
|
12558
13683
|
[state]
|
|
12559
13684
|
);
|
|
12560
|
-
const getSnapshot =
|
|
12561
|
-
return
|
|
13685
|
+
const getSnapshot = useCallback3(() => state?.getError() ?? null, [state]);
|
|
13686
|
+
return useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
|
|
12562
13687
|
}
|
|
12563
13688
|
|
|
12564
13689
|
// ../../core/react/useManagedTools.ts
|
|
13690
|
+
var NO_TOOLS = [];
|
|
13691
|
+
var readTools = (state) => state.getTools();
|
|
13692
|
+
var readListChanged = (state) => state.getListChanged();
|
|
12565
13693
|
function useManagedTools(client, managedToolsState) {
|
|
12566
|
-
const
|
|
12567
|
-
managedToolsState
|
|
13694
|
+
const tools = useStoreSnapshot(
|
|
13695
|
+
managedToolsState,
|
|
13696
|
+
"toolsChange",
|
|
13697
|
+
readTools,
|
|
13698
|
+
NO_TOOLS
|
|
12568
13699
|
);
|
|
12569
|
-
const
|
|
12570
|
-
managedToolsState
|
|
13700
|
+
const listChanged = useStoreSnapshot(
|
|
13701
|
+
managedToolsState,
|
|
13702
|
+
"listChangedChange",
|
|
13703
|
+
readListChanged,
|
|
13704
|
+
false
|
|
12571
13705
|
);
|
|
12572
|
-
useEffect2(() => {
|
|
12573
|
-
if (!managedToolsState) {
|
|
12574
|
-
setTools([]);
|
|
12575
|
-
setListChanged(false);
|
|
12576
|
-
return;
|
|
12577
|
-
}
|
|
12578
|
-
setTools(managedToolsState.getTools());
|
|
12579
|
-
setListChanged(managedToolsState.getListChanged());
|
|
12580
|
-
const onToolsChange = (event) => {
|
|
12581
|
-
setTools(event.detail);
|
|
12582
|
-
};
|
|
12583
|
-
const onListChangedChange = (event) => {
|
|
12584
|
-
setListChanged(event.detail);
|
|
12585
|
-
};
|
|
12586
|
-
managedToolsState.addEventListener("toolsChange", onToolsChange);
|
|
12587
|
-
managedToolsState.addEventListener(
|
|
12588
|
-
"listChangedChange",
|
|
12589
|
-
onListChangedChange
|
|
12590
|
-
);
|
|
12591
|
-
return () => {
|
|
12592
|
-
managedToolsState.removeEventListener("toolsChange", onToolsChange);
|
|
12593
|
-
managedToolsState.removeEventListener(
|
|
12594
|
-
"listChangedChange",
|
|
12595
|
-
onListChangedChange
|
|
12596
|
-
);
|
|
12597
|
-
};
|
|
12598
|
-
}, [managedToolsState]);
|
|
12599
13706
|
const error = useListError(managedToolsState);
|
|
12600
|
-
const refresh =
|
|
12601
|
-
if (!managedToolsState || !client) return
|
|
13707
|
+
const refresh = useCallback4(async () => {
|
|
13708
|
+
if (!managedToolsState || !client) return NO_TOOLS;
|
|
12602
13709
|
managedToolsState.clearListChanged();
|
|
12603
|
-
|
|
12604
|
-
setTools(next);
|
|
12605
|
-
return next;
|
|
13710
|
+
return managedToolsState.refresh(void 0, "refresh");
|
|
12606
13711
|
}, [client, managedToolsState]);
|
|
12607
|
-
const clearListChanged =
|
|
13712
|
+
const clearListChanged = useCallback4(() => {
|
|
12608
13713
|
managedToolsState?.clearListChanged();
|
|
12609
13714
|
}, [managedToolsState]);
|
|
12610
13715
|
return { tools, error, listChanged, refresh, clearListChanged };
|
|
12611
13716
|
}
|
|
12612
13717
|
|
|
12613
13718
|
// ../../core/react/useManagedResources.ts
|
|
12614
|
-
import {
|
|
13719
|
+
import { useCallback as useCallback5 } from "react";
|
|
13720
|
+
var NO_RESOURCES = [];
|
|
13721
|
+
var readResources = (state) => state.getResources();
|
|
13722
|
+
var readListChanged2 = (state) => state.getListChanged();
|
|
12615
13723
|
function useManagedResources(client, managedResourcesState) {
|
|
12616
|
-
const
|
|
12617
|
-
managedResourcesState
|
|
13724
|
+
const resources = useStoreSnapshot(
|
|
13725
|
+
managedResourcesState,
|
|
13726
|
+
"resourcesChange",
|
|
13727
|
+
readResources,
|
|
13728
|
+
NO_RESOURCES
|
|
12618
13729
|
);
|
|
12619
|
-
const
|
|
12620
|
-
managedResourcesState
|
|
13730
|
+
const listChanged = useStoreSnapshot(
|
|
13731
|
+
managedResourcesState,
|
|
13732
|
+
"listChangedChange",
|
|
13733
|
+
readListChanged2,
|
|
13734
|
+
false
|
|
12621
13735
|
);
|
|
12622
|
-
useEffect3(() => {
|
|
12623
|
-
if (!managedResourcesState) {
|
|
12624
|
-
setResources([]);
|
|
12625
|
-
setListChanged(false);
|
|
12626
|
-
return;
|
|
12627
|
-
}
|
|
12628
|
-
setResources(managedResourcesState.getResources());
|
|
12629
|
-
setListChanged(managedResourcesState.getListChanged());
|
|
12630
|
-
const onResourcesChange = (event) => {
|
|
12631
|
-
setResources(event.detail);
|
|
12632
|
-
};
|
|
12633
|
-
const onListChangedChange = (event) => {
|
|
12634
|
-
setListChanged(event.detail);
|
|
12635
|
-
};
|
|
12636
|
-
managedResourcesState.addEventListener(
|
|
12637
|
-
"resourcesChange",
|
|
12638
|
-
onResourcesChange
|
|
12639
|
-
);
|
|
12640
|
-
managedResourcesState.addEventListener(
|
|
12641
|
-
"listChangedChange",
|
|
12642
|
-
onListChangedChange
|
|
12643
|
-
);
|
|
12644
|
-
return () => {
|
|
12645
|
-
managedResourcesState.removeEventListener(
|
|
12646
|
-
"resourcesChange",
|
|
12647
|
-
onResourcesChange
|
|
12648
|
-
);
|
|
12649
|
-
managedResourcesState.removeEventListener(
|
|
12650
|
-
"listChangedChange",
|
|
12651
|
-
onListChangedChange
|
|
12652
|
-
);
|
|
12653
|
-
};
|
|
12654
|
-
}, [managedResourcesState]);
|
|
12655
13736
|
const error = useListError(managedResourcesState);
|
|
12656
|
-
const refresh =
|
|
12657
|
-
if (!managedResourcesState || !client) return
|
|
13737
|
+
const refresh = useCallback5(async () => {
|
|
13738
|
+
if (!managedResourcesState || !client) return NO_RESOURCES;
|
|
12658
13739
|
managedResourcesState.clearListChanged();
|
|
12659
|
-
|
|
12660
|
-
setResources(next);
|
|
12661
|
-
return next;
|
|
13740
|
+
return managedResourcesState.refresh(void 0, "refresh");
|
|
12662
13741
|
}, [client, managedResourcesState]);
|
|
12663
|
-
const clearListChanged =
|
|
13742
|
+
const clearListChanged = useCallback5(() => {
|
|
12664
13743
|
managedResourcesState?.clearListChanged();
|
|
12665
13744
|
}, [managedResourcesState]);
|
|
12666
13745
|
return { resources, error, listChanged, refresh, clearListChanged };
|
|
12667
13746
|
}
|
|
12668
13747
|
|
|
12669
13748
|
// ../../core/react/useManagedResourceTemplates.ts
|
|
12670
|
-
import {
|
|
13749
|
+
import { useCallback as useCallback6 } from "react";
|
|
13750
|
+
var NO_RESOURCE_TEMPLATES = [];
|
|
13751
|
+
var readResourceTemplates = (state) => state.getResourceTemplates();
|
|
12671
13752
|
function useManagedResourceTemplates(client, managedResourceTemplatesState) {
|
|
12672
|
-
const
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
setResourceTemplates(managedResourceTemplatesState.getResourceTemplates());
|
|
12679
|
-
const onResourceTemplatesChange = (event) => {
|
|
12680
|
-
setResourceTemplates(event.detail);
|
|
12681
|
-
};
|
|
12682
|
-
managedResourceTemplatesState.addEventListener(
|
|
12683
|
-
"resourceTemplatesChange",
|
|
12684
|
-
onResourceTemplatesChange
|
|
12685
|
-
);
|
|
12686
|
-
return () => {
|
|
12687
|
-
managedResourceTemplatesState.removeEventListener(
|
|
12688
|
-
"resourceTemplatesChange",
|
|
12689
|
-
onResourceTemplatesChange
|
|
12690
|
-
);
|
|
12691
|
-
};
|
|
12692
|
-
}, [managedResourceTemplatesState]);
|
|
13753
|
+
const resourceTemplates = useStoreSnapshot(
|
|
13754
|
+
managedResourceTemplatesState,
|
|
13755
|
+
"resourceTemplatesChange",
|
|
13756
|
+
readResourceTemplates,
|
|
13757
|
+
NO_RESOURCE_TEMPLATES
|
|
13758
|
+
);
|
|
12693
13759
|
const error = useListError(managedResourceTemplatesState);
|
|
12694
|
-
const refresh =
|
|
12695
|
-
if (!managedResourceTemplatesState || !client)
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
);
|
|
12700
|
-
setResourceTemplates(next);
|
|
12701
|
-
return next;
|
|
13760
|
+
const refresh = useCallback6(async () => {
|
|
13761
|
+
if (!managedResourceTemplatesState || !client) {
|
|
13762
|
+
return NO_RESOURCE_TEMPLATES;
|
|
13763
|
+
}
|
|
13764
|
+
return managedResourceTemplatesState.refresh(void 0, "refresh");
|
|
12702
13765
|
}, [client, managedResourceTemplatesState]);
|
|
12703
13766
|
return { resourceTemplates, error, refresh };
|
|
12704
13767
|
}
|
|
12705
13768
|
|
|
12706
13769
|
// ../../core/react/useManagedPrompts.ts
|
|
12707
|
-
import {
|
|
13770
|
+
import { useCallback as useCallback7 } from "react";
|
|
13771
|
+
var NO_PROMPTS = [];
|
|
13772
|
+
var readPrompts = (state) => state.getPrompts();
|
|
13773
|
+
var readListChanged3 = (state) => state.getListChanged();
|
|
12708
13774
|
function useManagedPrompts(client, managedPromptsState) {
|
|
12709
|
-
const
|
|
12710
|
-
managedPromptsState
|
|
13775
|
+
const prompts = useStoreSnapshot(
|
|
13776
|
+
managedPromptsState,
|
|
13777
|
+
"promptsChange",
|
|
13778
|
+
readPrompts,
|
|
13779
|
+
NO_PROMPTS
|
|
12711
13780
|
);
|
|
12712
|
-
const
|
|
12713
|
-
managedPromptsState
|
|
13781
|
+
const listChanged = useStoreSnapshot(
|
|
13782
|
+
managedPromptsState,
|
|
13783
|
+
"listChangedChange",
|
|
13784
|
+
readListChanged3,
|
|
13785
|
+
false
|
|
12714
13786
|
);
|
|
12715
|
-
useEffect5(() => {
|
|
12716
|
-
if (!managedPromptsState) {
|
|
12717
|
-
setPrompts([]);
|
|
12718
|
-
setListChanged(false);
|
|
12719
|
-
return;
|
|
12720
|
-
}
|
|
12721
|
-
setPrompts(managedPromptsState.getPrompts());
|
|
12722
|
-
setListChanged(managedPromptsState.getListChanged());
|
|
12723
|
-
const onPromptsChange = (event) => {
|
|
12724
|
-
setPrompts(event.detail);
|
|
12725
|
-
};
|
|
12726
|
-
const onListChangedChange = (event) => {
|
|
12727
|
-
setListChanged(event.detail);
|
|
12728
|
-
};
|
|
12729
|
-
managedPromptsState.addEventListener("promptsChange", onPromptsChange);
|
|
12730
|
-
managedPromptsState.addEventListener(
|
|
12731
|
-
"listChangedChange",
|
|
12732
|
-
onListChangedChange
|
|
12733
|
-
);
|
|
12734
|
-
return () => {
|
|
12735
|
-
managedPromptsState.removeEventListener("promptsChange", onPromptsChange);
|
|
12736
|
-
managedPromptsState.removeEventListener(
|
|
12737
|
-
"listChangedChange",
|
|
12738
|
-
onListChangedChange
|
|
12739
|
-
);
|
|
12740
|
-
};
|
|
12741
|
-
}, [managedPromptsState]);
|
|
12742
13787
|
const error = useListError(managedPromptsState);
|
|
12743
|
-
const refresh =
|
|
12744
|
-
if (!managedPromptsState || !client) return
|
|
13788
|
+
const refresh = useCallback7(async () => {
|
|
13789
|
+
if (!managedPromptsState || !client) return NO_PROMPTS;
|
|
12745
13790
|
managedPromptsState.clearListChanged();
|
|
12746
|
-
|
|
12747
|
-
setPrompts(next);
|
|
12748
|
-
return next;
|
|
13791
|
+
return managedPromptsState.refresh(void 0, "refresh");
|
|
12749
13792
|
}, [client, managedPromptsState]);
|
|
12750
|
-
const clearListChanged =
|
|
13793
|
+
const clearListChanged = useCallback7(() => {
|
|
12751
13794
|
managedPromptsState?.clearListChanged();
|
|
12752
13795
|
}, [managedPromptsState]);
|
|
12753
13796
|
return { prompts, error, listChanged, refresh, clearListChanged };
|
|
12754
13797
|
}
|
|
12755
13798
|
|
|
12756
13799
|
// ../../core/react/useMessageLog.ts
|
|
12757
|
-
|
|
13800
|
+
var NO_MESSAGES = [];
|
|
13801
|
+
var readMessages = (state) => state.getMessages();
|
|
12758
13802
|
function useMessageLog(messageLogState) {
|
|
12759
|
-
const
|
|
12760
|
-
messageLogState
|
|
13803
|
+
const messages = useStoreSnapshot(
|
|
13804
|
+
messageLogState,
|
|
13805
|
+
"messagesChange",
|
|
13806
|
+
readMessages,
|
|
13807
|
+
NO_MESSAGES
|
|
12761
13808
|
);
|
|
12762
|
-
useEffect6(() => {
|
|
12763
|
-
if (!messageLogState) {
|
|
12764
|
-
setMessages([]);
|
|
12765
|
-
return;
|
|
12766
|
-
}
|
|
12767
|
-
setMessages(messageLogState.getMessages());
|
|
12768
|
-
const onMessagesChange = (event) => {
|
|
12769
|
-
setMessages(event.detail);
|
|
12770
|
-
};
|
|
12771
|
-
messageLogState.addEventListener("messagesChange", onMessagesChange);
|
|
12772
|
-
return () => {
|
|
12773
|
-
messageLogState.removeEventListener("messagesChange", onMessagesChange);
|
|
12774
|
-
};
|
|
12775
|
-
}, [messageLogState]);
|
|
12776
13809
|
return { messages };
|
|
12777
13810
|
}
|
|
12778
13811
|
|
|
12779
13812
|
// ../../core/react/useFetchRequestLog.ts
|
|
12780
|
-
|
|
13813
|
+
var NO_FETCH_REQUESTS = [];
|
|
13814
|
+
var readFetchRequests = (state) => state.getFetchRequests();
|
|
12781
13815
|
function useFetchRequestLog(fetchRequestLogState) {
|
|
12782
|
-
const
|
|
12783
|
-
fetchRequestLogState
|
|
13816
|
+
const fetchRequests = useStoreSnapshot(
|
|
13817
|
+
fetchRequestLogState,
|
|
13818
|
+
"fetchRequestsChange",
|
|
13819
|
+
readFetchRequests,
|
|
13820
|
+
NO_FETCH_REQUESTS
|
|
12784
13821
|
);
|
|
12785
|
-
useEffect7(() => {
|
|
12786
|
-
if (!fetchRequestLogState) {
|
|
12787
|
-
setFetchRequests([]);
|
|
12788
|
-
return;
|
|
12789
|
-
}
|
|
12790
|
-
setFetchRequests(fetchRequestLogState.getFetchRequests());
|
|
12791
|
-
const onFetchRequestsChange = (event) => {
|
|
12792
|
-
setFetchRequests(event.detail);
|
|
12793
|
-
};
|
|
12794
|
-
fetchRequestLogState.addEventListener(
|
|
12795
|
-
"fetchRequestsChange",
|
|
12796
|
-
onFetchRequestsChange
|
|
12797
|
-
);
|
|
12798
|
-
return () => {
|
|
12799
|
-
fetchRequestLogState.removeEventListener(
|
|
12800
|
-
"fetchRequestsChange",
|
|
12801
|
-
onFetchRequestsChange
|
|
12802
|
-
);
|
|
12803
|
-
};
|
|
12804
|
-
}, [fetchRequestLogState]);
|
|
12805
13822
|
return { fetchRequests };
|
|
12806
13823
|
}
|
|
12807
13824
|
|
|
12808
13825
|
// ../../core/react/useStderrLog.ts
|
|
12809
|
-
|
|
13826
|
+
var NO_STDERR_LOGS = [];
|
|
13827
|
+
var readStderrLogs = (state) => state.getStderrLogs();
|
|
12810
13828
|
function useStderrLog(stderrLogState) {
|
|
12811
|
-
const
|
|
12812
|
-
stderrLogState
|
|
13829
|
+
const stderrLogs = useStoreSnapshot(
|
|
13830
|
+
stderrLogState,
|
|
13831
|
+
"stderrLogsChange",
|
|
13832
|
+
readStderrLogs,
|
|
13833
|
+
NO_STDERR_LOGS
|
|
12813
13834
|
);
|
|
12814
|
-
useEffect8(() => {
|
|
12815
|
-
if (!stderrLogState) {
|
|
12816
|
-
setStderrLogs([]);
|
|
12817
|
-
return;
|
|
12818
|
-
}
|
|
12819
|
-
setStderrLogs(stderrLogState.getStderrLogs());
|
|
12820
|
-
const onStderrLogsChange = (event) => {
|
|
12821
|
-
setStderrLogs(event.detail);
|
|
12822
|
-
};
|
|
12823
|
-
stderrLogState.addEventListener("stderrLogsChange", onStderrLogsChange);
|
|
12824
|
-
return () => {
|
|
12825
|
-
stderrLogState.removeEventListener(
|
|
12826
|
-
"stderrLogsChange",
|
|
12827
|
-
onStderrLogsChange
|
|
12828
|
-
);
|
|
12829
|
-
};
|
|
12830
|
-
}, [stderrLogState]);
|
|
12831
13835
|
return { stderrLogs };
|
|
12832
13836
|
}
|
|
12833
13837
|
|
|
@@ -12926,8 +13930,8 @@ function readInspectorVersion(callerUrl) {
|
|
|
12926
13930
|
|
|
12927
13931
|
// ../../core/auth/oauth-storage.ts
|
|
12928
13932
|
import {
|
|
12929
|
-
OAuthClientInformationSchema,
|
|
12930
|
-
OAuthTokensSchema as
|
|
13933
|
+
OAuthClientInformationSchema as OAuthClientInformationSchema2,
|
|
13934
|
+
OAuthTokensSchema as OAuthTokensSchema3
|
|
12931
13935
|
} from "@modelcontextprotocol/core";
|
|
12932
13936
|
function withIssuer(value, issuer) {
|
|
12933
13937
|
return issuer === void 0 ? value : { ...value, issuer };
|
|
@@ -13013,7 +14017,7 @@ var OAuthStorageBase = class {
|
|
|
13013
14017
|
const state = this.memory.getState().getServerState(serverUrl);
|
|
13014
14018
|
if (isPreregistered) {
|
|
13015
14019
|
const prereg = state.preregisteredClientInformation;
|
|
13016
|
-
return prereg ? await
|
|
14020
|
+
return prereg ? await OAuthClientInformationSchema2.parseAsync(prereg) : void 0;
|
|
13017
14021
|
}
|
|
13018
14022
|
const slot = this.issuerSlot(state, issuer);
|
|
13019
14023
|
const fromSlot = slot?.clientInformation;
|
|
@@ -13021,7 +14025,7 @@ var OAuthStorageBase = class {
|
|
|
13021
14025
|
if (!clientInfo) {
|
|
13022
14026
|
return void 0;
|
|
13023
14027
|
}
|
|
13024
|
-
const parsed = await
|
|
14028
|
+
const parsed = await OAuthClientInformationSchema2.parseAsync(clientInfo);
|
|
13025
14029
|
return withIssuer(
|
|
13026
14030
|
parsed,
|
|
13027
14031
|
fromSlot ? this.resolveReadIssuer(state, issuer) : void 0
|
|
@@ -13100,7 +14104,7 @@ var OAuthStorageBase = class {
|
|
|
13100
14104
|
if (!tokens) {
|
|
13101
14105
|
return void 0;
|
|
13102
14106
|
}
|
|
13103
|
-
const parsed = await
|
|
14107
|
+
const parsed = await OAuthTokensSchema3.parseAsync(tokens);
|
|
13104
14108
|
return withIssuer(
|
|
13105
14109
|
parsed,
|
|
13106
14110
|
fromSlot ? this.resolveReadIssuer(state, issuer) : void 0
|
|
@@ -13206,6 +14210,25 @@ var OAuthStorageBase = class {
|
|
|
13206
14210
|
this.memory.getState().setServerState(serverUrl, { discoveryState: void 0 });
|
|
13207
14211
|
await this.persist();
|
|
13208
14212
|
}
|
|
14213
|
+
async takeRevocationSnapshot(serverUrl) {
|
|
14214
|
+
await this.ensureLoaded();
|
|
14215
|
+
const state = this.memory.getState().getServerState(serverUrl);
|
|
14216
|
+
const snapshot = {
|
|
14217
|
+
byIssuer: Object.fromEntries(
|
|
14218
|
+
Object.entries(state.byIssuer ?? {}).map(([issuer, slot]) => [
|
|
14219
|
+
issuer,
|
|
14220
|
+
{ tokens: slot?.tokens, clientInformation: slot?.clientInformation }
|
|
14221
|
+
])
|
|
14222
|
+
),
|
|
14223
|
+
legacyTokens: state.tokens,
|
|
14224
|
+
legacyClientInformation: state.clientInformation,
|
|
14225
|
+
preregisteredClientInformation: state.preregisteredClientInformation,
|
|
14226
|
+
serverMetadata: state.serverMetadata
|
|
14227
|
+
};
|
|
14228
|
+
this.memory.getState().clearServerState(serverUrl);
|
|
14229
|
+
await this.persist();
|
|
14230
|
+
return snapshot;
|
|
14231
|
+
}
|
|
13209
14232
|
async clear(serverUrl) {
|
|
13210
14233
|
await this.ensureLoaded();
|
|
13211
14234
|
this.memory.getState().clearServerState(serverUrl);
|
|
@@ -13634,6 +14657,11 @@ async function runRunnerInteractiveOAuth(options) {
|
|
|
13634
14657
|
}
|
|
13635
14658
|
}
|
|
13636
14659
|
|
|
14660
|
+
// src/oauthMessageTone.ts
|
|
14661
|
+
function oauthMessageToneFor(message, warningText) {
|
|
14662
|
+
return message !== null && message === warningText ? "warning" : "info";
|
|
14663
|
+
}
|
|
14664
|
+
|
|
13637
14665
|
// src/logger.ts
|
|
13638
14666
|
import path5 from "path";
|
|
13639
14667
|
import pino from "pino";
|
|
@@ -13759,24 +14787,24 @@ function Tabs({
|
|
|
13759
14787
|
}
|
|
13760
14788
|
|
|
13761
14789
|
// src/components/InfoTab.tsx
|
|
13762
|
-
import { useRef as
|
|
14790
|
+
import { useRef as useRef4 } from "react";
|
|
13763
14791
|
import { Box as Box3, Text as Text2, useInput } from "ink";
|
|
13764
14792
|
|
|
13765
14793
|
// node_modules/ink-scroll-view/dist/index.js
|
|
13766
14794
|
import {
|
|
13767
|
-
useState as
|
|
14795
|
+
useState as useState2,
|
|
13768
14796
|
useRef as useRef2,
|
|
13769
14797
|
forwardRef as forwardRef2,
|
|
13770
14798
|
useImperativeHandle as useImperativeHandle2,
|
|
13771
14799
|
useCallback as useCallback22
|
|
13772
14800
|
} from "react";
|
|
13773
14801
|
import {
|
|
13774
|
-
useState as
|
|
13775
|
-
useRef,
|
|
14802
|
+
useState as useState3,
|
|
14803
|
+
useRef as useRef3,
|
|
13776
14804
|
forwardRef,
|
|
13777
14805
|
useImperativeHandle,
|
|
13778
14806
|
useLayoutEffect,
|
|
13779
|
-
useCallback as
|
|
14807
|
+
useCallback as useCallback8,
|
|
13780
14808
|
Children,
|
|
13781
14809
|
isValidElement
|
|
13782
14810
|
} from "react";
|
|
@@ -13790,7 +14818,7 @@ var MeasurableItem = ({
|
|
|
13790
14818
|
width,
|
|
13791
14819
|
measureKey
|
|
13792
14820
|
}) => {
|
|
13793
|
-
const ref =
|
|
14821
|
+
const ref = useRef3(null);
|
|
13794
14822
|
useLayoutEffect(() => {
|
|
13795
14823
|
if (ref.current) {
|
|
13796
14824
|
const { height } = measureElement(ref.current);
|
|
@@ -13800,14 +14828,14 @@ var MeasurableItem = ({
|
|
|
13800
14828
|
return /* @__PURE__ */ jsx2(Box2, { ref, flexShrink: 0, width: "100%", flexDirection: "column", children });
|
|
13801
14829
|
};
|
|
13802
14830
|
function useStateRef(initialValue) {
|
|
13803
|
-
const [state, setStateInternal] =
|
|
13804
|
-
const ref =
|
|
13805
|
-
const setState =
|
|
14831
|
+
const [state, setStateInternal] = useState3(initialValue);
|
|
14832
|
+
const ref = useRef3(initialValue);
|
|
14833
|
+
const setState = useCallback8((update) => {
|
|
13806
14834
|
const nextValue = typeof update === "function" ? update(ref.current) : update;
|
|
13807
14835
|
ref.current = nextValue;
|
|
13808
14836
|
setStateInternal(nextValue);
|
|
13809
14837
|
}, []);
|
|
13810
|
-
const getState =
|
|
14838
|
+
const getState = useCallback8(() => ref.current, []);
|
|
13811
14839
|
return [state, setState, getState];
|
|
13812
14840
|
}
|
|
13813
14841
|
var ControlledScrollView = forwardRef(
|
|
@@ -13825,21 +14853,21 @@ var ControlledScrollView = forwardRef(
|
|
|
13825
14853
|
width: 0
|
|
13826
14854
|
});
|
|
13827
14855
|
const [contentHeight, setContentHeight, getContentHeight] = useStateRef(0);
|
|
13828
|
-
const [itemMeasureKeys, setItemMeasureKeys] =
|
|
13829
|
-
const viewportRef =
|
|
13830
|
-
const contentRef =
|
|
13831
|
-
const prevContentHeightRef =
|
|
14856
|
+
const [itemMeasureKeys, setItemMeasureKeys] = useState3({});
|
|
14857
|
+
const viewportRef = useRef3(null);
|
|
14858
|
+
const contentRef = useRef3(null);
|
|
14859
|
+
const prevContentHeightRef = useRef3(0);
|
|
13832
14860
|
useLayoutEffect(() => {
|
|
13833
14861
|
if (contentHeight !== prevContentHeightRef.current) {
|
|
13834
14862
|
onContentHeightChange?.(contentHeight, prevContentHeightRef.current);
|
|
13835
14863
|
prevContentHeightRef.current = contentHeight;
|
|
13836
14864
|
}
|
|
13837
14865
|
}, [contentHeight, onContentHeightChange]);
|
|
13838
|
-
const itemHeightsRef =
|
|
13839
|
-
const itemKeysRef =
|
|
13840
|
-
const itemOffsetsRef =
|
|
13841
|
-
const firstInvalidOffsetIndexRef =
|
|
13842
|
-
const handleItemMeasure =
|
|
14866
|
+
const itemHeightsRef = useRef3({});
|
|
14867
|
+
const itemKeysRef = useRef3([]);
|
|
14868
|
+
const itemOffsetsRef = useRef3([]);
|
|
14869
|
+
const firstInvalidOffsetIndexRef = useRef3(0);
|
|
14870
|
+
const handleItemMeasure = useCallback8(
|
|
13843
14871
|
(index, height) => {
|
|
13844
14872
|
const key = itemKeysRef.current[index] || index;
|
|
13845
14873
|
if (itemHeightsRef.current[key] !== height) {
|
|
@@ -13870,7 +14898,7 @@ var ControlledScrollView = forwardRef(
|
|
|
13870
14898
|
setContentHeight
|
|
13871
14899
|
]
|
|
13872
14900
|
);
|
|
13873
|
-
const measureViewport =
|
|
14901
|
+
const measureViewport = useCallback8(() => {
|
|
13874
14902
|
if (viewportRef.current) {
|
|
13875
14903
|
const { width, height } = measureElement(viewportRef.current);
|
|
13876
14904
|
const currentSize = getViewportSize();
|
|
@@ -13883,7 +14911,7 @@ var ControlledScrollView = forwardRef(
|
|
|
13883
14911
|
useLayoutEffect(() => {
|
|
13884
14912
|
measureViewport();
|
|
13885
14913
|
});
|
|
13886
|
-
const prevChildrenRef =
|
|
14914
|
+
const prevChildrenRef = useRef3(null);
|
|
13887
14915
|
if (prevChildrenRef.current !== children) {
|
|
13888
14916
|
prevChildrenRef.current = children;
|
|
13889
14917
|
const newItemKeys = [];
|
|
@@ -13980,7 +15008,7 @@ var ControlledScrollView = forwardRef(
|
|
|
13980
15008
|
}
|
|
13981
15009
|
);
|
|
13982
15010
|
function useStateRef2(initialValue) {
|
|
13983
|
-
const [state, setStateInternal] =
|
|
15011
|
+
const [state, setStateInternal] = useState2(initialValue);
|
|
13984
15012
|
const ref = useRef2(initialValue);
|
|
13985
15013
|
const setState = useCallback22((update) => {
|
|
13986
15014
|
const nextValue = typeof update === "function" ? update(ref.current) : update;
|
|
@@ -14109,7 +15137,7 @@ function InfoTab({
|
|
|
14109
15137
|
" ",
|
|
14110
15138
|
headerPairs.map(({ key, value }) => `${key}=${value}`).join(", ")
|
|
14111
15139
|
] }) }) : null;
|
|
14112
|
-
const scrollViewRef =
|
|
15140
|
+
const scrollViewRef = useRef4(null);
|
|
14113
15141
|
useInput(
|
|
14114
15142
|
(input, key) => {
|
|
14115
15143
|
if (focused) {
|
|
@@ -14231,7 +15259,7 @@ function InfoTab({
|
|
|
14231
15259
|
}
|
|
14232
15260
|
|
|
14233
15261
|
// src/components/AuthTab.tsx
|
|
14234
|
-
import { useState as
|
|
15262
|
+
import { useState as useState4, useEffect as useEffect2, useRef as useRef5, useCallback as useCallback9 } from "react";
|
|
14235
15263
|
import { Box as Box5, Text as Text4, useInput as useInput2 } from "ink";
|
|
14236
15264
|
|
|
14237
15265
|
// src/components/SelectableItem.tsx
|
|
@@ -14294,6 +15322,7 @@ function AuthTab({
|
|
|
14294
15322
|
inspectorClient,
|
|
14295
15323
|
oauthStatus,
|
|
14296
15324
|
oauthMessage,
|
|
15325
|
+
oauthMessageTone = "info",
|
|
14297
15326
|
oauthRevision,
|
|
14298
15327
|
pendingStepUp,
|
|
14299
15328
|
onAuthorizeStepUp,
|
|
@@ -14305,12 +15334,28 @@ function AuthTab({
|
|
|
14305
15334
|
connectionStatus
|
|
14306
15335
|
}) {
|
|
14307
15336
|
const isLiveConnection = connectionStatus === "connected" || connectionStatus === "connecting";
|
|
14308
|
-
const scrollViewRef =
|
|
14309
|
-
const [oauthState, setOauthState] =
|
|
14310
|
-
const [
|
|
14311
|
-
const [
|
|
14312
|
-
const
|
|
14313
|
-
const
|
|
15337
|
+
const scrollViewRef = useRef5(null);
|
|
15338
|
+
const [oauthState, setOauthState] = useState4(void 0);
|
|
15339
|
+
const [clearState, setClearState] = useState4("idle");
|
|
15340
|
+
const [clearFailure, setClearFailure] = useState4(null);
|
|
15341
|
+
const clearAttemptRef = useRef5(0);
|
|
15342
|
+
const clearInFlightRef = useRef5(false);
|
|
15343
|
+
const ownClearRef = useRef5(false);
|
|
15344
|
+
const serverNameRef = useRef5(serverName);
|
|
15345
|
+
useEffect2(() => {
|
|
15346
|
+
serverNameRef.current = serverName;
|
|
15347
|
+
}, [serverName]);
|
|
15348
|
+
useEffect2(() => {
|
|
15349
|
+
clearAttemptRef.current++;
|
|
15350
|
+
clearInFlightRef.current = false;
|
|
15351
|
+
ownClearRef.current = false;
|
|
15352
|
+
setClearState("idle");
|
|
15353
|
+
setClearFailure(null);
|
|
15354
|
+
setLastClearDisconnected(false);
|
|
15355
|
+
}, [serverName]);
|
|
15356
|
+
const [lastClearDisconnected, setLastClearDisconnected] = useState4(false);
|
|
15357
|
+
const [stepUpChoiceIndex, setStepUpChoiceIndex] = useState4(0);
|
|
15358
|
+
const refreshOAuthState = useCallback9(async () => {
|
|
14314
15359
|
if (!inspectorClient) {
|
|
14315
15360
|
setOauthState(void 0);
|
|
14316
15361
|
return;
|
|
@@ -14318,17 +15363,22 @@ function AuthTab({
|
|
|
14318
15363
|
const state = await inspectorClient.getOAuthState();
|
|
14319
15364
|
setOauthState(state);
|
|
14320
15365
|
}, [inspectorClient]);
|
|
14321
|
-
|
|
15366
|
+
useEffect2(() => {
|
|
14322
15367
|
void refreshOAuthState();
|
|
14323
15368
|
}, [refreshOAuthState, oauthRevision, connectionStatus]);
|
|
14324
|
-
|
|
14325
|
-
|
|
15369
|
+
useEffect2(() => {
|
|
15370
|
+
if (ownClearRef.current) {
|
|
15371
|
+
ownClearRef.current = false;
|
|
15372
|
+
return;
|
|
15373
|
+
}
|
|
15374
|
+
setClearState("idle");
|
|
15375
|
+
setClearFailure(null);
|
|
14326
15376
|
setLastClearDisconnected(false);
|
|
14327
15377
|
}, [oauthRevision]);
|
|
14328
|
-
|
|
15378
|
+
useEffect2(() => {
|
|
14329
15379
|
setStepUpChoiceIndex(0);
|
|
14330
15380
|
}, [pendingStepUp]);
|
|
14331
|
-
|
|
15381
|
+
useEffect2(() => {
|
|
14332
15382
|
if (!inspectorClient) return;
|
|
14333
15383
|
const update = () => {
|
|
14334
15384
|
void refreshOAuthState();
|
|
@@ -14379,9 +15429,29 @@ function AuthTab({
|
|
|
14379
15429
|
const h = scrollViewRef.current.getViewportHeight() || 1;
|
|
14380
15430
|
scrollViewRef.current.scrollBy(h);
|
|
14381
15431
|
} else if (input.toLowerCase() === "s") {
|
|
15432
|
+
if (clearInFlightRef.current) return;
|
|
15433
|
+
clearInFlightRef.current = true;
|
|
15434
|
+
const attempt = ++clearAttemptRef.current;
|
|
15435
|
+
const attemptServer = serverName;
|
|
14382
15436
|
setLastClearDisconnected(isLiveConnection);
|
|
14383
|
-
|
|
14384
|
-
|
|
15437
|
+
setClearFailure(null);
|
|
15438
|
+
ownClearRef.current = true;
|
|
15439
|
+
setClearState("clearing");
|
|
15440
|
+
const current = () => clearAttemptRef.current === attempt && serverNameRef.current === attemptServer;
|
|
15441
|
+
void Promise.resolve(onClearOAuth()).then(
|
|
15442
|
+
() => {
|
|
15443
|
+
if (!current()) return;
|
|
15444
|
+
clearInFlightRef.current = false;
|
|
15445
|
+
setClearState("cleared");
|
|
15446
|
+
},
|
|
15447
|
+
(err) => {
|
|
15448
|
+
if (!current()) return;
|
|
15449
|
+
clearInFlightRef.current = false;
|
|
15450
|
+
ownClearRef.current = false;
|
|
15451
|
+
setClearFailure(err instanceof Error ? err.message : String(err));
|
|
15452
|
+
setClearState("failed");
|
|
15453
|
+
}
|
|
15454
|
+
);
|
|
14385
15455
|
}
|
|
14386
15456
|
},
|
|
14387
15457
|
{ isActive: focused }
|
|
@@ -14396,7 +15466,7 @@ function AuthTab({
|
|
|
14396
15466
|
/* @__PURE__ */ jsx5(ScrollView, { ref: scrollViewRef, height: height - 8, children: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 0, children: [
|
|
14397
15467
|
oauthStatus === "authenticating" && /* @__PURE__ */ jsx5(Text4, { color: "yellow", children: "Authenticating\u2026" }),
|
|
14398
15468
|
oauthStatus === "error" && oauthMessage && /* @__PURE__ */ jsx5(Text4, { color: "red", children: oauthMessage }),
|
|
14399
|
-
oauthStatus === "idle" && oauthMessage && /* @__PURE__ */ jsx5(Text4, { color: "cyan", children: oauthMessage }),
|
|
15469
|
+
oauthStatus === "idle" && oauthMessage && /* @__PURE__ */ jsx5(Text4, { color: oauthMessageTone === "warning" ? "yellow" : "cyan", children: oauthMessage }),
|
|
14400
15470
|
pendingStepUp ? /* @__PURE__ */ jsxs4(Box5, { marginTop: 1, flexDirection: "column", gap: 0, children: [
|
|
14401
15471
|
/* @__PURE__ */ jsx5(Text4, { bold: true, color: "yellow", children: stepUpModalTitle({
|
|
14402
15472
|
enterpriseManaged: pendingStepUp.enterpriseManaged
|
|
@@ -14505,7 +15575,12 @@ function AuthTab({
|
|
|
14505
15575
|
"tate",
|
|
14506
15576
|
isLiveConnection && " and disconnect"
|
|
14507
15577
|
] }),
|
|
14508
|
-
|
|
15578
|
+
clearState === "clearing" && /* @__PURE__ */ jsx5(Text4, { color: "yellow", children: "Clearing OAuth state\u2026" }),
|
|
15579
|
+
clearState === "cleared" && /* @__PURE__ */ jsx5(Text4, { color: "green", children: lastClearDisconnected ? "OAuth state cleared. Disconnected." : "OAuth state cleared." }),
|
|
15580
|
+
clearState === "failed" && /* @__PURE__ */ jsxs4(Text4, { color: "red", children: [
|
|
15581
|
+
"Could not clear OAuth state",
|
|
15582
|
+
clearFailure ? `: ${clearFailure}` : "."
|
|
15583
|
+
] })
|
|
14509
15584
|
] })
|
|
14510
15585
|
] }) }),
|
|
14511
15586
|
focused && /* @__PURE__ */ jsx5(
|
|
@@ -14522,20 +15597,20 @@ function AuthTab({
|
|
|
14522
15597
|
}
|
|
14523
15598
|
|
|
14524
15599
|
// src/components/ResourcesTab.tsx
|
|
14525
|
-
import { useState as
|
|
15600
|
+
import { useState as useState6, useEffect as useEffect4, useRef as useRef6, useMemo } from "react";
|
|
14526
15601
|
import { Box as Box6, Text as Text5, useInput as useInput3 } from "ink";
|
|
14527
15602
|
|
|
14528
15603
|
// src/hooks/useSelectableList.ts
|
|
14529
|
-
import { useState as
|
|
15604
|
+
import { useState as useState5, useEffect as useEffect3, useCallback as useCallback10 } from "react";
|
|
14530
15605
|
function clampFirstVisible(first, selected, visibleCount) {
|
|
14531
15606
|
if (selected < first) return selected;
|
|
14532
15607
|
if (selected >= first + visibleCount) return selected - visibleCount + 1;
|
|
14533
15608
|
return first;
|
|
14534
15609
|
}
|
|
14535
15610
|
function useSelectableList(itemCount, visibleCount, options) {
|
|
14536
|
-
const [selectedIndex, setSelectedIndex] =
|
|
14537
|
-
const [firstVisible, setFirstVisible] =
|
|
14538
|
-
const setSelection =
|
|
15611
|
+
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
15612
|
+
const [firstVisible, setFirstVisible] = useState5(0);
|
|
15613
|
+
const setSelection = useCallback10(
|
|
14539
15614
|
(newIndex) => {
|
|
14540
15615
|
setSelectedIndex(newIndex);
|
|
14541
15616
|
setFirstVisible(
|
|
@@ -14544,13 +15619,13 @@ function useSelectableList(itemCount, visibleCount, options) {
|
|
|
14544
15619
|
},
|
|
14545
15620
|
[visibleCount]
|
|
14546
15621
|
);
|
|
14547
|
-
|
|
15622
|
+
useEffect3(() => {
|
|
14548
15623
|
if (options?.resetWhen !== void 0) {
|
|
14549
15624
|
setSelectedIndex(0);
|
|
14550
15625
|
setFirstVisible(0);
|
|
14551
15626
|
}
|
|
14552
15627
|
}, [options?.resetWhen]);
|
|
14553
|
-
|
|
15628
|
+
useEffect3(() => {
|
|
14554
15629
|
if (itemCount > 0 && selectedIndex >= itemCount) {
|
|
14555
15630
|
const newIndex = itemCount - 1;
|
|
14556
15631
|
setSelectedIndex(newIndex);
|
|
@@ -14578,13 +15653,13 @@ function ResourcesTab({
|
|
|
14578
15653
|
onAuthRecoveryRequired,
|
|
14579
15654
|
modalOpen = false
|
|
14580
15655
|
}) {
|
|
14581
|
-
const [error, setError] =
|
|
14582
|
-
const [resourceContent, setResourceContent] =
|
|
14583
|
-
const [loading, setLoading] =
|
|
14584
|
-
const [shouldFetchResource, setShouldFetchResource] =
|
|
15656
|
+
const [error, setError] = useState6(null);
|
|
15657
|
+
const [resourceContent, setResourceContent] = useState6(null);
|
|
15658
|
+
const [loading, setLoading] = useState6(false);
|
|
15659
|
+
const [shouldFetchResource, setShouldFetchResource] = useState6(
|
|
14585
15660
|
null
|
|
14586
15661
|
);
|
|
14587
|
-
const scrollViewRef =
|
|
15662
|
+
const scrollViewRef = useRef6(null);
|
|
14588
15663
|
const allItems = useMemo(
|
|
14589
15664
|
() => [
|
|
14590
15665
|
...resources.map((r) => ({ type: "resource", data: r })),
|
|
@@ -14649,11 +15724,11 @@ function ResourcesTab({
|
|
|
14649
15724
|
isActive: !modalOpen && (focusedPane === "list" || focusedPane === "details")
|
|
14650
15725
|
}
|
|
14651
15726
|
);
|
|
14652
|
-
|
|
15727
|
+
useEffect4(() => {
|
|
14653
15728
|
scrollViewRef.current?.scrollTo(0);
|
|
14654
15729
|
}, [selectedIndex]);
|
|
14655
|
-
const prevResourcesRef =
|
|
14656
|
-
|
|
15730
|
+
const prevResourcesRef = useRef6(resources);
|
|
15731
|
+
useEffect4(() => {
|
|
14657
15732
|
if (prevResourcesRef.current !== resources) {
|
|
14658
15733
|
setResourceContent(null);
|
|
14659
15734
|
setShouldFetchResource(null);
|
|
@@ -14664,7 +15739,7 @@ function ResourcesTab({
|
|
|
14664
15739
|
const isTemplate = selectedItem?.type === "template";
|
|
14665
15740
|
const selectedResource = isResource ? selectedItem.data : null;
|
|
14666
15741
|
const selectedTemplate = isTemplate ? selectedItem.data : null;
|
|
14667
|
-
|
|
15742
|
+
useEffect4(() => {
|
|
14668
15743
|
if (!shouldFetchResource || !inspectorClient) return;
|
|
14669
15744
|
const fetchContent = async () => {
|
|
14670
15745
|
setLoading(true);
|
|
@@ -14690,8 +15765,8 @@ function ResourcesTab({
|
|
|
14690
15765
|
}, [shouldFetchResource, inspectorClient, onAuthRecoveryRequired]);
|
|
14691
15766
|
const listWidth = Math.floor(width * 0.4);
|
|
14692
15767
|
const detailWidth = width - listWidth;
|
|
14693
|
-
const prevCountRef =
|
|
14694
|
-
|
|
15768
|
+
const prevCountRef = useRef6(totalCount);
|
|
15769
|
+
useEffect4(() => {
|
|
14695
15770
|
if (prevCountRef.current !== totalCount) {
|
|
14696
15771
|
prevCountRef.current = totalCount;
|
|
14697
15772
|
onCountChange?.(totalCount);
|
|
@@ -14841,7 +15916,7 @@ function ResourcesTab({
|
|
|
14841
15916
|
}
|
|
14842
15917
|
|
|
14843
15918
|
// src/components/PromptsTab.tsx
|
|
14844
|
-
import { useState as
|
|
15919
|
+
import { useState as useState7, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
14845
15920
|
import { Box as Box7, Text as Text6, useInput as useInput4 } from "ink";
|
|
14846
15921
|
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
14847
15922
|
function PromptsTab({
|
|
@@ -14861,8 +15936,8 @@ function PromptsTab({
|
|
|
14861
15936
|
visibleCount,
|
|
14862
15937
|
{ resetWhen: prompts }
|
|
14863
15938
|
);
|
|
14864
|
-
const [error, setError] =
|
|
14865
|
-
const scrollViewRef =
|
|
15939
|
+
const [error, setError] = useState7(null);
|
|
15940
|
+
const scrollViewRef = useRef7(null);
|
|
14866
15941
|
useInput4(
|
|
14867
15942
|
(input, key) => {
|
|
14868
15943
|
if (key.return && selectedPrompt && inspectorClient && onFetchPrompt) {
|
|
@@ -14923,7 +15998,7 @@ function PromptsTab({
|
|
|
14923
15998
|
isActive: !modalOpen && (focusedPane === "list" || focusedPane === "details")
|
|
14924
15999
|
}
|
|
14925
16000
|
);
|
|
14926
|
-
|
|
16001
|
+
useEffect5(() => {
|
|
14927
16002
|
scrollViewRef.current?.scrollTo(0);
|
|
14928
16003
|
}, [selectedIndex]);
|
|
14929
16004
|
const selectedPrompt = prompts[selectedIndex] || null;
|
|
@@ -15043,7 +16118,7 @@ function PromptsTab({
|
|
|
15043
16118
|
}
|
|
15044
16119
|
|
|
15045
16120
|
// src/components/ToolsTab.tsx
|
|
15046
|
-
import { useState as
|
|
16121
|
+
import { useState as useState8, useEffect as useEffect6, useMemo as useMemo2, useRef as useRef8 } from "react";
|
|
15047
16122
|
import { Box as Box8, Text as Text7, useInput as useInput5 } from "ink";
|
|
15048
16123
|
|
|
15049
16124
|
// ../../core/json/schemaLint.ts
|
|
@@ -15336,12 +16411,12 @@ function ToolsTab({
|
|
|
15336
16411
|
visibleCount,
|
|
15337
16412
|
{ resetWhen: tools }
|
|
15338
16413
|
);
|
|
15339
|
-
const [error] =
|
|
16414
|
+
const [error] = useState8(null);
|
|
15340
16415
|
const findingsByTool = useMemo2(
|
|
15341
16416
|
() => tools.map((tool) => lintToolSchemas(tool)),
|
|
15342
16417
|
[tools]
|
|
15343
16418
|
);
|
|
15344
|
-
const scrollViewRef =
|
|
16419
|
+
const scrollViewRef = useRef8(null);
|
|
15345
16420
|
const listWidth = Math.floor(width * 0.4);
|
|
15346
16421
|
const detailWidth = width - listWidth;
|
|
15347
16422
|
useInput5(
|
|
@@ -15380,7 +16455,7 @@ function ToolsTab({
|
|
|
15380
16455
|
isActive: !modalOpen && (focusedPane === "list" || focusedPane === "details")
|
|
15381
16456
|
}
|
|
15382
16457
|
);
|
|
15383
|
-
|
|
16458
|
+
useEffect6(() => {
|
|
15384
16459
|
scrollViewRef.current?.scrollTo(0);
|
|
15385
16460
|
}, [selectedIndex]);
|
|
15386
16461
|
const selectedTool = tools[selectedIndex] || null;
|
|
@@ -15539,7 +16614,7 @@ function ToolsTab({
|
|
|
15539
16614
|
}
|
|
15540
16615
|
|
|
15541
16616
|
// src/components/NotificationsTab.tsx
|
|
15542
|
-
import { useEffect as
|
|
16617
|
+
import { useEffect as useEffect7, useRef as useRef9 } from "react";
|
|
15543
16618
|
import { Box as Box9, Text as Text8, useInput as useInput6 } from "ink";
|
|
15544
16619
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
15545
16620
|
function NotificationsTab({
|
|
@@ -15549,12 +16624,12 @@ function NotificationsTab({
|
|
|
15549
16624
|
onCountChange,
|
|
15550
16625
|
focused = false
|
|
15551
16626
|
}) {
|
|
15552
|
-
const scrollViewRef =
|
|
15553
|
-
const onCountChangeRef =
|
|
15554
|
-
|
|
16627
|
+
const scrollViewRef = useRef9(null);
|
|
16628
|
+
const onCountChangeRef = useRef9(onCountChange);
|
|
16629
|
+
useEffect7(() => {
|
|
15555
16630
|
onCountChangeRef.current = onCountChange;
|
|
15556
16631
|
}, [onCountChange]);
|
|
15557
|
-
|
|
16632
|
+
useEffect7(() => {
|
|
15558
16633
|
onCountChangeRef.current?.(stderrLogs.length);
|
|
15559
16634
|
}, [stderrLogs.length]);
|
|
15560
16635
|
useInput6(
|
|
@@ -15602,7 +16677,7 @@ function NotificationsTab({
|
|
|
15602
16677
|
}
|
|
15603
16678
|
|
|
15604
16679
|
// src/components/HistoryTab.tsx
|
|
15605
|
-
import React7, { useEffect as
|
|
16680
|
+
import React7, { useEffect as useEffect8, useRef as useRef10 } from "react";
|
|
15606
16681
|
import { Box as Box10, Text as Text9, useInput as useInput7 } from "ink";
|
|
15607
16682
|
import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
15608
16683
|
function HistoryTab({
|
|
@@ -15619,7 +16694,7 @@ function HistoryTab({
|
|
|
15619
16694
|
messages.length,
|
|
15620
16695
|
visibleCount
|
|
15621
16696
|
);
|
|
15622
|
-
const scrollViewRef =
|
|
16697
|
+
const scrollViewRef = useRef10(null);
|
|
15623
16698
|
const selectedMessage = messages[selectedIndex] || null;
|
|
15624
16699
|
useInput7(
|
|
15625
16700
|
(input, key) => {
|
|
@@ -15660,7 +16735,7 @@ function HistoryTab({
|
|
|
15660
16735
|
React7.useEffect(() => {
|
|
15661
16736
|
onCountChange?.(messages.length);
|
|
15662
16737
|
}, [messages.length]);
|
|
15663
|
-
|
|
16738
|
+
useEffect8(() => {
|
|
15664
16739
|
scrollViewRef.current?.scrollTo(0);
|
|
15665
16740
|
}, [selectedIndex]);
|
|
15666
16741
|
const listWidth = Math.floor(width * 0.4);
|
|
@@ -15822,7 +16897,7 @@ function HistoryTab({
|
|
|
15822
16897
|
}
|
|
15823
16898
|
|
|
15824
16899
|
// src/components/RequestsTab.tsx
|
|
15825
|
-
import React8, { useEffect as
|
|
16900
|
+
import React8, { useEffect as useEffect9, useRef as useRef11 } from "react";
|
|
15826
16901
|
import { Box as Box11, Text as Text10, useInput as useInput8 } from "ink";
|
|
15827
16902
|
import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
15828
16903
|
function RequestsTab({
|
|
@@ -15839,7 +16914,7 @@ function RequestsTab({
|
|
|
15839
16914
|
requests.length,
|
|
15840
16915
|
visibleCount
|
|
15841
16916
|
);
|
|
15842
|
-
const scrollViewRef =
|
|
16917
|
+
const scrollViewRef = useRef11(null);
|
|
15843
16918
|
const selectedRequest = requests[selectedIndex] || null;
|
|
15844
16919
|
useInput8(
|
|
15845
16920
|
(input, key) => {
|
|
@@ -15880,7 +16955,7 @@ function RequestsTab({
|
|
|
15880
16955
|
React8.useEffect(() => {
|
|
15881
16956
|
onCountChange?.(requests.length);
|
|
15882
16957
|
}, [requests.length]);
|
|
15883
|
-
|
|
16958
|
+
useEffect9(() => {
|
|
15884
16959
|
scrollViewRef.current?.scrollTo(0);
|
|
15885
16960
|
}, [selectedIndex]);
|
|
15886
16961
|
const listWidth = Math.floor(width * 0.4);
|
|
@@ -16093,12 +17168,12 @@ function RequestsTab({
|
|
|
16093
17168
|
}
|
|
16094
17169
|
|
|
16095
17170
|
// src/components/ToolTestModal.tsx
|
|
16096
|
-
import React25, { useState as
|
|
17171
|
+
import React25, { useState as useState13 } from "react";
|
|
16097
17172
|
import { Box as Box23, Text as Text20, useInput as useInput17 } from "ink";
|
|
16098
17173
|
|
|
16099
17174
|
// node_modules/ink-form/lib/Form.js
|
|
16100
17175
|
import { Box as Box22, useFocusManager, useInput as useInput16 } from "ink";
|
|
16101
|
-
import { useEffect as
|
|
17176
|
+
import { useEffect as useEffect12, useMemo as useMemo3, useState as useState12 } from "react";
|
|
16102
17177
|
import * as React23 from "react";
|
|
16103
17178
|
|
|
16104
17179
|
// node_modules/ink-form/lib/FormHeader.js
|
|
@@ -16166,7 +17241,7 @@ var FormHeader = (props) => {
|
|
|
16166
17241
|
};
|
|
16167
17242
|
|
|
16168
17243
|
// node_modules/ink-form/lib/FormFieldRenderer.js
|
|
16169
|
-
import React21, { useState as
|
|
17244
|
+
import React21, { useState as useState11 } from "react";
|
|
16170
17245
|
import { Box as Box20, useFocus, Text as Text18, useInput as useInput14 } from "ink";
|
|
16171
17246
|
|
|
16172
17247
|
// node_modules/ink-form/lib/managers/FloatFormFieldManager.js
|
|
@@ -16177,7 +17252,7 @@ import React11 from "react";
|
|
|
16177
17252
|
import { Box as Box13, Text as Text13, useInput as useInput11 } from "ink";
|
|
16178
17253
|
|
|
16179
17254
|
// node_modules/ink-text-input/build/index.js
|
|
16180
|
-
import React10, { useState as
|
|
17255
|
+
import React10, { useState as useState9, useEffect as useEffect10 } from "react";
|
|
16181
17256
|
import { Text as Text12, useInput as useInput10 } from "ink";
|
|
16182
17257
|
|
|
16183
17258
|
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
@@ -16677,12 +17752,12 @@ var source_default = chalk;
|
|
|
16677
17752
|
|
|
16678
17753
|
// node_modules/ink-text-input/build/index.js
|
|
16679
17754
|
function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
|
|
16680
|
-
const [state, setState] =
|
|
17755
|
+
const [state, setState] = useState9({
|
|
16681
17756
|
cursorOffset: (originalValue || "").length,
|
|
16682
17757
|
cursorWidth: 0
|
|
16683
17758
|
});
|
|
16684
17759
|
const { cursorOffset, cursorWidth } = state;
|
|
16685
|
-
|
|
17760
|
+
useEffect10(() => {
|
|
16686
17761
|
setState((previousState) => {
|
|
16687
17762
|
if (!focus || !showCursor) {
|
|
16688
17763
|
return previousState;
|
|
@@ -17153,7 +18228,7 @@ var Item_default = Item;
|
|
|
17153
18228
|
|
|
17154
18229
|
// node_modules/ink-select-input/build/SelectInput.js
|
|
17155
18230
|
import { isDeepStrictEqual } from "util";
|
|
17156
|
-
import React16, { useState as
|
|
18231
|
+
import React16, { useState as useState10, useEffect as useEffect11, useRef as useRef12, useCallback as useCallback11 } from "react";
|
|
17157
18232
|
|
|
17158
18233
|
// node_modules/to-rotated/index.js
|
|
17159
18234
|
function toRotated(array, steps) {
|
|
@@ -17183,17 +18258,17 @@ function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicator
|
|
|
17183
18258
|
const hasLimit = typeof customLimit === "number" && items.length > customLimit;
|
|
17184
18259
|
const limit = hasLimit ? Math.min(customLimit, items.length) : items.length;
|
|
17185
18260
|
const lastIndex = limit - 1;
|
|
17186
|
-
const [rotateIndex, setRotateIndex] =
|
|
17187
|
-
const [selectedIndex, setSelectedIndex] =
|
|
17188
|
-
const previousItems =
|
|
17189
|
-
|
|
18261
|
+
const [rotateIndex, setRotateIndex] = useState10(initialIndex > lastIndex ? lastIndex - initialIndex : 0);
|
|
18262
|
+
const [selectedIndex, setSelectedIndex] = useState10(initialIndex ? initialIndex > lastIndex ? lastIndex : initialIndex : 0);
|
|
18263
|
+
const previousItems = useRef12(items);
|
|
18264
|
+
useEffect11(() => {
|
|
17190
18265
|
if (!isDeepStrictEqual(previousItems.current.map((item) => item.value), items.map((item) => item.value))) {
|
|
17191
18266
|
setRotateIndex(0);
|
|
17192
18267
|
setSelectedIndex(0);
|
|
17193
18268
|
}
|
|
17194
18269
|
previousItems.current = items;
|
|
17195
18270
|
}, [items]);
|
|
17196
|
-
useInput12(
|
|
18271
|
+
useInput12(useCallback11((input, key) => {
|
|
17197
18272
|
if (input === "k" || key.upArrow) {
|
|
17198
18273
|
const lastIndex2 = (hasLimit ? limit : items.length) - 1;
|
|
17199
18274
|
const atFirstIndex = selectedIndex === 0;
|
|
@@ -17354,8 +18429,8 @@ var DescriptionRenderer = (props) => {
|
|
|
17354
18429
|
// node_modules/ink-form/lib/FormFieldRenderer.js
|
|
17355
18430
|
var FormFieldRenderer = (props) => {
|
|
17356
18431
|
const manager = getManager(props.field.type, props.customManagers);
|
|
17357
|
-
const [error, setError] =
|
|
17358
|
-
const [currentValue, setCurrentValue] =
|
|
18432
|
+
const [error, setError] = useState11();
|
|
18433
|
+
const [currentValue, setCurrentValue] = useState11(props.value ?? props.field.initialValue);
|
|
17359
18434
|
const isEditing = !!props.editingField && props.editingField === (props.field.label ?? props.field.name);
|
|
17360
18435
|
const hide = !isEditing && !!props.editingField;
|
|
17361
18436
|
const save = (newValue) => {
|
|
@@ -17513,20 +18588,20 @@ var SubmitButton = (props) => {
|
|
|
17513
18588
|
// node_modules/ink-form/lib/Form.js
|
|
17514
18589
|
var Form = (props) => {
|
|
17515
18590
|
const isControlled = props.value !== void 0;
|
|
17516
|
-
const [currentTab, setCurrentTab] =
|
|
17517
|
-
const [value, setValue] =
|
|
17518
|
-
const [editingField, setEditingField] =
|
|
18591
|
+
const [currentTab, setCurrentTab] = useState12(0);
|
|
18592
|
+
const [value, setValue] = useState12(props.value ?? {});
|
|
18593
|
+
const [editingField, setEditingField] = useState12();
|
|
17519
18594
|
const canSubmitForm = useMemo3(() => canSubmit(props.form, value), [value, props.form]);
|
|
17520
18595
|
const focusManager = useFocusManager();
|
|
17521
|
-
|
|
18596
|
+
useEffect12(() => {
|
|
17522
18597
|
focusManager.enableFocus();
|
|
17523
18598
|
}, []);
|
|
17524
|
-
|
|
18599
|
+
useEffect12(() => {
|
|
17525
18600
|
if (props.value) {
|
|
17526
18601
|
setValue(props.value);
|
|
17527
18602
|
}
|
|
17528
18603
|
}, [props.value]);
|
|
17529
|
-
|
|
18604
|
+
useEffect12(() => {
|
|
17530
18605
|
if (!isControlled) {
|
|
17531
18606
|
setValueAndPropagate({
|
|
17532
18607
|
...value,
|
|
@@ -17567,179 +18642,159 @@ var Form = (props) => {
|
|
|
17567
18642
|
import { render } from "ink";
|
|
17568
18643
|
import React24 from "react";
|
|
17569
18644
|
|
|
17570
|
-
//
|
|
17571
|
-
|
|
17572
|
-
|
|
17573
|
-
|
|
17574
|
-
|
|
17575
|
-
|
|
17576
|
-
|
|
17577
|
-
"object"
|
|
17578
|
-
];
|
|
17579
|
-
function isRenderableType(type) {
|
|
17580
|
-
return RENDERABLE_TYPES.includes(type);
|
|
18645
|
+
// src/utils/schemaToForm.ts
|
|
18646
|
+
function toSelectOptions(values, names) {
|
|
18647
|
+
const useNames = names !== void 0 && names.length === values.length;
|
|
18648
|
+
return values.map((val, index) => ({
|
|
18649
|
+
label: useNames ? names[index] : String(val),
|
|
18650
|
+
value: String(val)
|
|
18651
|
+
}));
|
|
17581
18652
|
}
|
|
17582
|
-
function
|
|
17583
|
-
|
|
17584
|
-
|
|
17585
|
-
|
|
17586
|
-
|
|
18653
|
+
function generatedNames(base, branches) {
|
|
18654
|
+
const declared = [
|
|
18655
|
+
...Object.keys(base.properties ?? {}),
|
|
18656
|
+
...branches.flatMap((branch) => branch.declaredFields)
|
|
18657
|
+
];
|
|
18658
|
+
let variant = "__variant";
|
|
18659
|
+
while (declared.includes(variant)) variant += "_";
|
|
18660
|
+
let prefix = "__b";
|
|
18661
|
+
while (declared.some((name) => name.startsWith(prefix))) prefix += "_";
|
|
18662
|
+
return { variant, prefix };
|
|
18663
|
+
}
|
|
18664
|
+
function branchFieldName(prefix, branchIndex, name) {
|
|
18665
|
+
return `${prefix}${branchIndex}__${name}`;
|
|
18666
|
+
}
|
|
18667
|
+
function sharedFieldNames(base, branches) {
|
|
18668
|
+
const declared = new Set(branches.flatMap((branch) => branch.declaredFields));
|
|
18669
|
+
return Object.keys(base.properties ?? {}).filter(
|
|
18670
|
+
(name) => declared.has(name)
|
|
18671
|
+
);
|
|
17587
18672
|
}
|
|
17588
|
-
function
|
|
17589
|
-
|
|
18673
|
+
function branchFields(base, branches, index) {
|
|
18674
|
+
const own = branches[index].declaredFields;
|
|
18675
|
+
return [.../* @__PURE__ */ new Set([...own, ...sharedFieldNames(base, branches)])];
|
|
17590
18676
|
}
|
|
17591
|
-
function
|
|
17592
|
-
if (
|
|
17593
|
-
return
|
|
18677
|
+
function labelled(property, name) {
|
|
18678
|
+
if (typeof property !== "object" || property === null) {
|
|
18679
|
+
return { title: name };
|
|
17594
18680
|
}
|
|
17595
|
-
return
|
|
17596
|
-
}
|
|
17597
|
-
var ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
17598
|
-
"title",
|
|
17599
|
-
"description",
|
|
17600
|
-
"default",
|
|
17601
|
-
"enumNames",
|
|
17602
|
-
"examples",
|
|
17603
|
-
"deprecated",
|
|
17604
|
-
"readOnly",
|
|
17605
|
-
"writeOnly",
|
|
17606
|
-
"$comment",
|
|
17607
|
-
"$schema",
|
|
17608
|
-
"$id"
|
|
17609
|
-
]);
|
|
17610
|
-
function wrapperCarriesConstraints(schema) {
|
|
17611
|
-
return Object.keys(schema).some(
|
|
17612
|
-
(key) => key !== "anyOf" && !ANNOTATION_KEYWORDS.has(key)
|
|
17613
|
-
);
|
|
17614
|
-
}
|
|
17615
|
-
function typeNamesNull(type) {
|
|
17616
|
-
return Array.isArray(type) ? type.includes("null") : type === "null";
|
|
18681
|
+
return { title: name, ...property };
|
|
17617
18682
|
}
|
|
17618
|
-
function
|
|
17619
|
-
return
|
|
17620
|
-
// *alongside* its siblings — `{ type: "string", $ref: "#/$defs/intOnly" }`
|
|
17621
|
-
// can be unsatisfiable. The wrapper path already declines on it (it is not
|
|
17622
|
-
// an annotation); this is the same rule for every other position.
|
|
17623
|
-
schema.$ref !== void 0;
|
|
18683
|
+
function requiredOf2(schema) {
|
|
18684
|
+
return Array.isArray(schema.required) ? schema.required.filter((name) => typeof name === "string") : [];
|
|
17624
18685
|
}
|
|
17625
|
-
function
|
|
17626
|
-
|
|
18686
|
+
function constOf(schema) {
|
|
18687
|
+
if (typeof schema !== "object" || schema === null) return void 0;
|
|
18688
|
+
return schema.const;
|
|
17627
18689
|
}
|
|
17628
|
-
function
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
const kept = members.map((member, index) => ({ member, index })).filter((entry) => entry.member !== null);
|
|
17633
|
-
if (kept.length === 0) {
|
|
17634
|
-
return { kind: "unselectable" };
|
|
18690
|
+
function schemaToForm(schema, toolName) {
|
|
18691
|
+
const title = `Test Tool: ${toolName}`;
|
|
18692
|
+
if (!schema) {
|
|
18693
|
+
return { title, sections: [{ title: "Parameters", fields: [] }] };
|
|
17635
18694
|
}
|
|
17636
|
-
|
|
17637
|
-
|
|
18695
|
+
const { base, branches } = resolveRootUnion(schema);
|
|
18696
|
+
if (branches.length === 0) {
|
|
18697
|
+
return {
|
|
18698
|
+
title,
|
|
18699
|
+
sections: [{ title: "Parameters", fields: buildFields(base) }]
|
|
18700
|
+
};
|
|
17638
18701
|
}
|
|
17639
|
-
const
|
|
17640
|
-
const
|
|
17641
|
-
|
|
17642
|
-
|
|
17643
|
-
|
|
17644
|
-
|
|
17645
|
-
};
|
|
17646
|
-
}
|
|
17647
|
-
function collapsed(schema, branch, type) {
|
|
17648
|
-
const merged = { ...schema, ...branch };
|
|
17649
|
-
const strip = stripNullEnumMembers(
|
|
17650
|
-
merged.enum,
|
|
17651
|
-
merged.enumNames
|
|
18702
|
+
const { variant, prefix } = generatedNames(base, branches);
|
|
18703
|
+
const shared = sharedFieldNames(base, branches);
|
|
18704
|
+
const baseProperties = Object.fromEntries(
|
|
18705
|
+
Object.entries(base.properties ?? {}).filter(
|
|
18706
|
+
([name]) => !shared.includes(name)
|
|
18707
|
+
)
|
|
17652
18708
|
);
|
|
17653
|
-
|
|
17654
|
-
|
|
17655
|
-
|
|
17656
|
-
|
|
17657
|
-
|
|
17658
|
-
|
|
17659
|
-
|
|
17660
|
-
|
|
17661
|
-
|
|
17662
|
-
|
|
17663
|
-
|
|
17664
|
-
|
|
17665
|
-
|
|
18709
|
+
const parameters = [
|
|
18710
|
+
{
|
|
18711
|
+
type: "select",
|
|
18712
|
+
name: variant,
|
|
18713
|
+
label: "Variant",
|
|
18714
|
+
required: true,
|
|
18715
|
+
initialValue: "0",
|
|
18716
|
+
options: branches.map((branch, index) => ({
|
|
18717
|
+
label: branch.label,
|
|
18718
|
+
value: String(index)
|
|
18719
|
+
}))
|
|
18720
|
+
},
|
|
18721
|
+
...buildFields({ properties: baseProperties, required: base.required })
|
|
18722
|
+
];
|
|
18723
|
+
const sections = [{ title: "Parameters", fields: parameters }];
|
|
18724
|
+
branches.forEach((branch, index) => {
|
|
18725
|
+
const byRealName = Object.fromEntries(
|
|
18726
|
+
branchFields(base, branches, index).map((name) => [name, true])
|
|
18727
|
+
);
|
|
18728
|
+
const properties = Object.fromEntries(
|
|
18729
|
+
branchFields(base, branches, index).map((name) => [
|
|
18730
|
+
branchFieldName(prefix, index, name),
|
|
18731
|
+
// The prefix is an internal field NAME, never a label: `buildFields`
|
|
18732
|
+
// falls back to its map key when a declaration carries no `title`, so
|
|
18733
|
+
// without this the form would show `__b0__address` where the schema
|
|
18734
|
+
// says `address`.
|
|
18735
|
+
labelled(branch.schema.properties?.[name], name)
|
|
18736
|
+
])
|
|
18737
|
+
);
|
|
18738
|
+
sections.push({
|
|
18739
|
+
title: branch.label,
|
|
18740
|
+
fields: buildFields(
|
|
18741
|
+
{
|
|
18742
|
+
properties,
|
|
18743
|
+
// Under their prefixed names, so the constant seeding below can tell
|
|
18744
|
+
// which of this branch's fields the schema actually requires.
|
|
18745
|
+
required: requiredOf2(branch.schema).filter((name) => Object.hasOwn(byRealName, name)).map((name) => branchFieldName(prefix, index, name))
|
|
18746
|
+
},
|
|
18747
|
+
{ optional: true }
|
|
18748
|
+
)
|
|
18749
|
+
});
|
|
18750
|
+
});
|
|
18751
|
+
return { title, sections };
|
|
17666
18752
|
}
|
|
17667
|
-
function
|
|
17668
|
-
|
|
17669
|
-
|
|
17670
|
-
|
|
17671
|
-
if (hasOpaqueApplicator(schema)) {
|
|
17672
|
-
return false;
|
|
17673
|
-
}
|
|
17674
|
-
if (schema.nullable === true) {
|
|
17675
|
-
return true;
|
|
17676
|
-
}
|
|
17677
|
-
if (schema.type !== void 0) {
|
|
17678
|
-
if (schema.anyOf !== void 0) {
|
|
17679
|
-
return false;
|
|
17680
|
-
}
|
|
17681
|
-
return typeNamesNull(schema.type);
|
|
18753
|
+
function decodeFormValues(schema, values) {
|
|
18754
|
+
const { base, branches } = resolveRootUnion(schema ?? {});
|
|
18755
|
+
if (branches.length === 0) {
|
|
18756
|
+
return applyConstants(base.properties ?? {}, values, requiredOf2(base));
|
|
17682
18757
|
}
|
|
17683
|
-
|
|
17684
|
-
|
|
17685
|
-
|
|
17686
|
-
|
|
18758
|
+
const { variant, prefix } = generatedNames(base, branches);
|
|
18759
|
+
const branchIndex = selectedBranchIndex(base, branches, values);
|
|
18760
|
+
const branch = branches[branchIndex];
|
|
18761
|
+
const generated = /* @__PURE__ */ new Set([variant]);
|
|
18762
|
+
branches.forEach((_each, index) => {
|
|
18763
|
+
for (const name of branchFields(base, branches, index)) {
|
|
18764
|
+
generated.add(branchFieldName(prefix, index, name));
|
|
17687
18765
|
}
|
|
17688
|
-
|
|
17689
|
-
|
|
17690
|
-
|
|
18766
|
+
});
|
|
18767
|
+
const decoded = Object.fromEntries([
|
|
18768
|
+
...Object.entries(values).filter(([name]) => !generated.has(name)),
|
|
18769
|
+
...branchFields(base, branches, branchIndex).map(
|
|
18770
|
+
(name) => [name, values[branchFieldName(prefix, branchIndex, name)]]
|
|
18771
|
+
).filter(([, value]) => value !== void 0)
|
|
18772
|
+
]);
|
|
18773
|
+
return applyConstants(
|
|
18774
|
+
branch.schema.properties ?? {},
|
|
18775
|
+
decoded,
|
|
18776
|
+
requiredOf2(branch.schema)
|
|
18777
|
+
);
|
|
17691
18778
|
}
|
|
17692
|
-
function
|
|
17693
|
-
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
const branch = branches.find(
|
|
17697
|
-
(entry) => entry !== null && entry.type !== "null"
|
|
17698
|
-
);
|
|
17699
|
-
if (nullBranch && branch && !wrapperCarriesConstraints(schema) && !hasUnevaluatedComposition(branch)) {
|
|
17700
|
-
const type = branch.type ?? (isStringEnum(branch.enum) ? "string" : void 0);
|
|
17701
|
-
if (isRenderableType(type)) {
|
|
17702
|
-
const result = collapsed(schema, branch, type);
|
|
17703
|
-
if (result !== null) {
|
|
17704
|
-
return result;
|
|
17705
|
-
}
|
|
17706
|
-
}
|
|
17707
|
-
}
|
|
17708
|
-
}
|
|
17709
|
-
if (Array.isArray(schema.type) && schema.type.length === 2 && schema.type.includes("null") && // This path keeps the schema's own keywords, but `collapsed` clears `anyOf`
|
|
17710
|
-
// and the renderers ignore the other applicators — so a compound schema
|
|
17711
|
-
// like `{ type: ["string", "null"], anyOf: [{ const: "a" }] }` would be
|
|
17712
|
-
// widened into an unconstrained string field. Leave it for the JSON editor.
|
|
17713
|
-
!hasUnevaluatedComposition(schema)) {
|
|
17714
|
-
const type = schema.type.find((member) => member !== "null");
|
|
17715
|
-
if (isRenderableType(type)) {
|
|
17716
|
-
const result = collapsed(schema, void 0, type);
|
|
17717
|
-
if (result !== null) {
|
|
17718
|
-
return result;
|
|
17719
|
-
}
|
|
17720
|
-
}
|
|
17721
|
-
}
|
|
17722
|
-
return schema;
|
|
18779
|
+
function selectedBranchIndex(base, branches, values) {
|
|
18780
|
+
const { variant } = generatedNames(base, branches);
|
|
18781
|
+
const selected = Number(values[variant]);
|
|
18782
|
+
return Number.isInteger(selected) && selected >= 0 && selected < branches.length ? selected : 0;
|
|
17723
18783
|
}
|
|
17724
|
-
|
|
17725
|
-
|
|
17726
|
-
|
|
17727
|
-
|
|
17728
|
-
|
|
17729
|
-
|
|
17730
|
-
|
|
17731
|
-
|
|
18784
|
+
function applyConstants(properties, values, required) {
|
|
18785
|
+
const pinned = Object.entries(properties).filter(
|
|
18786
|
+
([name, schema]) => constOf(schema) !== void 0 && (required.includes(name) || Object.hasOwn(values, name) && values[name] !== void 0)
|
|
18787
|
+
);
|
|
18788
|
+
if (pinned.length === 0) return values;
|
|
18789
|
+
return Object.fromEntries([
|
|
18790
|
+
...Object.entries(values),
|
|
18791
|
+
...pinned.map(([name, schema]) => [name, constOf(schema)])
|
|
18792
|
+
]);
|
|
17732
18793
|
}
|
|
17733
|
-
function
|
|
18794
|
+
function buildFields(schema, { optional = false } = {}) {
|
|
17734
18795
|
const fields = [];
|
|
17735
|
-
if (!schema || !schema.properties) {
|
|
17736
|
-
return {
|
|
17737
|
-
title: `Test Tool: ${toolName}`,
|
|
17738
|
-
sections: [{ title: "Parameters", fields: [] }]
|
|
17739
|
-
};
|
|
17740
|
-
}
|
|
17741
18796
|
const properties = schema.properties || {};
|
|
17742
|
-
const required = schema.required
|
|
18797
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
17743
18798
|
for (const [key, prop] of Object.entries(properties)) {
|
|
17744
18799
|
const property = normalizeNullableUnion(
|
|
17745
18800
|
typeof prop === "object" && prop !== null ? prop : {}
|
|
@@ -17747,9 +18802,30 @@ function schemaToForm(schema, toolName) {
|
|
|
17747
18802
|
const baseField = {
|
|
17748
18803
|
name: key,
|
|
17749
18804
|
label: property.title || key,
|
|
17750
|
-
required: required.includes(key)
|
|
18805
|
+
required: optional ? false : required.includes(key)
|
|
17751
18806
|
};
|
|
17752
18807
|
let field;
|
|
18808
|
+
const pinned = property.const;
|
|
18809
|
+
if (pinned !== void 0) {
|
|
18810
|
+
fields.push({
|
|
18811
|
+
type: "select",
|
|
18812
|
+
...baseField,
|
|
18813
|
+
// Only a REQUIRED constant is pre-filled. `const` constrains a present
|
|
18814
|
+
// value; it neither requires the property nor acts as a default, so an
|
|
18815
|
+
// optional `dryRun: { const: true }` must stay omittable rather than
|
|
18816
|
+
// being sent on every call. The single option is still there for a user
|
|
18817
|
+
// who wants it.
|
|
18818
|
+
...required.includes(key) ? { initialValue: String(pinned) } : {},
|
|
18819
|
+
// Never required: the one option may legitimately be the empty string,
|
|
18820
|
+
// which ink-form's required gate can never accept — submission would
|
|
18821
|
+
// not even reach `decodeFormValues`, which reapplies the constant. The
|
|
18822
|
+
// value is fixed by the schema, and `missingRequiredFields` still
|
|
18823
|
+
// validates the decoded call.
|
|
18824
|
+
required: false,
|
|
18825
|
+
options: [{ label: String(pinned), value: String(pinned) }]
|
|
18826
|
+
});
|
|
18827
|
+
continue;
|
|
18828
|
+
}
|
|
17753
18829
|
if (property.type === "array" && property.items?.enum) {
|
|
17754
18830
|
field = {
|
|
17755
18831
|
type: "select",
|
|
@@ -17760,6 +18836,7 @@ function schemaToForm(schema, toolName) {
|
|
|
17760
18836
|
field = {
|
|
17761
18837
|
type: "select",
|
|
17762
18838
|
...baseField,
|
|
18839
|
+
/* v8 ignore next -- guarded by `isStringEnum(property.enum)` above */
|
|
17763
18840
|
options: toSelectOptions(property.enum ?? [], property.enumNames)
|
|
17764
18841
|
};
|
|
17765
18842
|
} else {
|
|
@@ -17804,16 +18881,25 @@ function schemaToForm(schema, toolName) {
|
|
|
17804
18881
|
}
|
|
17805
18882
|
fields.push(field);
|
|
17806
18883
|
}
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
18884
|
+
return fields;
|
|
18885
|
+
}
|
|
18886
|
+
function missingRequiredFields(schema, decoded, rawValues = {}) {
|
|
18887
|
+
const { base, branches } = resolveRootUnion(schema ?? {});
|
|
18888
|
+
const effective = branches.length === 0 ? base : branches[selectedBranchIndex(base, branches, rawValues)].schema;
|
|
18889
|
+
const properties = effective.properties ?? {};
|
|
18890
|
+
const required = Array.isArray(effective.required) ? effective.required : [];
|
|
18891
|
+
return required.filter((name) => {
|
|
18892
|
+
if (!Object.hasOwn(decoded, name)) return true;
|
|
18893
|
+
const value = decoded[name];
|
|
18894
|
+
if (value === null) {
|
|
18895
|
+
const property = properties[name];
|
|
18896
|
+
return typeof property !== "object" || property === null || !admitsNull(property);
|
|
18897
|
+
}
|
|
18898
|
+
if (value === "") {
|
|
18899
|
+
return constOf(properties[name]) !== "";
|
|
18900
|
+
}
|
|
18901
|
+
return value === void 0;
|
|
18902
|
+
});
|
|
17817
18903
|
}
|
|
17818
18904
|
|
|
17819
18905
|
// src/components/ToolTestModal.tsx
|
|
@@ -17826,8 +18912,8 @@ function ToolTestModal({
|
|
|
17826
18912
|
onClose,
|
|
17827
18913
|
onAuthRecoveryRequired
|
|
17828
18914
|
}) {
|
|
17829
|
-
const [state, setState] =
|
|
17830
|
-
const [result, setResult] =
|
|
18915
|
+
const [state, setState] = useState13("form");
|
|
18916
|
+
const [result, setResult] = useState13(null);
|
|
17831
18917
|
const scrollViewRef = React25.useRef(null);
|
|
17832
18918
|
const [terminalDimensions, setTerminalDimensions] = React25.useState({
|
|
17833
18919
|
width: process.stdout.columns || width,
|
|
@@ -17883,8 +18969,20 @@ function ToolTestModal({
|
|
|
17883
18969
|
},
|
|
17884
18970
|
{ isActive: true }
|
|
17885
18971
|
);
|
|
17886
|
-
const handleFormSubmit = async (
|
|
18972
|
+
const handleFormSubmit = async (rawValues) => {
|
|
17887
18973
|
if (!inspectorClient || !tool) return;
|
|
18974
|
+
const values = decodeFormValues(tool.inputSchema, rawValues);
|
|
18975
|
+
const missing = missingRequiredFields(tool.inputSchema, values, rawValues);
|
|
18976
|
+
if (missing.length > 0) {
|
|
18977
|
+
setResult({
|
|
18978
|
+
input: values,
|
|
18979
|
+
output: null,
|
|
18980
|
+
error: `Missing required argument${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`,
|
|
18981
|
+
duration: 0
|
|
18982
|
+
});
|
|
18983
|
+
setState("results");
|
|
18984
|
+
return;
|
|
18985
|
+
}
|
|
17888
18986
|
setState("loading");
|
|
17889
18987
|
const startTime = Date.now();
|
|
17890
18988
|
try {
|
|
@@ -17996,7 +19094,7 @@ function ToolTestModal({
|
|
|
17996
19094
|
}
|
|
17997
19095
|
|
|
17998
19096
|
// src/components/ResourceTestModal.tsx
|
|
17999
|
-
import React26, { useState as
|
|
19097
|
+
import React26, { useState as useState14 } from "react";
|
|
18000
19098
|
import { Box as Box24, Text as Text21, useInput as useInput18 } from "ink";
|
|
18001
19099
|
|
|
18002
19100
|
// src/utils/uriTemplateToForm.ts
|
|
@@ -18051,8 +19149,8 @@ function ResourceTestModal({
|
|
|
18051
19149
|
onClose,
|
|
18052
19150
|
onAuthRecoveryRequired
|
|
18053
19151
|
}) {
|
|
18054
|
-
const [state, setState] =
|
|
18055
|
-
const [result, setResult] =
|
|
19152
|
+
const [state, setState] = useState14("form");
|
|
19153
|
+
const [result, setResult] = useState14(null);
|
|
18056
19154
|
const scrollViewRef = React26.useRef(null);
|
|
18057
19155
|
const [terminalDimensions, setTerminalDimensions] = React26.useState({
|
|
18058
19156
|
width: process.stdout.columns || width,
|
|
@@ -18255,7 +19353,7 @@ function ResourceTestModal({
|
|
|
18255
19353
|
}
|
|
18256
19354
|
|
|
18257
19355
|
// src/components/PromptTestModal.tsx
|
|
18258
|
-
import React27, { useState as
|
|
19356
|
+
import React27, { useState as useState15 } from "react";
|
|
18259
19357
|
import { Box as Box25, Text as Text22, useInput as useInput19 } from "ink";
|
|
18260
19358
|
|
|
18261
19359
|
// src/utils/promptArgsToForm.ts
|
|
@@ -18313,8 +19411,8 @@ function PromptTestModal({
|
|
|
18313
19411
|
onClose,
|
|
18314
19412
|
onAuthRecoveryRequired
|
|
18315
19413
|
}) {
|
|
18316
|
-
const [state, setState] =
|
|
18317
|
-
const [result, setResult] =
|
|
19414
|
+
const [state, setState] = useState15("form");
|
|
19415
|
+
const [result, setResult] = useState15(null);
|
|
18318
19416
|
const scrollViewRef = React27.useRef(null);
|
|
18319
19417
|
const [terminalDimensions, setTerminalDimensions] = React27.useState({
|
|
18320
19418
|
width: process.stdout.columns || width,
|
|
@@ -18483,7 +19581,7 @@ function PromptTestModal({
|
|
|
18483
19581
|
}
|
|
18484
19582
|
|
|
18485
19583
|
// src/components/DetailsModal.tsx
|
|
18486
|
-
import React28, { useRef as
|
|
19584
|
+
import React28, { useRef as useRef13 } from "react";
|
|
18487
19585
|
import { Box as Box26, Text as Text23, useInput as useInput20 } from "ink";
|
|
18488
19586
|
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
18489
19587
|
function DetailsModal({
|
|
@@ -18493,7 +19591,7 @@ function DetailsModal({
|
|
|
18493
19591
|
height,
|
|
18494
19592
|
onClose
|
|
18495
19593
|
}) {
|
|
18496
|
-
const scrollViewRef =
|
|
19594
|
+
const scrollViewRef = useRef13(null);
|
|
18497
19595
|
const [terminalDimensions, setTerminalDimensions] = React28.useState({
|
|
18498
19596
|
width: process.stdout.columns || width,
|
|
18499
19597
|
height: process.stdout.rows || height
|
|
@@ -18580,49 +19678,52 @@ function App({
|
|
|
18580
19678
|
callbackUrlConfig
|
|
18581
19679
|
}) {
|
|
18582
19680
|
const { exit } = useApp();
|
|
18583
|
-
|
|
19681
|
+
useEffect13(() => {
|
|
18584
19682
|
getTuiLogger().info(
|
|
18585
19683
|
{ serverNames: Object.keys(mcpServers) },
|
|
18586
19684
|
"TUI started"
|
|
18587
19685
|
);
|
|
18588
19686
|
}, [mcpServers]);
|
|
18589
|
-
const [selectedServer, setSelectedServer] =
|
|
18590
|
-
const [activeTab, setActiveTab] =
|
|
18591
|
-
const [focus, setFocus] =
|
|
18592
|
-
const [tabCounts, setTabCounts] =
|
|
18593
|
-
const [oauthStatus, setOauthStatus] =
|
|
18594
|
-
const [oauthMessage, setOauthMessage] =
|
|
18595
|
-
const [
|
|
18596
|
-
const
|
|
18597
|
-
const
|
|
18598
|
-
|
|
19687
|
+
const [selectedServer, setSelectedServer] = useState16(null);
|
|
19688
|
+
const [activeTab, setActiveTab] = useState16("info");
|
|
19689
|
+
const [focus, setFocus] = useState16("serverList");
|
|
19690
|
+
const [tabCounts, setTabCounts] = useState16({});
|
|
19691
|
+
const [oauthStatus, setOauthStatus] = useState16("idle");
|
|
19692
|
+
const [oauthMessage, setOauthMessage] = useState16(null);
|
|
19693
|
+
const [oauthWarningText, setOauthWarningText] = useState16(null);
|
|
19694
|
+
const oauthMessageTone = oauthMessageToneFor(oauthMessage, oauthWarningText);
|
|
19695
|
+
const [oauthRevision, setOauthRevision] = useState16(0);
|
|
19696
|
+
const [pendingStepUp, setPendingStepUp] = useState16(null);
|
|
19697
|
+
const pendingStepUpRef = useRef14(pendingStepUp);
|
|
19698
|
+
useEffect13(() => {
|
|
18599
19699
|
pendingStepUpRef.current = pendingStepUp;
|
|
18600
19700
|
}, [pendingStepUp]);
|
|
18601
|
-
const [connectError, setConnectError] =
|
|
18602
|
-
const disconnectAttemptRef =
|
|
18603
|
-
const
|
|
18604
|
-
const
|
|
18605
|
-
const
|
|
18606
|
-
const
|
|
18607
|
-
const
|
|
18608
|
-
const
|
|
18609
|
-
const
|
|
18610
|
-
const [
|
|
18611
|
-
const [
|
|
18612
|
-
const [
|
|
18613
|
-
const [
|
|
18614
|
-
const [
|
|
18615
|
-
const [
|
|
18616
|
-
const [
|
|
18617
|
-
const [
|
|
18618
|
-
const [
|
|
18619
|
-
const [
|
|
18620
|
-
const [
|
|
18621
|
-
const [
|
|
19701
|
+
const [connectError, setConnectError] = useState16(null);
|
|
19702
|
+
const disconnectAttemptRef = useRef14(0);
|
|
19703
|
+
const clearOAuthAttemptRef = useRef14(0);
|
|
19704
|
+
const [disconnectError, setDisconnectError] = useState16(null);
|
|
19705
|
+
const oauthInProgressRef = useRef14(false);
|
|
19706
|
+
const callbackServerRef = useRef14(null);
|
|
19707
|
+
const selectedServerRef = useRef14(null);
|
|
19708
|
+
const mcpServersRef = useRef14(mcpServers);
|
|
19709
|
+
const inspectorClientsRef = useRef14({});
|
|
19710
|
+
const [toolTestModal, setToolTestModal] = useState16(null);
|
|
19711
|
+
const [resourceTestModal, setResourceTestModal] = useState16(null);
|
|
19712
|
+
const [promptTestModal, setPromptTestModal] = useState16(null);
|
|
19713
|
+
const [detailsModal, setDetailsModal] = useState16(null);
|
|
19714
|
+
const [inspectorClients, setInspectorClients] = useState16({});
|
|
19715
|
+
const [managedToolsStates, setManagedToolsStates] = useState16({});
|
|
19716
|
+
const [managedResourcesStates, setManagedResourcesStates] = useState16({});
|
|
19717
|
+
const [managedResourceTemplatesStates, setManagedResourceTemplatesStates] = useState16({});
|
|
19718
|
+
const [managedPromptsStates, setManagedPromptsStates] = useState16({});
|
|
19719
|
+
const [messageLogStates, setMessageLogStates] = useState16({});
|
|
19720
|
+
const [fetchRequestLogStates, setFetchRequestLogStates] = useState16({});
|
|
19721
|
+
const [stderrLogStates, setStderrLogStates] = useState16({});
|
|
19722
|
+
const [dimensions, setDimensions] = useState16({
|
|
18622
19723
|
width: process.stdout.columns || 80,
|
|
18623
19724
|
height: process.stdout.rows || 24
|
|
18624
19725
|
});
|
|
18625
|
-
|
|
19726
|
+
useEffect13(() => {
|
|
18626
19727
|
const updateDimensions = () => {
|
|
18627
19728
|
setDimensions({
|
|
18628
19729
|
width: process.stdout.columns || 80,
|
|
@@ -18637,8 +19738,8 @@ function App({
|
|
|
18637
19738
|
const serverNames = Object.keys(mcpServers);
|
|
18638
19739
|
const selectedServerEntry = selectedServer ? mcpServers[selectedServer] : null;
|
|
18639
19740
|
const selectedServerConfig = selectedServerEntry?.config ?? null;
|
|
18640
|
-
const redirectUrlProvidersRef =
|
|
18641
|
-
|
|
19741
|
+
const redirectUrlProvidersRef = useRef14({});
|
|
19742
|
+
useEffect13(() => {
|
|
18642
19743
|
const newClients = {};
|
|
18643
19744
|
const newManagers = {};
|
|
18644
19745
|
const newManagedResourcesStates = {};
|
|
@@ -18742,7 +19843,7 @@ function App({
|
|
|
18742
19843
|
clientMetadataUrl,
|
|
18743
19844
|
callbackUrlConfig
|
|
18744
19845
|
]);
|
|
18745
|
-
|
|
19846
|
+
useEffect13(() => {
|
|
18746
19847
|
return () => {
|
|
18747
19848
|
void callbackServerRef.current?.stop();
|
|
18748
19849
|
callbackServerRef.current = null;
|
|
@@ -18782,27 +19883,28 @@ function App({
|
|
|
18782
19883
|
fetchRequestLogStates,
|
|
18783
19884
|
stderrLogStates
|
|
18784
19885
|
]);
|
|
18785
|
-
|
|
19886
|
+
useEffect13(() => {
|
|
18786
19887
|
if (serverNames.length > 0 && selectedServer === null) {
|
|
18787
19888
|
setSelectedServer(serverNames[0]);
|
|
18788
19889
|
}
|
|
18789
19890
|
}, []);
|
|
18790
|
-
|
|
19891
|
+
useEffect13(() => {
|
|
18791
19892
|
setOauthStatus("idle");
|
|
18792
19893
|
setOauthMessage(null);
|
|
18793
19894
|
disconnectAttemptRef.current++;
|
|
19895
|
+
clearOAuthAttemptRef.current++;
|
|
18794
19896
|
setDisconnectError(null);
|
|
18795
19897
|
const stepUp = pendingStepUpRef.current;
|
|
18796
19898
|
if (stepUp && selectedServer && stepUp.serverName !== selectedServer) {
|
|
18797
19899
|
setPendingStepUp(null);
|
|
18798
19900
|
}
|
|
18799
19901
|
}, [selectedServer]);
|
|
18800
|
-
|
|
19902
|
+
useEffect13(() => {
|
|
18801
19903
|
selectedServerRef.current = selectedServer;
|
|
18802
19904
|
mcpServersRef.current = mcpServers;
|
|
18803
19905
|
inspectorClientsRef.current = inspectorClients;
|
|
18804
19906
|
}, [selectedServer, mcpServers, inspectorClients]);
|
|
18805
|
-
|
|
19907
|
+
useEffect13(() => {
|
|
18806
19908
|
if (activeTab === "auth" && selectedServerConfig && !isOAuthCapableServerConfig(selectedServerConfig)) {
|
|
18807
19909
|
setActiveTab("info");
|
|
18808
19910
|
}
|
|
@@ -18873,7 +19975,7 @@ function App({
|
|
|
18873
19975
|
selectedInspectorClient,
|
|
18874
19976
|
selectedManagedPromptsState
|
|
18875
19977
|
);
|
|
18876
|
-
const runOAuthAuthentication =
|
|
19978
|
+
const runOAuthAuthentication = useCallback12(
|
|
18877
19979
|
async (options) => {
|
|
18878
19980
|
const serverName = options?.serverName ?? selectedServer;
|
|
18879
19981
|
if (!serverName) {
|
|
@@ -18932,7 +20034,7 @@ function App({
|
|
|
18932
20034
|
},
|
|
18933
20035
|
[selectedServer, callbackUrlConfig]
|
|
18934
20036
|
);
|
|
18935
|
-
const presentStepUpForServer =
|
|
20037
|
+
const presentStepUpForServer = useCallback12(
|
|
18936
20038
|
(serverName, challenge, authorizationUrl, enterpriseManaged) => {
|
|
18937
20039
|
const pending = pendingStepUpRef.current;
|
|
18938
20040
|
if (pending && pending.serverName !== serverName) {
|
|
@@ -18961,7 +20063,7 @@ function App({
|
|
|
18961
20063
|
},
|
|
18962
20064
|
[]
|
|
18963
20065
|
);
|
|
18964
|
-
const handleAuthRecoveryRequired =
|
|
20066
|
+
const handleAuthRecoveryRequired = useCallback12(
|
|
18965
20067
|
(serverName, error) => {
|
|
18966
20068
|
const serverEntry = mcpServersRef.current[serverName];
|
|
18967
20069
|
const settings = serverEntry?.settings;
|
|
@@ -19024,7 +20126,7 @@ function App({
|
|
|
19024
20126
|
},
|
|
19025
20127
|
[presentStepUpForServer, runOAuthAuthentication]
|
|
19026
20128
|
);
|
|
19027
|
-
const onAuthRecoveryRequired =
|
|
20129
|
+
const onAuthRecoveryRequired = useCallback12(
|
|
19028
20130
|
(error) => {
|
|
19029
20131
|
if (selectedServer) {
|
|
19030
20132
|
handleAuthRecoveryRequired(selectedServer, error);
|
|
@@ -19032,11 +20134,12 @@ function App({
|
|
|
19032
20134
|
},
|
|
19033
20135
|
[selectedServer, handleAuthRecoveryRequired]
|
|
19034
20136
|
);
|
|
19035
|
-
const handleConnect =
|
|
20137
|
+
const handleConnect = useCallback12(async () => {
|
|
19036
20138
|
if (!selectedServer || !selectedInspectorClient || !selectedServerConfig) {
|
|
19037
20139
|
return;
|
|
19038
20140
|
}
|
|
19039
20141
|
disconnectAttemptRef.current++;
|
|
20142
|
+
clearOAuthAttemptRef.current++;
|
|
19040
20143
|
setDisconnectError(null);
|
|
19041
20144
|
const finishConnect = async () => {
|
|
19042
20145
|
await connectInspector();
|
|
@@ -19098,7 +20201,7 @@ function App({
|
|
|
19098
20201
|
runOAuthAuthentication,
|
|
19099
20202
|
handleAuthRecoveryRequired
|
|
19100
20203
|
]);
|
|
19101
|
-
|
|
20204
|
+
useEffect13(() => {
|
|
19102
20205
|
const cleanups = [];
|
|
19103
20206
|
for (const [serverName, client] of Object.entries(inspectorClients)) {
|
|
19104
20207
|
const onAmbient = () => {
|
|
@@ -19143,7 +20246,7 @@ function App({
|
|
|
19143
20246
|
}
|
|
19144
20247
|
};
|
|
19145
20248
|
}, [inspectorClients, handleAuthRecoveryRequired]);
|
|
19146
|
-
const handleDisconnect =
|
|
20249
|
+
const handleDisconnect = useCallback12(async () => {
|
|
19147
20250
|
if (!selectedServer) return;
|
|
19148
20251
|
const attempt = ++disconnectAttemptRef.current;
|
|
19149
20252
|
const attemptServer = selectedServer;
|
|
@@ -19157,17 +20260,43 @@ function App({
|
|
|
19157
20260
|
setDisconnectError(err instanceof Error ? err.message : String(err));
|
|
19158
20261
|
}
|
|
19159
20262
|
}, [selectedServer, disconnectInspector]);
|
|
19160
|
-
const handleClearOAuth =
|
|
20263
|
+
const handleClearOAuth = useCallback12(async () => {
|
|
19161
20264
|
if (!selectedInspectorClient) return;
|
|
19162
|
-
|
|
20265
|
+
const attempt = ++clearOAuthAttemptRef.current;
|
|
20266
|
+
const attemptServer = selectedServer;
|
|
20267
|
+
const revocation = await selectedInspectorClient.clearOAuthTokens({
|
|
20268
|
+
revoke: selectedServerEntry?.settings?.oauthRevokeOnClear !== false
|
|
20269
|
+
});
|
|
20270
|
+
if (clearOAuthAttemptRef.current !== attempt || selectedServerRef.current !== attemptServer) {
|
|
20271
|
+
return;
|
|
20272
|
+
}
|
|
19163
20273
|
setOauthStatus("idle");
|
|
19164
|
-
|
|
20274
|
+
if (revocation.status === "failed") {
|
|
20275
|
+
const warning = `Cleared locally, but revoking the grant at the authorization server failed: ${revocation.detail}. It may still be valid there.`;
|
|
20276
|
+
setOauthWarningText(warning);
|
|
20277
|
+
setOauthMessage(warning);
|
|
20278
|
+
} else {
|
|
20279
|
+
setOauthMessage(null);
|
|
20280
|
+
}
|
|
19165
20281
|
setConnectError(null);
|
|
19166
20282
|
if (inspectorStatus === "connected" || inspectorStatus === "connecting") {
|
|
19167
|
-
|
|
20283
|
+
try {
|
|
20284
|
+
await disconnectInspector();
|
|
20285
|
+
} catch (err) {
|
|
20286
|
+
setDisconnectError(err instanceof Error ? err.message : String(err));
|
|
20287
|
+
}
|
|
20288
|
+
if (clearOAuthAttemptRef.current !== attempt || selectedServerRef.current !== attemptServer) {
|
|
20289
|
+
return;
|
|
20290
|
+
}
|
|
19168
20291
|
}
|
|
19169
20292
|
setOauthRevision((n) => n + 1);
|
|
19170
|
-
}, [
|
|
20293
|
+
}, [
|
|
20294
|
+
selectedInspectorClient,
|
|
20295
|
+
selectedServer,
|
|
20296
|
+
selectedServerEntry,
|
|
20297
|
+
inspectorStatus,
|
|
20298
|
+
disconnectInspector
|
|
20299
|
+
]);
|
|
19171
20300
|
const currentServerState = useMemo4(() => {
|
|
19172
20301
|
if (!selectedServer) return null;
|
|
19173
20302
|
return {
|
|
@@ -19379,7 +20508,7 @@ function App({
|
|
|
19379
20508
|
/* @__PURE__ */ jsx16(Box27, { paddingLeft: 2, children: /* @__PURE__ */ jsx16(Text24, { dimColor: true, children: JSON.stringify(message.message, null, 2) }) })
|
|
19380
20509
|
] })
|
|
19381
20510
|
] });
|
|
19382
|
-
|
|
20511
|
+
useEffect13(() => {
|
|
19383
20512
|
if (!selectedServer) {
|
|
19384
20513
|
return;
|
|
19385
20514
|
}
|
|
@@ -19400,7 +20529,7 @@ function App({
|
|
|
19400
20529
|
inspectorFetchRequests,
|
|
19401
20530
|
inspectorStderrLogs
|
|
19402
20531
|
]);
|
|
19403
|
-
|
|
20532
|
+
useEffect13(() => {
|
|
19404
20533
|
if (activeTab === "messages") {
|
|
19405
20534
|
if (focus === "tabContentList" || focus === "tabContentDetails") {
|
|
19406
20535
|
setFocus("messagesList");
|
|
@@ -19415,7 +20544,7 @@ function App({
|
|
|
19415
20544
|
}
|
|
19416
20545
|
}
|
|
19417
20546
|
}, [activeTab]);
|
|
19418
|
-
|
|
20547
|
+
useEffect13(() => {
|
|
19419
20548
|
if (activeTab === "logging" && selectedServer) {
|
|
19420
20549
|
const client = inspectorClients[selectedServer];
|
|
19421
20550
|
if (client && client.getServerType() !== "stdio") {
|
|
@@ -19744,6 +20873,7 @@ function App({
|
|
|
19744
20873
|
inspectorClient: selectedInspectorClient,
|
|
19745
20874
|
oauthStatus,
|
|
19746
20875
|
oauthMessage,
|
|
20876
|
+
oauthMessageTone,
|
|
19747
20877
|
oauthRevision,
|
|
19748
20878
|
pendingStepUp: pendingStepUp?.serverName === selectedServer ? {
|
|
19749
20879
|
challenge: pendingStepUp.challenge,
|
|
@@ -19829,9 +20959,7 @@ function App({
|
|
|
19829
20959
|
width: contentWidth,
|
|
19830
20960
|
height: contentHeight,
|
|
19831
20961
|
focused: focus === "tabContentList" || focus === "tabContentDetails",
|
|
19832
|
-
onClearOAuth:
|
|
19833
|
-
void handleClearOAuth();
|
|
19834
|
-
},
|
|
20962
|
+
onClearOAuth: handleClearOAuth,
|
|
19835
20963
|
connectionStatus: inspectorStatus
|
|
19836
20964
|
}
|
|
19837
20965
|
) : null,
|