@frontmcp/adapters 1.4.1 → 1.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.
Files changed (37) hide show
  1. package/esm/index.mjs +21 -3
  2. package/esm/openapi/index.mjs +21 -3
  3. package/esm/package.json +7 -7
  4. package/esm/skills/index.mjs +258 -20
  5. package/index.js +21 -3
  6. package/openapi/index.js +21 -3
  7. package/openapi/openapi.adapter.d.ts +12 -0
  8. package/openapi/openapi.adapter.d.ts.map +1 -1
  9. package/openapi/openapi.types.d.ts +8 -1
  10. package/openapi/openapi.types.d.ts.map +1 -1
  11. package/package.json +7 -7
  12. package/skills/audit/audit-config.d.ts +1 -1
  13. package/skills/audit/audit-writer.d.ts +2 -1
  14. package/skills/audit/audit-writer.d.ts.map +1 -1
  15. package/skills/bundle/bundle-diff.d.ts.map +1 -1
  16. package/skills/bundle/bundle.schema.d.ts +1 -0
  17. package/skills/bundle/bundle.schema.d.ts.map +1 -1
  18. package/skills/bundle/bundle.types.d.ts +12 -3
  19. package/skills/bundle/bundle.types.d.ts.map +1 -1
  20. package/skills/deploy/manifest-to-config.d.ts +61 -0
  21. package/skills/deploy/manifest-to-config.d.ts.map +1 -0
  22. package/skills/index.d.ts +4 -2
  23. package/skills/index.d.ts.map +1 -1
  24. package/skills/index.js +261 -20
  25. package/skills/openapi/compile-skilled-bundle.d.ts +73 -0
  26. package/skills/openapi/compile-skilled-bundle.d.ts.map +1 -0
  27. package/skills/source-options.d.ts +8 -0
  28. package/skills/source-options.d.ts.map +1 -1
  29. package/skills/sources/index.d.ts +5 -4
  30. package/skills/sources/index.d.ts.map +1 -1
  31. package/skills/sources/inline.source.d.ts +16 -0
  32. package/skills/sources/inline.source.d.ts.map +1 -0
  33. package/skills/sources/npm.source.d.ts.map +1 -1
  34. package/skills/sources/saas-pull.source.d.ts +12 -2
  35. package/skills/sources/saas-pull.source.d.ts.map +1 -1
  36. package/skills/sources/skill-bundle-source.interface.d.ts +41 -0
  37. package/skills/sources/skill-bundle-source.interface.d.ts.map +1 -1
package/skills/index.js CHANGED
@@ -36,6 +36,7 @@ __export(skills_exports, {
36
36
  ClassificationRegistry: () => ClassificationRegistry,
37
37
  FilesystemSkillsSource: () => FilesystemSkillsSource,
38
38
  Hs256AuditSigner: () => Hs256AuditSigner,
39
+ InlineSource: () => InlineSource,
39
40
  MemoryAuditStore: () => MemoryAuditStore,
40
41
  NpmSource: () => NpmSource,
41
42
  OverlayParseError: () => OverlayParseError,
@@ -55,6 +56,7 @@ __export(skills_exports, {
55
56
  WebhookReplayGuard: () => WebhookReplayGuard,
56
57
  applyClassificationOverrides: () => applyClassificationOverrides,
57
58
  applyEnvironmentOverlay: () => applyEnvironmentOverlay,
59
+ buildFrontMcpConfigFromManifest: () => buildFrontMcpConfigFromManifest,
58
60
  buildKnownOps: () => buildKnownOps,
59
61
  buildResourceChangeNotification: () => buildResourceChangeNotification,
60
62
  bundleDigest: () => bundleDigest,
@@ -64,6 +66,7 @@ __export(skills_exports, {
64
66
  canonicalizeRecordForSigning: () => canonicalizeRecordForSigning,
65
67
  classifyOne: () => classifyOne,
66
68
  classifyOperations: () => classifyOperations,
69
+ compileSkilledBundleFromOpenApi: () => compileSkilledBundleFromOpenApi,
67
70
  createBundleSource: () => createBundleSource,
68
71
  crossValidate: () => crossValidate,
69
72
  crossValidateManifest: () => crossValidateManifest,
@@ -168,6 +171,9 @@ var operationDescriptorSchema = import_lazy_zod.z.object({
168
171
  mapper: import_lazy_zod.z.array(parameterMapperSchema).max(256),
169
172
  authBindingRef: import_lazy_zod.z.string().min(1).max(128),
170
173
  requiredAuthorities: authoritiesPolicySchema.optional(),
174
+ // Explicit opt-in that a policy-less op is intentionally public — consulted
175
+ // only when the deployment runs the executor with `unprotectedOps: 'deny'`.
176
+ public: import_lazy_zod.z.boolean().optional(),
171
177
  maxResponseBytes: import_lazy_zod.z.number().int().positive().max(64 * 1024 * 1024).optional(),
172
178
  timeoutMs: import_lazy_zod.z.number().int().positive().max(6e5).optional(),
173
179
  summary: import_lazy_zod.z.string().max(512).optional(),
@@ -248,6 +254,7 @@ var OverlayParseError = class extends Error {
248
254
  this.errors = errors;
249
255
  this.name = "OverlayParseError";
250
256
  }
257
+ errors;
251
258
  };
252
259
  function parseRaw(input) {
253
260
  switch (input.kind) {
@@ -305,7 +312,7 @@ function parseOverlay(input) {
305
312
  }
306
313
 
307
314
  // libs/adapters/src/skills/bundle/bundle-diff.ts
308
- var opEqual = (a, b) => a.operationId === b.operationId && a.serviceId === b.serviceId && a.httpMethod === b.httpMethod && a.pathTemplate === b.pathTemplate && a.authBindingRef === b.authBindingRef && JSON.stringify(a.mapper ?? null) === JSON.stringify(b.mapper ?? null) && JSON.stringify(a.inputSchema) === JSON.stringify(b.inputSchema) && JSON.stringify(a.outputSchema) === JSON.stringify(b.outputSchema) && JSON.stringify(a.requiredAuthorities ?? null) === JSON.stringify(b.requiredAuthorities ?? null) && a.maxResponseBytes === b.maxResponseBytes && a.timeoutMs === b.timeoutMs;
315
+ var opEqual = (a, b) => a.operationId === b.operationId && a.serviceId === b.serviceId && a.httpMethod === b.httpMethod && a.pathTemplate === b.pathTemplate && a.authBindingRef === b.authBindingRef && JSON.stringify(a.mapper ?? null) === JSON.stringify(b.mapper ?? null) && JSON.stringify(a.inputSchema) === JSON.stringify(b.inputSchema) && JSON.stringify(a.outputSchema) === JSON.stringify(b.outputSchema) && JSON.stringify(a.requiredAuthorities ?? null) === JSON.stringify(b.requiredAuthorities ?? null) && (a.public ?? false) === (b.public ?? false) && a.maxResponseBytes === b.maxResponseBytes && a.timeoutMs === b.timeoutMs;
309
316
  var skillEqual = (a, b) => a.id === b.id && a.name === b.name && a.description === b.description && a.instructions === b.instructions && JSON.stringify(a.tags ?? []) === JSON.stringify(b.tags ?? []) && JSON.stringify(a.operationIds) === JSON.stringify(b.operationIds) && JSON.stringify(a.requiredAuthorities ?? null) === JSON.stringify(b.requiredAuthorities ?? null);
310
317
  function diffBundles(oldBundle, newBundle) {
311
318
  const oldSkills = new Map((oldBundle?.skills ?? []).map((s) => [s.id, s]));
@@ -546,6 +553,7 @@ var BundlePinnedError = class extends Error {
546
553
  this.pinnedVersion = pinnedVersion;
547
554
  this.name = "BundlePinnedError";
548
555
  }
556
+ pinnedVersion;
549
557
  };
550
558
 
551
559
  // libs/adapters/src/skills/dependency/skill-dag.ts
@@ -555,6 +563,7 @@ var SkillDependencyCycleError = class extends Error {
555
563
  this.cycle = cycle;
556
564
  this.name = "SkillDependencyCycleError";
557
565
  }
566
+ cycle;
558
567
  };
559
568
  var SkillDependencyMissingError = class extends Error {
560
569
  constructor(skillId, missingId) {
@@ -563,6 +572,8 @@ var SkillDependencyMissingError = class extends Error {
563
572
  this.missingId = missingId;
564
573
  this.name = "SkillDependencyMissingError";
565
574
  }
575
+ skillId;
576
+ missingId;
566
577
  };
567
578
  var SkillDependencyInvariantError = class extends Error {
568
579
  constructor(message) {
@@ -725,7 +736,22 @@ var saasSourceSchema = import_lazy_zod2.z.object({
725
736
  /** Expected issuer (`iss`) claim. */
726
737
  expectedIssuer: import_lazy_zod2.z.string().min(1)
727
738
  });
728
- var bundleSourceSchema = import_lazy_zod2.z.discriminatedUnion("type", [staticSourceSchema, npmSourceSchema, saasSourceSchema]);
739
+ var inlineSourceSchema = import_lazy_zod2.z.object({
740
+ type: import_lazy_zod2.z.literal("inline"),
741
+ /**
742
+ * The skilled-OpenAPI bundle object, embedded directly (no filesystem, no
743
+ * network). The right source for V8-isolate runtimes (Cloudflare Workers),
744
+ * where `static` (fs) and `npm` can't run and `saas` needs an endpoint. The
745
+ * object is validated by the overlay parser, same as file/remote bundles.
746
+ */
747
+ content: import_lazy_zod2.z.unknown()
748
+ });
749
+ var bundleSourceSchema = import_lazy_zod2.z.discriminatedUnion("type", [
750
+ staticSourceSchema,
751
+ npmSourceSchema,
752
+ saasSourceSchema,
753
+ inlineSourceSchema
754
+ ]);
729
755
  var signatureKeySchema = import_lazy_zod2.z.object({
730
756
  /** Stable key id (matches `kid` claim in the bundle JWT). */
731
757
  keyId: import_lazy_zod2.z.string().min(1),
@@ -735,13 +761,50 @@ var signatureKeySchema = import_lazy_zod2.z.object({
735
761
  publicKeyPem: import_lazy_zod2.z.string().min(1)
736
762
  });
737
763
 
764
+ // libs/adapters/src/skills/sources/inline.source.ts
765
+ var InlineSource = class {
766
+ constructor(options, logger) {
767
+ this.options = options;
768
+ this.logger = logger;
769
+ }
770
+ options;
771
+ logger;
772
+ id = "inline:bundle";
773
+ listeners = /* @__PURE__ */ new Set();
774
+ async start() {
775
+ const bundle = this.parse();
776
+ for (const fn of this.listeners) {
777
+ try {
778
+ fn(bundle);
779
+ } catch (e) {
780
+ this.logger.warn(`[inline-source] listener threw: ${e.message}`);
781
+ }
782
+ }
783
+ }
784
+ onChange(listener) {
785
+ this.listeners.add(listener);
786
+ return () => {
787
+ this.listeners.delete(listener);
788
+ };
789
+ }
790
+ async stop() {
791
+ this.listeners.clear();
792
+ }
793
+ parse() {
794
+ return parseOverlay({ kind: "object", content: this.options.content });
795
+ }
796
+ };
797
+
738
798
  // libs/adapters/src/skills/sources/npm.source.ts
799
+ var npmDynamicImport;
739
800
  var NpmSource = class {
740
801
  constructor(options, logger) {
741
802
  this.options = options;
742
803
  this.logger = logger;
743
804
  this.id = `npm:${this.options.packageName}${this.options.exportName ? `#${this.options.exportName}` : ""}`;
744
805
  }
806
+ options;
807
+ logger;
745
808
  id;
746
809
  listeners = /* @__PURE__ */ new Set();
747
810
  cached;
@@ -781,9 +844,16 @@ var NpmSource = class {
781
844
  }
782
845
  return parseOverlay({ kind: "object", content: exported });
783
846
  }
784
- // Indirected so tests can stub.
847
+ // Indirected so tests can stub. The dynamic `import()` is wrapped in a
848
+ // lazily-built `new Function` so static bundlers (esbuild / `wrangler dev` /
849
+ // miniflare) don't try to resolve the runtime-computed package specifier at
850
+ // build time — installing an npm bundle is a Node-only path that never runs
851
+ // on a V8 isolate, but `createBundleSource` keeps NpmSource statically
852
+ // reachable in the worker bundle. The Function is only built when this runs
853
+ // (Node), so a Worker that merely bundles it never evaluates it.
785
854
  dynamicImport(specifier) {
786
- return import(specifier);
855
+ npmDynamicImport ??= new Function("s", "return import(s)");
856
+ return npmDynamicImport(specifier);
787
857
  }
788
858
  notify(bundle) {
789
859
  for (const fn of this.listeners) {
@@ -801,35 +871,49 @@ var import_utils = require("@frontmcp/utils");
801
871
  var DEFAULT_CACHE_DIR = ".frontmcp/skilled-openapi";
802
872
  var DEFAULT_PULL_TIMEOUT_MS = 3e4;
803
873
  var SaasPullSource = class {
804
- constructor(options, cacheDir, logger) {
874
+ constructor(options, cacheDir, logger, deps = {}) {
805
875
  this.options = options;
806
876
  this.cacheDir = cacheDir;
807
877
  this.logger = logger;
878
+ this.deps = deps;
808
879
  this.id = `saas:${this.options.endpoint}`;
809
880
  }
881
+ options;
882
+ cacheDir;
883
+ logger;
884
+ deps;
810
885
  id;
811
886
  listeners = /* @__PURE__ */ new Set();
812
887
  pollHandle;
813
888
  inFlight = false;
814
889
  stopped = false;
815
890
  async start() {
891
+ if (this.stopped || this.inFlight) {
892
+ this.schedulePoll();
893
+ return;
894
+ }
895
+ this.inFlight = true;
816
896
  let bundle;
817
897
  try {
818
- bundle = await this.fetchOnce();
819
- await this.persistCache(bundle);
820
- } catch (e) {
821
- this.logger.warn(
822
- `[saas-source] initial pull failed (${e.message}); attempting cached bundle fallback`
823
- );
824
- bundle = await this.loadCache();
825
- if (!bundle) {
826
- throw new Error(
827
- `[saas-source] initial pull failed and no cached bundle is available at ${this.cachePath()}: ${e.message}`
898
+ try {
899
+ bundle = await this.fetchOnce();
900
+ await this.persistCache(bundle);
901
+ } catch (e) {
902
+ this.logger.warn(
903
+ `[saas-source] initial pull failed (${e.message}); attempting cached bundle fallback`
828
904
  );
905
+ bundle = await this.loadCache();
906
+ if (!bundle) {
907
+ throw new Error(
908
+ `[saas-source] initial pull failed and no cached bundle is available at ${this.cachePath()}: ${e.message}`
909
+ );
910
+ }
911
+ this.logger.warn(`[saas-source] using cached bundle "${bundle.bundleId}@${bundle.version}"`);
829
912
  }
830
- this.logger.warn(`[saas-source] using cached bundle "${bundle.bundleId}@${bundle.version}"`);
913
+ this.notify(bundle);
914
+ } finally {
915
+ this.inFlight = false;
831
916
  }
832
- this.notify(bundle);
833
917
  this.schedulePoll();
834
918
  }
835
919
  onChange(listener) {
@@ -847,12 +931,32 @@ var SaasPullSource = class {
847
931
  this.listeners.clear();
848
932
  }
849
933
  schedulePoll() {
850
- if (this.stopped) return;
934
+ if (this.stopped || this.deps.disablePolling) return;
935
+ if (this.pollHandle) clearTimeout(this.pollHandle);
851
936
  this.pollHandle = setTimeout(() => {
852
937
  void this.pollOnce();
853
938
  }, this.options.pollIntervalMs);
854
939
  this.pollHandle.unref?.();
855
940
  }
941
+ /**
942
+ * Manually pull a fresh bundle, persist it, and notify listeners. Drive this
943
+ * from a Cron Trigger / Durable Object alarm on runtimes without background
944
+ * timers (where `disablePolling` is set). Single-flight: returns `undefined`
945
+ * if a pull is already in flight; throws if the pull itself fails (the caller
946
+ * — e.g. a scheduled handler — decides how to surface it).
947
+ */
948
+ async refresh() {
949
+ if (this.stopped || this.inFlight) return void 0;
950
+ this.inFlight = true;
951
+ try {
952
+ const bundle = await this.fetchOnce();
953
+ await this.persistCache(bundle);
954
+ this.notify(bundle);
955
+ return bundle;
956
+ } finally {
957
+ this.inFlight = false;
958
+ }
959
+ }
856
960
  async pollOnce() {
857
961
  if (this.stopped) return;
858
962
  if (this.inFlight) {
@@ -903,6 +1007,10 @@ var SaasPullSource = class {
903
1007
  }
904
1008
  async persistCache(bundle) {
905
1009
  try {
1010
+ if (this.deps.cache) {
1011
+ await this.deps.cache.write(bundle);
1012
+ return;
1013
+ }
906
1014
  const filePath = this.cachePath();
907
1015
  await (0, import_utils.ensureDir)((0, import_utils.dirname)(filePath));
908
1016
  await (0, import_utils.writeFile)(filePath, JSON.stringify(bundle));
@@ -912,6 +1020,11 @@ var SaasPullSource = class {
912
1020
  }
913
1021
  async loadCache() {
914
1022
  try {
1023
+ if (this.deps.cache) {
1024
+ const cached = await this.deps.cache.read();
1025
+ if (cached === void 0 || cached === null) return void 0;
1026
+ return parseOverlay({ kind: "object", content: cached });
1027
+ }
915
1028
  const filePath = this.cachePath();
916
1029
  const raw = await (0, import_utils.readFile)(filePath, "utf8");
917
1030
  return parseOverlay({ kind: "json", content: raw });
@@ -938,6 +1051,8 @@ var StaticSource = class {
938
1051
  this.logger = logger;
939
1052
  this.id = `static:${this.options.path}`;
940
1053
  }
1054
+ options;
1055
+ logger;
941
1056
  id;
942
1057
  listeners = /* @__PURE__ */ new Set();
943
1058
  watcher;
@@ -1022,17 +1137,74 @@ var StaticSource = class {
1022
1137
  };
1023
1138
 
1024
1139
  // libs/adapters/src/skills/sources/index.ts
1025
- function createBundleSource(source, cacheDir, logger) {
1140
+ function createBundleSource(source, cacheDir, logger, deps) {
1026
1141
  switch (source.type) {
1027
1142
  case "static":
1028
1143
  return new StaticSource(source, logger);
1029
1144
  case "npm":
1030
1145
  return new NpmSource(source, logger);
1031
1146
  case "saas":
1032
- return new SaasPullSource(source, cacheDir, logger);
1147
+ return new SaasPullSource(source, cacheDir, logger, deps);
1148
+ case "inline":
1149
+ return new InlineSource(source, logger);
1033
1150
  }
1034
1151
  }
1035
1152
 
1153
+ // libs/adapters/src/skills/openapi/compile-skilled-bundle.ts
1154
+ var import_mcp_from_openapi = require("mcp-from-openapi");
1155
+ async function compileSkilledBundleFromOpenApi(openapi, skills, options) {
1156
+ const serviceId = options.serviceId ?? "api";
1157
+ const baseUrl = options.baseUrl ?? openapi.servers?.[0]?.url;
1158
+ if (!baseUrl) {
1159
+ throw new Error("compileSkilledBundleFromOpenApi: no baseUrl \u2014 pass options.baseUrl or declare servers[] in the OpenAPI doc.");
1160
+ }
1161
+ const generator = await import_mcp_from_openapi.OpenAPIToolGenerator.fromJSON(openapi);
1162
+ const tools = await generator.generateTools();
1163
+ const byOperationId = /* @__PURE__ */ new Map();
1164
+ for (const tool of tools) {
1165
+ const opId = tool.metadata.operationId;
1166
+ if (opId) byOperationId.set(opId, tool);
1167
+ }
1168
+ const referenced = /* @__PURE__ */ new Set();
1169
+ for (const skill of skills) for (const opId of skill.operationIds) referenced.add(opId);
1170
+ const operations = {};
1171
+ for (const opId of referenced) {
1172
+ const tool = byOperationId.get(opId);
1173
+ if (!tool) {
1174
+ throw new Error(`compileSkilledBundleFromOpenApi: operationId "${opId}" is referenced by a skill but not defined in the OpenAPI document.`);
1175
+ }
1176
+ operations[opId] = {
1177
+ operationId: opId,
1178
+ serviceId,
1179
+ httpMethod: tool.metadata.method.toUpperCase(),
1180
+ pathTemplate: tool.metadata.path,
1181
+ summary: tool.metadata.operationSummary ?? tool.description,
1182
+ inputSchema: tool.inputSchema,
1183
+ outputSchema: tool.outputSchema ?? { type: "object" },
1184
+ mapper: tool.mapper,
1185
+ authBindingRef: "default"
1186
+ };
1187
+ }
1188
+ return {
1189
+ schemaVersion: 1,
1190
+ bundleId: options.bundleId,
1191
+ version: options.version,
1192
+ generatedAt: options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1193
+ sourceDigest: options.sourceDigest ?? "0".repeat(64),
1194
+ services: [{ id: serviceId, baseUrl }],
1195
+ authBindings: { default: options.authBinding ?? { kind: "none" } },
1196
+ skills: skills.map((s) => ({
1197
+ id: s.id,
1198
+ name: s.name,
1199
+ description: s.description,
1200
+ instructions: s.instructions,
1201
+ tags: s.tags ?? [],
1202
+ operationIds: s.operationIds
1203
+ })),
1204
+ operations
1205
+ };
1206
+ }
1207
+
1036
1208
  // libs/adapters/src/skills/sources/filesystem-skills.source.ts
1037
1209
  var import_utils3 = require("@frontmcp/utils");
1038
1210
  var DEFAULT_OPTIONS = {
@@ -1047,6 +1219,7 @@ var FilesystemSkillsSource = class {
1047
1219
  this.options = { ...DEFAULT_OPTIONS, ...options };
1048
1220
  this.id = `filesystem-skills:${this.options.skillsDir}`;
1049
1221
  }
1222
+ logger;
1050
1223
  id;
1051
1224
  options;
1052
1225
  listeners = /* @__PURE__ */ new Set();
@@ -1445,6 +1618,8 @@ var BundlePushJwtVerifier = class {
1445
1618
  jwksUri: options.jwksUri
1446
1619
  };
1447
1620
  }
1621
+ options;
1622
+ logger;
1448
1623
  providerRef;
1449
1624
  jwks;
1450
1625
  /**
@@ -1839,6 +2014,8 @@ var StorageAdapterAuditStore = class {
1839
2014
  this.adapter = adapter;
1840
2015
  this.options = options;
1841
2016
  }
2017
+ adapter;
2018
+ options;
1842
2019
  get sequenceKey() {
1843
2020
  return this.options.sequenceKey ?? SKILL_AUDIT_KEYS.sequence;
1844
2021
  }
@@ -1915,6 +2092,10 @@ var SkillAuditWriter = class {
1915
2092
  this.subjectHashSecret = options.subjectHashSecret ?? this.deriveDefaultSubjectSecret();
1916
2093
  this.maxQueueDepth = options.maxQueueDepth ?? SKILL_AUDIT_QUEUE_MAX;
1917
2094
  }
2095
+ store;
2096
+ signer;
2097
+ logger;
2098
+ metrics;
1918
2099
  /**
1919
2100
  * Single-flight queue: every append() chains onto this promise so the
1920
2101
  * read-tail-then-append-with-prevHash sequence stays atomic per process.
@@ -2529,6 +2710,63 @@ function crossValidateManifest(manifest) {
2529
2710
  return errors.length === 0 ? { ok: true } : { ok: false, errors };
2530
2711
  }
2531
2712
 
2713
+ // libs/adapters/src/skills/deploy/manifest-to-config.ts
2714
+ function specStem(ref) {
2715
+ const noQuery = ref.split("?")[0].split("#")[0];
2716
+ const base = noQuery.split("/").pop() ?? noQuery;
2717
+ const stem = base.replace(/\.(ya?ml|json)$/i, "");
2718
+ const safe = (stem || base).replace(/[^a-zA-Z0-9_.-]/g, "-");
2719
+ return safe || "spec";
2720
+ }
2721
+ function normalizeSpec(source) {
2722
+ if (typeof source === "string") {
2723
+ const id = specStem(source);
2724
+ return { id, spec: source, bindingName: id };
2725
+ }
2726
+ return {
2727
+ id: source.id,
2728
+ spec: source.spec,
2729
+ baseUrl: source.baseUrl,
2730
+ bindingName: source.bindingName ?? source.id
2731
+ };
2732
+ }
2733
+ function buildFrontMcpConfigFromManifest(manifest) {
2734
+ const info = {
2735
+ name: manifest.server.info.name,
2736
+ version: manifest.server.info.version,
2737
+ ...manifest.server.info.title !== void 0 ? { title: manifest.server.info.title } : {}
2738
+ };
2739
+ const skills = {
2740
+ source: manifest.skills.source,
2741
+ ...manifest.skills.alwaysLoad ? { alwaysLoad: manifest.skills.alwaysLoad } : {},
2742
+ ...manifest.skills.tags ? { tags: manifest.skills.tags } : {}
2743
+ };
2744
+ let specs = [];
2745
+ let specsDir;
2746
+ if (typeof manifest.specs === "string") {
2747
+ specsDir = manifest.specs;
2748
+ } else {
2749
+ specs = manifest.specs.map(normalizeSpec);
2750
+ const seen = /* @__PURE__ */ new Set();
2751
+ for (const s of specs) {
2752
+ if (seen.has(s.id)) {
2753
+ throw new Error(
2754
+ `manifest specs: duplicate spec id "${s.id}" (derived from the filename stem). Give the colliding spec an explicit { id } in frontmcp.deploy.yaml.`
2755
+ );
2756
+ }
2757
+ seen.add(s.id);
2758
+ }
2759
+ }
2760
+ return {
2761
+ info,
2762
+ ...manifest.server.instructions !== void 0 ? { instructions: manifest.server.instructions } : {},
2763
+ skillsConfig: { enabled: true, injectInstructions: "append" },
2764
+ skills,
2765
+ specs,
2766
+ ...specsDir !== void 0 ? { specsDir } : {}
2767
+ };
2768
+ }
2769
+
2532
2770
  // libs/adapters/src/skills/classifier/openapi-classify.ts
2533
2771
  function classifyOperations(specId, ops) {
2534
2772
  if (!specId || specId.length === 0) {
@@ -2848,6 +3086,7 @@ var ClassificationRegistry = class {
2848
3086
  ClassificationRegistry,
2849
3087
  FilesystemSkillsSource,
2850
3088
  Hs256AuditSigner,
3089
+ InlineSource,
2851
3090
  MemoryAuditStore,
2852
3091
  NpmSource,
2853
3092
  OverlayParseError,
@@ -2867,6 +3106,7 @@ var ClassificationRegistry = class {
2867
3106
  WebhookReplayGuard,
2868
3107
  applyClassificationOverrides,
2869
3108
  applyEnvironmentOverlay,
3109
+ buildFrontMcpConfigFromManifest,
2870
3110
  buildKnownOps,
2871
3111
  buildResourceChangeNotification,
2872
3112
  bundleDigest,
@@ -2876,6 +3116,7 @@ var ClassificationRegistry = class {
2876
3116
  canonicalizeRecordForSigning,
2877
3117
  classifyOne,
2878
3118
  classifyOperations,
3119
+ compileSkilledBundleFromOpenApi,
2879
3120
  createBundleSource,
2880
3121
  crossValidate,
2881
3122
  crossValidateManifest,
@@ -0,0 +1,73 @@
1
+ /** A hand-authored skill that declares which OpenAPI operations it serves. */
2
+ export interface SkillOpenApiRef {
3
+ /** Stable skill id (kebab-case). */
4
+ id: string;
5
+ /** Human-readable skill name. */
6
+ name: string;
7
+ /** One-line description (used for search ranking). */
8
+ description: string;
9
+ /** Markdown instructions for performing the skill. */
10
+ instructions: string;
11
+ /** OpenAPI `operationId`s this skill exposes. Operations not referenced by any skill are dropped. */
12
+ operationIds: string[];
13
+ /** Optional tags (search facets). */
14
+ tags?: string[];
15
+ }
16
+ export interface CompileSkilledBundleOptions {
17
+ /** Stable bundle id (e.g. `acme:billing`). */
18
+ bundleId: string;
19
+ /** Bundle version (e.g. `1.0.0`). */
20
+ version: string;
21
+ /** Service id the operations bind to. Default `'api'`. */
22
+ serviceId?: string;
23
+ /**
24
+ * Base URL for the service. Defaults to the OpenAPI doc's first `servers[].url`.
25
+ * Required if the document declares no servers.
26
+ */
27
+ baseUrl?: string;
28
+ /** ISO timestamp for `generatedAt`. Defaults to now. */
29
+ generatedAt?: string;
30
+ /** Auth binding for the service. Default `{ kind: 'none' }`. */
31
+ authBinding?: Record<string, unknown>;
32
+ /** Digest of the source inputs (provenance). Defaults to a zero digest. */
33
+ sourceDigest?: string;
34
+ }
35
+ /** A compiled skilled-OpenAPI bundle (schemaVersion 1) — validated downstream by `parseOverlay`. */
36
+ export interface CompiledSkilledBundle {
37
+ schemaVersion: 1;
38
+ bundleId: string;
39
+ version: string;
40
+ generatedAt: string;
41
+ sourceDigest: string;
42
+ services: Array<{
43
+ id: string;
44
+ baseUrl: string;
45
+ description?: string;
46
+ }>;
47
+ authBindings: Record<string, Record<string, unknown>>;
48
+ skills: Array<{
49
+ id: string;
50
+ name: string;
51
+ description: string;
52
+ instructions: string;
53
+ tags: string[];
54
+ operationIds: string[];
55
+ }>;
56
+ operations: Record<string, {
57
+ operationId: string;
58
+ serviceId: string;
59
+ httpMethod: string;
60
+ pathTemplate: string;
61
+ summary?: string;
62
+ inputSchema: unknown;
63
+ outputSchema: unknown;
64
+ mapper: unknown[];
65
+ authBindingRef: string;
66
+ }>;
67
+ }
68
+ /**
69
+ * Compile `(openapi, skills)` → a skilled-OpenAPI bundle. Throws if a skill
70
+ * references an `operationId` the OpenAPI doesn't define (fail-fast on drift).
71
+ */
72
+ export declare function compileSkilledBundleFromOpenApi(openapi: object, skills: SkillOpenApiRef[], options: CompileSkilledBundleOptions): Promise<CompiledSkilledBundle>;
73
+ //# sourceMappingURL=compile-skilled-bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-skilled-bundle.d.ts","sourceRoot":"","sources":["../../../src/skills/openapi/compile-skilled-bundle.ts"],"names":[],"mappings":"AAmBA,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,qGAAqG;IACrG,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,oGAAoG;AACpG,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,CAAC,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,MAAM,EAAE,KAAK,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,CAChB,MAAM,EACN;QACE,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,OAAO,CAAC;QACrB,YAAY,EAAE,OAAO,CAAC;QACtB,MAAM,EAAE,OAAO,EAAE,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;KACxB,CACF,CAAC;CACH;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,eAAe,EAAE,EACzB,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CA2DhC"}
@@ -20,6 +20,10 @@ export declare const saasSourceSchema: import("@frontmcp/lazy-zod").ZodObject<{
20
20
  jwksUrl: import("@frontmcp/lazy-zod").ZodString;
21
21
  expectedIssuer: import("@frontmcp/lazy-zod").ZodString;
22
22
  }, import("zod/v4/core").$strip>;
23
+ export declare const inlineSourceSchema: import("@frontmcp/lazy-zod").ZodObject<{
24
+ type: import("@frontmcp/lazy-zod").ZodLiteral<"inline">;
25
+ content: import("@frontmcp/lazy-zod").ZodUnknown;
26
+ }, import("zod/v4/core").$strip>;
23
27
  export declare const bundleSourceSchema: import("@frontmcp/lazy-zod").ZodDiscriminatedUnion<[import("@frontmcp/lazy-zod").ZodObject<{
24
28
  type: import("@frontmcp/lazy-zod").ZodLiteral<"static">;
25
29
  path: import("@frontmcp/lazy-zod").ZodString;
@@ -38,10 +42,14 @@ export declare const bundleSourceSchema: import("@frontmcp/lazy-zod").ZodDiscrim
38
42
  enableWebhook: import("@frontmcp/lazy-zod").ZodDefault<import("@frontmcp/lazy-zod").ZodBoolean>;
39
43
  jwksUrl: import("@frontmcp/lazy-zod").ZodString;
40
44
  expectedIssuer: import("@frontmcp/lazy-zod").ZodString;
45
+ }, import("zod/v4/core").$strip>, import("@frontmcp/lazy-zod").ZodObject<{
46
+ type: import("@frontmcp/lazy-zod").ZodLiteral<"inline">;
47
+ content: import("@frontmcp/lazy-zod").ZodUnknown;
41
48
  }, import("zod/v4/core").$strip>], "type">;
42
49
  export type StaticSourceOptions = z.infer<typeof staticSourceSchema>;
43
50
  export type NpmSourceOptions = z.infer<typeof npmSourceSchema>;
44
51
  export type SaasSourceOptions = z.infer<typeof saasSourceSchema>;
52
+ export type InlineSourceOptions = z.infer<typeof inlineSourceSchema>;
45
53
  export type BundleSourceOptions = z.infer<typeof bundleSourceSchema>;
46
54
  export declare const signatureKeySchema: import("@frontmcp/lazy-zod").ZodObject<{
47
55
  keyId: import("@frontmcp/lazy-zod").ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"source-options.d.ts","sourceRoot":"","sources":["../../src/skills/source-options.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AAkBvC,eAAO,MAAM,kBAAkB;;;;gCAM7B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;gCAW1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;gCAsB3B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;0CAAwF,CAAC;AAExH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AACjE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAIrE,eAAO,MAAM,kBAAkB;;;;;;;gCAO7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"source-options.d.ts","sourceRoot":"","sources":["../../src/skills/source-options.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AAkBvC,eAAO,MAAM,kBAAkB;;;;gCAM7B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;gCAW1B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;gCAsB3B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;gCAS7B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;0CAK7B,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AACjE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACrE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAIrE,eAAO,MAAM,kBAAkB;;;;;;;gCAO7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -1,10 +1,11 @@
1
1
  import type { FrontMcpLogger } from '@frontmcp/sdk';
2
2
  import type { BundleSourceOptions } from '../source-options';
3
+ import { InlineSource } from './inline.source';
3
4
  import { NpmSource } from './npm.source';
4
5
  import { SaasPullSource } from './saas-pull.source';
5
- import type { SkillBundleSource } from './skill-bundle-source.interface';
6
+ import type { BundleSourceDeps, SkillBundleSource } from './skill-bundle-source.interface';
6
7
  import { StaticSource } from './static.source';
7
- export { StaticSource, NpmSource, SaasPullSource };
8
- export type { SkillBundleSource, BundleSourceListener } from './skill-bundle-source.interface';
9
- export declare function createBundleSource(source: BundleSourceOptions, cacheDir: string | undefined, logger: FrontMcpLogger): SkillBundleSource;
8
+ export { StaticSource, NpmSource, SaasPullSource, InlineSource };
9
+ export type { BundleCacheStore, BundleSourceDeps, BundleSourceListener, SkillBundleSource, } from './skill-bundle-source.interface';
10
+ export declare function createBundleSource(source: BundleSourceOptions, cacheDir: string | undefined, logger: FrontMcpLogger, deps?: BundleSourceDeps): SkillBundleSource;
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE/F,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,cAAc,GACrB,iBAAiB,CASnB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AACjE,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,iCAAiC,CAAC;AAEzC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,EAAE,cAAc,EAGtB,IAAI,CAAC,EAAE,gBAAgB,GACtB,iBAAiB,CAWnB"}
@@ -0,0 +1,16 @@
1
+ import type { FrontMcpLogger } from '@frontmcp/sdk';
2
+ import type { InlineSourceOptions } from '../source-options';
3
+ import type { BundleSourceListener, SkillBundleSource } from './skill-bundle-source.interface';
4
+ /** Loads a bundle from an embedded object. Static (never refreshes). */
5
+ export declare class InlineSource implements SkillBundleSource {
6
+ private readonly options;
7
+ private readonly logger;
8
+ readonly id = "inline:bundle";
9
+ private readonly listeners;
10
+ constructor(options: InlineSourceOptions, logger: FrontMcpLogger);
11
+ start(): Promise<void>;
12
+ onChange(listener: BundleSourceListener): () => void;
13
+ stop(): Promise<void>;
14
+ private parse;
15
+ }
16
+ //# sourceMappingURL=inline.source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/inline.source.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE/F,wEAAwE;AACxE,qBAAa,YAAa,YAAW,iBAAiB;IAMlD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,QAAQ,CAAC,EAAE,mBAAmB;IAE9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmC;gBAG1C,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,cAAc;IAGnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAO9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,OAAO,CAAC,KAAK;CAGd"}
@@ -1 +1 @@
1
- {"version":3,"file":"npm.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/npm.source.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAE/F;;;;;;;;;;;GAWG;AACH,qBAAa,SAAU,YAAW,iBAAiB;IAO/C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,MAAM,CAAC,CAAiB;gBAGb,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,cAAc;IAKnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAe9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAIb,qBAAqB;IAqBnC,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5D,OAAO,CAAC,MAAM;CASf"}
1
+ {"version":3,"file":"npm.source.d.ts","sourceRoot":"","sources":["../../../src/skills/sources/npm.source.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAO/F;;;;;;;;;;;GAWG;AACH,qBAAa,SAAU,YAAW,iBAAiB;IAO/C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,MAAM,CAAC,CAAiB;gBAGb,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,cAAc;IAKnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,MAAM,IAAI;IAe9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAIb,qBAAqB;IA2BnC,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK5D,OAAO,CAAC,MAAM;CASf"}