@frontmcp/sdk 1.8.1 → 1.8.2

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 (60) hide show
  1. package/common/metadata/front-mcp.metadata.d.ts +15 -0
  2. package/common/metadata/front-mcp.metadata.d.ts.map +1 -1
  3. package/common/metadata/tool-ui.metadata.d.ts +1 -0
  4. package/common/metadata/tool-ui.metadata.d.ts.map +1 -1
  5. package/completion/flows/complete.flow.d.ts +9 -2
  6. package/completion/flows/complete.flow.d.ts.map +1 -1
  7. package/context/frontmcp-context.d.ts +2 -0
  8. package/context/frontmcp-context.d.ts.map +1 -1
  9. package/esm/index.mjs +445 -250
  10. package/flows/resolved-entries.d.ts +9 -0
  11. package/flows/resolved-entries.d.ts.map +1 -0
  12. package/front-mcp/front-mcp.d.ts.map +1 -1
  13. package/index.d.ts +2 -2
  14. package/index.d.ts.map +1 -1
  15. package/index.js +441 -249
  16. package/package.json +10 -10
  17. package/plugin/plugin.registry.d.ts +2 -0
  18. package/plugin/plugin.registry.d.ts.map +1 -1
  19. package/prompt/flows/get-prompt.flow.d.ts.map +1 -1
  20. package/prompt/prompt.registry.d.ts +1 -0
  21. package/prompt/prompt.registry.d.ts.map +1 -1
  22. package/provider/provider.registry.d.ts +6 -1
  23. package/provider/provider.registry.d.ts.map +1 -1
  24. package/resource/flows/read-resource.flow.d.ts.map +1 -1
  25. package/resource/resource.registry.d.ts +1 -0
  26. package/resource/resource.registry.d.ts.map +1 -1
  27. package/scope/scope.instance.d.ts.map +1 -1
  28. package/skill/flows/http/skills-api.flow.d.ts +0 -6
  29. package/skill/flows/http/skills-api.flow.d.ts.map +1 -1
  30. package/skill/flows/load-skill.flow.d.ts +0 -7
  31. package/skill/flows/load-skill.flow.d.ts.map +1 -1
  32. package/skill/flows/search-skills.flow.d.ts +0 -13
  33. package/skill/flows/search-skills.flow.d.ts.map +1 -1
  34. package/skill/index.d.ts +2 -2
  35. package/skill/index.d.ts.map +1 -1
  36. package/skill/sep-2640/sep-2640.per-skill.d.ts.map +1 -1
  37. package/skill/skill-authorities.helper.d.ts +0 -20
  38. package/skill/skill-authorities.helper.d.ts.map +1 -1
  39. package/skill/skill-entry.resolver.d.ts +27 -0
  40. package/skill/skill-entry.resolver.d.ts.map +1 -0
  41. package/skill/skill-filter.helper.d.ts +15 -6
  42. package/skill/skill-filter.helper.d.ts.map +1 -1
  43. package/skill/skill-instructions.helper.d.ts +30 -0
  44. package/skill/skill-instructions.helper.d.ts.map +1 -1
  45. package/tool/flows/call-tool.flow.d.ts.map +1 -1
  46. package/tool/tool.registry.d.ts +1 -1
  47. package/tool/tool.registry.d.ts.map +1 -1
  48. package/tool/ui/ui-shared.d.ts +12 -1
  49. package/tool/ui/ui-shared.d.ts.map +1 -1
  50. package/transport/adapters/transport.local.adapter.d.ts +0 -9
  51. package/transport/adapters/transport.local.adapter.d.ts.map +1 -1
  52. package/transport/mcp-20260728/dispatcher.d.ts +3 -2
  53. package/transport/mcp-20260728/dispatcher.d.ts.map +1 -1
  54. package/transport/mcp-handlers/mcp-handlers.types.d.ts +9 -9
  55. package/transport/mcp-handlers/mcp-handlers.types.d.ts.map +1 -1
  56. package/transport/mcp-handlers/skills-list-request.handler.d.ts.map +1 -1
  57. package/transport/mcp-handlers/skills-load-request.handler.d.ts.map +1 -1
  58. package/transport/mcp-handlers/skills-search-request.handler.d.ts.map +1 -1
  59. package/utils/lineage.utils.d.ts +11 -0
  60. package/utils/lineage.utils.d.ts.map +1 -1
package/index.js CHANGED
@@ -3167,7 +3167,8 @@ var init_front_mcp_metadata = __esm({
3167
3167
  extApps: extAppsOptionsSchema.optional(),
3168
3168
  sqlite: sqliteOptionsSchema.optional(),
3169
3169
  ui: import_lazy_zod25.z.object({
3170
- cdnOverrides: import_lazy_zod25.z.record(import_lazy_zod25.z.string(), import_lazy_zod25.z.string()).optional()
3170
+ cdnOverrides: import_lazy_zod25.z.record(import_lazy_zod25.z.string(), import_lazy_zod25.z.string()).optional(),
3171
+ escapeStringResults: import_lazy_zod25.z.boolean().optional()
3171
3172
  }).optional(),
3172
3173
  /**
3173
3174
  * Output-validation policy applied after entry-level Zod parsing succeeds.
@@ -9588,7 +9589,7 @@ function initializeRequestHandler({
9588
9589
  const requestedVersion = request.params.protocolVersion;
9589
9590
  const protocolVersion = import_protocol15.SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : import_protocol15.LATEST_PROTOCOL_VERSION;
9590
9591
  const configuredInfo = scope.metadata?.info ?? { name: "FrontMcpServer", version: "0.0.1" };
9591
- const composed = composeInstructions?.();
9592
+ const composed = await composeInstructions?.(ctx);
9592
9593
  const instructions = composed !== void 0 ? composed : serverOptions.instructions;
9593
9594
  const result = {
9594
9595
  capabilities: serverOptions.capabilities ?? {},
@@ -9901,25 +9902,6 @@ async function filterSkillsByAuthorities(scope, skills, authInfo) {
9901
9902
  );
9902
9903
  return skills.filter((_, i) => grants[i]);
9903
9904
  }
9904
- async function filterSkillMetadataByAuthorities(scope, registry, results, authInfo) {
9905
- const engine = scope.authoritiesEngine;
9906
- const ctxBuilder = scope.authoritiesContextBuilder;
9907
- if (!engine || !ctxBuilder) return [...results];
9908
- const normalized = normalizeAuthInfoForAuthorities(authInfo);
9909
- const grants = await Promise.all(
9910
- results.map(async (r) => {
9911
- const id = r.metadata.id ?? r.metadata.name;
9912
- const entry = registry.findByName(id) ?? registry.getSkills(true).find((s) => (s.metadata.id ?? s.name) === id || s.metadata.name === id);
9913
- if (!entry) return true;
9914
- const authorities = getSkillAuthorities(entry);
9915
- if (!authorities) return true;
9916
- const evalCtx = ctxBuilder.build(normalized);
9917
- const result = await engine.evaluate(authorities, evalCtx);
9918
- return result.granted;
9919
- })
9920
- );
9921
- return results.filter((_, i) => grants[i]);
9922
- }
9923
9905
  var import_auth16;
9924
9906
  var init_skill_authorities_helper = __esm({
9925
9907
  "libs/sdk/src/skill/skill-authorities.helper.ts"() {
@@ -9928,6 +9910,43 @@ var init_skill_authorities_helper = __esm({
9928
9910
  }
9929
9911
  });
9930
9912
 
9913
+ // libs/sdk/src/skill/skill-entry.resolver.ts
9914
+ function skillResultId(result) {
9915
+ return result.metadata.id ?? result.metadata.name;
9916
+ }
9917
+ function createSkillEntryResolver(registry) {
9918
+ let fallback;
9919
+ const fallbackEntry = (id) => {
9920
+ if (!fallback) {
9921
+ const skills = registry.getSkills(true);
9922
+ fallback = /* @__PURE__ */ new Map();
9923
+ for (const skill of skills) {
9924
+ const skillId = skill.metadata.id ?? skill.name;
9925
+ if (!fallback.has(skillId)) fallback.set(skillId, skill);
9926
+ }
9927
+ for (const skill of skills) {
9928
+ if (!fallback.has(skill.metadata.name)) fallback.set(skill.metadata.name, skill);
9929
+ }
9930
+ }
9931
+ return fallback.get(id);
9932
+ };
9933
+ const lookup = (id) => registry.findByName(id) ?? // Qualified names always carry an owner prefix, so plain ids skip that scan.
9934
+ (id.includes(":") ? registry.findByQualifiedName(id) : void 0) ?? fallbackEntry(id);
9935
+ return (...ids) => {
9936
+ for (const id of ids) {
9937
+ if (!id) continue;
9938
+ const entry = lookup(id);
9939
+ if (entry) return entry;
9940
+ }
9941
+ return void 0;
9942
+ };
9943
+ }
9944
+ var init_skill_entry_resolver = __esm({
9945
+ "libs/sdk/src/skill/skill-entry.resolver.ts"() {
9946
+ "use strict";
9947
+ }
9948
+ });
9949
+
9931
9950
  // libs/sdk/src/skill/skill-filter.helper.ts
9932
9951
  async function filterServableSkills(scope, skills, ctx) {
9933
9952
  if (skills.length === 0) return [];
@@ -9939,21 +9958,22 @@ async function isSkillServable(scope, skill, ctx) {
9939
9958
  const servable = await filterServableSkills(scope, [skill], ctx);
9940
9959
  return servable.length === 1;
9941
9960
  }
9942
- async function filterServableSkillResults(scope, registry, results, ctx) {
9943
- const entries = results.map((result) => findSkillEntry(registry, result.metadata.id ?? result.metadata.name));
9944
- const registered = entries.filter((entry) => entry !== void 0);
9945
- const servable = new Set(await filterServableSkills(scope, registered, ctx));
9961
+ async function filterDiscoverableSkillResults(scope, registry, results, caller = {}) {
9962
+ const resolve = createSkillEntryResolver(registry);
9963
+ const entries = results.map((result) => resolve(skillResultId(result)));
9964
+ const registered = [...new Set(entries.filter((entry) => entry !== void 0))];
9965
+ const authorized = await filterSkillsByAuthorities(scope, registered, caller.authInfo ?? {});
9966
+ const servable = new Set(await filterServableSkills(scope, authorized, caller.ctx));
9946
9967
  return results.filter((_, index) => {
9947
9968
  const entry = entries[index];
9948
9969
  return entry === void 0 || servable.has(entry);
9949
9970
  });
9950
9971
  }
9951
- function findSkillEntry(registry, id) {
9952
- return registry.findByName(id) ?? registry.getSkills(true).find((skill) => (skill.metadata.id ?? skill.name) === id || skill.metadata.name === id);
9953
- }
9954
9972
  var init_skill_filter_helper = __esm({
9955
9973
  "libs/sdk/src/skill/skill-filter.helper.ts"() {
9956
9974
  "use strict";
9975
+ init_skill_authorities_helper();
9976
+ init_skill_entry_resolver();
9957
9977
  }
9958
9978
  });
9959
9979
 
@@ -9983,8 +10003,7 @@ function skillsListRequestHandler({
9983
10003
  });
9984
10004
  const authInfo = ctx?.authInfo ?? {};
9985
10005
  const wrapped = listResult.skills.map((metadata) => ({ metadata }));
9986
- const authVisible = await filterSkillMetadataByAuthorities(scope, skillRegistry, wrapped, authInfo);
9987
- const visible = await filterServableSkillResults(scope, skillRegistry, authVisible, ctx);
10006
+ const visible = await filterDiscoverableSkillResults(scope, skillRegistry, wrapped, { authInfo, ctx });
9988
10007
  const removed = listResult.skills.length - visible.length;
9989
10008
  const skills = visible.map(({ metadata: s }) => ({
9990
10009
  id: s.id ?? s.name,
@@ -10008,7 +10027,6 @@ var init_skills_list_request_handler = __esm({
10008
10027
  "libs/sdk/src/transport/mcp-handlers/skills-list-request.handler.ts"() {
10009
10028
  "use strict";
10010
10029
  init_errors();
10011
- init_skill_authorities_helper();
10012
10030
  init_skill_filter_helper();
10013
10031
  init_skills_mcp_types();
10014
10032
  }
@@ -10419,10 +10437,10 @@ async function loadInstructions(source, basePath) {
10419
10437
  }
10420
10438
  throw new InvalidInstructionSourceError();
10421
10439
  }
10422
- function buildSkillContent(metadata, instructions, resolvedReferences, resolvedExamples) {
10440
+ function buildSkillContent(metadata, instructions, resolvedReferences2, resolvedExamples) {
10423
10441
  let finalInstructions = instructions;
10424
- if (resolvedReferences && resolvedReferences.length > 0) {
10425
- finalInstructions += buildReferencesTable(resolvedReferences);
10442
+ if (resolvedReferences2 && resolvedReferences2.length > 0) {
10443
+ finalInstructions += buildReferencesTable(resolvedReferences2);
10426
10444
  }
10427
10445
  if (resolvedExamples && resolvedExamples.length > 0) {
10428
10446
  finalInstructions += buildExamplesTable(resolvedExamples);
@@ -10440,7 +10458,7 @@ function buildSkillContent(metadata, instructions, resolvedReferences, resolvedE
10440
10458
  specMetadata: metadata.specMetadata,
10441
10459
  allowedTools: metadata.allowedTools,
10442
10460
  resources: metadata.resources,
10443
- resolvedReferences,
10461
+ resolvedReferences: resolvedReferences2,
10444
10462
  resolvedExamples
10445
10463
  };
10446
10464
  }
@@ -10710,13 +10728,14 @@ function skillsLoadRequestHandler({
10710
10728
  toolsByName.set(tool.name, tool);
10711
10729
  }
10712
10730
  }
10731
+ const resolveEntry = createSkillEntryResolver(skillRegistry);
10713
10732
  for (const skillId of skillIds) {
10714
10733
  const loadResult = await skillRegistry.loadSkill(skillId);
10715
10734
  if (!loadResult) {
10716
10735
  warnings.push(`Skill "${skillId}" not found`);
10717
10736
  continue;
10718
10737
  }
10719
- const entry = skillRegistry.findByName(skillId) ?? skillRegistry.findByQualifiedName(skillId) ?? skillRegistry.findByName(loadResult.skill.id) ?? skillRegistry.getSkills(true).find((s) => (s.metadata.id ?? s.name) === loadResult.skill.id || s.metadata.name === loadResult.skill.id);
10738
+ const entry = resolveEntry(skillId, loadResult.skill.id);
10720
10739
  if (entry) {
10721
10740
  if (!await isSkillServable(scope, entry, ctx)) {
10722
10741
  warnings.push(`Skill "${skillId}" not found`);
@@ -10795,6 +10814,7 @@ var init_skills_load_request_handler = __esm({
10795
10814
  "use strict";
10796
10815
  init_errors();
10797
10816
  init_skill_authorities_helper();
10817
+ init_skill_entry_resolver();
10798
10818
  init_skill_filter_helper();
10799
10819
  init_skill_http_utils();
10800
10820
  init_skill_utils();
@@ -10829,13 +10849,10 @@ function skillsSearchRequestHandler({
10829
10849
  return visibility === "mcp" || visibility === "both";
10830
10850
  });
10831
10851
  const authInfo = ctx?.authInfo ?? {};
10832
- const authVisibleResults = await filterSkillMetadataByAuthorities(
10833
- scope,
10834
- skillRegistry,
10835
- mcpVisibleResults,
10836
- authInfo
10837
- );
10838
- const servableResults = await filterServableSkillResults(scope, skillRegistry, authVisibleResults, ctx);
10852
+ const servableResults = await filterDiscoverableSkillResults(scope, skillRegistry, mcpVisibleResults, {
10853
+ authInfo,
10854
+ ctx
10855
+ });
10839
10856
  const skills = servableResults.map((r) => {
10840
10857
  const toolNames = extractToolNames(r.metadata);
10841
10858
  return {
@@ -10869,7 +10886,6 @@ var init_skills_search_request_handler = __esm({
10869
10886
  "use strict";
10870
10887
  init_skill_metadata();
10871
10888
  init_errors();
10872
- init_skill_authorities_helper();
10873
10889
  init_skill_filter_helper();
10874
10890
  init_skills_mcp_types();
10875
10891
  }
@@ -13063,6 +13079,15 @@ var init_metrics2 = __esm({
13063
13079
  }
13064
13080
  });
13065
13081
 
13082
+ // libs/sdk/src/transport/transport.types.ts
13083
+ var STATELESS_SESSION_ID;
13084
+ var init_transport_types = __esm({
13085
+ "libs/sdk/src/transport/transport.types.ts"() {
13086
+ "use strict";
13087
+ STATELESS_SESSION_ID = "__stateless__";
13088
+ }
13089
+ });
13090
+
13066
13091
  // libs/sdk/src/context/trace-context.ts
13067
13092
  function parseTraceContext(headers) {
13068
13093
  const traceparent = getHeader(headers, "traceparent");
@@ -13179,6 +13204,7 @@ var init_frontmcp_context = __esm({
13179
13204
  import_auth17 = require("@frontmcp/auth");
13180
13205
  import_utils30 = require("@frontmcp/utils");
13181
13206
  init_mcp_error();
13207
+ init_transport_types();
13182
13208
  init_trace_context();
13183
13209
  PRE_RESOLVED_ELICIT_KEY = /* @__PURE__ */ Symbol.for("frontmcp:pre-resolved-elicit");
13184
13210
  MRTR_EXCHANGE_KEY = /* @__PURE__ */ Symbol.for("frontmcp:mrtr-exchange");
@@ -13280,6 +13306,12 @@ var init_frontmcp_context = __esm({
13280
13306
  updateAuthInfo(authInfo) {
13281
13307
  this._authInfo = { ...this._authInfo, ...authInfo };
13282
13308
  }
13309
+ /** `sessionId` when the server verified it; undefined for stateless and per-request placeholder ids. */
13310
+ get verifiedSessionId() {
13311
+ if (this.sessionId === STATELESS_SESSION_ID) return void 0;
13312
+ const verified = this._authInfo.sessionId ?? this._authInfo.extra?.["sessionId"];
13313
+ return verified === this.sessionId ? this.sessionId : void 0;
13314
+ }
13283
13315
  /**
13284
13316
  * The client's self-reported identity, sent with this request (MCP 2026-07-28 `_meta`).
13285
13317
  * Session-based clients report it once at initialize instead; see the notification service.
@@ -17446,9 +17478,24 @@ function appOwnerIdOf(lineage, owner) {
17446
17478
  const owners = owner ? [...lineage, owner] : lineage;
17447
17479
  return owners.find((candidate) => candidate.kind === "app")?.id;
17448
17480
  }
17481
+ var EntryLineageIndex;
17449
17482
  var init_lineage_utils = __esm({
17450
17483
  "libs/sdk/src/utils/lineage.utils.ts"() {
17451
17484
  "use strict";
17485
+ EntryLineageIndex = class {
17486
+ lineages = /* @__PURE__ */ new Map();
17487
+ /** Replace the index with these rows; an entry held by several rows keeps the first row's lineage. */
17488
+ rebuild(rows) {
17489
+ this.lineages.clear();
17490
+ for (const row of rows) {
17491
+ if (!this.lineages.has(row.instance)) this.lineages.set(row.instance, row.lineage);
17492
+ }
17493
+ }
17494
+ /** Owner lineage (root → leaf) of an entry, or undefined when no row holds it. */
17495
+ lineageOf(entry) {
17496
+ return this.lineages.get(entry);
17497
+ }
17498
+ };
17452
17499
  }
17453
17500
  });
17454
17501
 
@@ -17481,6 +17528,28 @@ var init_remote_capabilities_utils = __esm({
17481
17528
  }
17482
17529
  });
17483
17530
 
17531
+ // libs/sdk/src/flows/resolved-entries.ts
17532
+ var ResolvedEntries;
17533
+ var init_resolved_entries = __esm({
17534
+ "libs/sdk/src/flows/resolved-entries.ts"() {
17535
+ "use strict";
17536
+ ResolvedEntries = class {
17537
+ byInput = /* @__PURE__ */ new WeakMap();
17538
+ /** Keep the entry resolved for this run's raw input and lookup key. */
17539
+ remember(rawInput, key, entry) {
17540
+ if (typeof rawInput === "object" && rawInput !== null) this.byInput.set(rawInput, { key, entry });
17541
+ }
17542
+ /** The entry kept for this run when it was resolved from the same key; undefined otherwise. */
17543
+ take(rawInput, key) {
17544
+ if (typeof rawInput !== "object" || rawInput === null) return void 0;
17545
+ const resolved = this.byInput.get(rawInput);
17546
+ this.byInput.delete(rawInput);
17547
+ return resolved?.key === key ? resolved.entry : void 0;
17548
+ }
17549
+ };
17550
+ }
17551
+ });
17552
+
17484
17553
  // libs/sdk/src/provider/flow-context-providers.ts
17485
17554
  var FlowContextProviders;
17486
17555
  var init_flow_context_providers = __esm({
@@ -17516,7 +17585,7 @@ var init_flow_context_providers = __esm({
17516
17585
  });
17517
17586
 
17518
17587
  // libs/sdk/src/prompt/flows/get-prompt.flow.ts
17519
- var import_auth18, import_lazy_zod49, import_protocol31, inputSchema5, outputSchema5, stateSchema5, plan5, name5, Stage5, GetPromptFlow;
17588
+ var import_auth18, import_lazy_zod49, import_protocol31, inputSchema5, outputSchema5, stateSchema5, plan5, name5, Stage5, resolvedPrompts, GetPromptFlow;
17520
17589
  var init_get_prompt_flow = __esm({
17521
17590
  "libs/sdk/src/prompt/flows/get-prompt.flow.ts"() {
17522
17591
  "use strict";
@@ -17526,6 +17595,7 @@ var init_get_prompt_flow = __esm({
17526
17595
  init_remote_capabilities_utils();
17527
17596
  init_common();
17528
17597
  init_errors();
17598
+ init_resolved_entries();
17529
17599
  init_hooks_utils();
17530
17600
  init_flow_context_providers();
17531
17601
  init_lineage_utils();
@@ -17561,17 +17631,19 @@ var init_get_prompt_flow = __esm({
17561
17631
  };
17562
17632
  name5 = "prompts:get-prompt";
17563
17633
  ({ Stage: Stage5 } = FlowHooksOf(name5));
17634
+ resolvedPrompts = new ResolvedEntries();
17564
17635
  GetPromptFlow = class extends FlowBase {
17565
17636
  static async resolveHookOwnerId(rawInput, scope) {
17566
- const parsed = inputSchema5.safeParse(rawInput);
17567
- if (!parsed.success) return void 0;
17568
- const findPrompt = () => scope.prompts.findByName(parsed.data.request.params.name);
17569
- let prompt = findPrompt();
17637
+ const promptName = rawInput?.request?.params?.name;
17638
+ if (typeof promptName !== "string") return void 0;
17639
+ let prompt = scope.prompts.findByName(promptName);
17570
17640
  if (!prompt) {
17571
17641
  await loadRemoteAppCapabilities(scope);
17572
- prompt = findPrompt();
17642
+ prompt = scope.prompts.findByName(promptName);
17573
17643
  }
17574
- return prompt ? appOwnerIdOf(scope.prompts.lineageOf(prompt) ?? [], prompt.owner) : void 0;
17644
+ if (!prompt) return void 0;
17645
+ resolvedPrompts.remember(rawInput, promptName, prompt);
17646
+ return appOwnerIdOf(scope.prompts.lineageOf(prompt) ?? [], prompt.owner);
17575
17647
  }
17576
17648
  logger = this.scopeLogger.child("GetPromptFlow");
17577
17649
  async parseInput() {
@@ -17635,7 +17707,7 @@ var init_get_prompt_flow = __esm({
17635
17707
  this.logger.verbose("findPrompt:start");
17636
17708
  const { name: name44 } = this.state.required.input;
17637
17709
  this.logger.info(`findPrompt: looking for prompt with name "${name44}"`);
17638
- const prompt = this.scope.prompts.findByName(name44);
17710
+ const prompt = resolvedPrompts.take(this.rawInput, name44) ?? this.scope.prompts.findByName(name44);
17639
17711
  if (!prompt) {
17640
17712
  this.logger.warn(`findPrompt: prompt "${name44}" not found`);
17641
17713
  throw new PromptNotFoundError(name44);
@@ -17691,14 +17763,8 @@ var init_get_prompt_flow = __esm({
17691
17763
  const parsedArgs = prompt.parseArguments(input.arguments);
17692
17764
  this.state.set("parsedArgs", parsedArgs);
17693
17765
  const sessionKey = authInfo?.sessionId ?? "anonymous";
17694
- const promptViews = await prompt.providers.buildViews(sessionKey, new Map(this.deps));
17695
- const mergedContextDeps = new Map(this.deps);
17696
- for (const [token, instance] of promptViews.context) {
17697
- if (!mergedContextDeps.has(token)) {
17698
- mergedContextDeps.set(token, instance);
17699
- }
17700
- }
17701
- const contextProviders = new FlowContextProviders(prompt.providers, mergedContextDeps);
17766
+ const promptViews = await prompt.providers.buildViews(sessionKey, new Map(this.deps), this.scope.providers);
17767
+ const contextProviders = new FlowContextProviders(prompt.providers, promptViews.context);
17702
17768
  const context = prompt.create(parsedArgs, { ...ctx, contextProviders });
17703
17769
  this.appendContextHooks(hooksBoundTo(this.scope.hooks.getClsHooks(prompt.record.provide), context));
17704
17770
  context.mark("createPromptContext");
@@ -18320,6 +18386,8 @@ var init_prompt_registry = __esm({
18320
18386
  // "ownerKey:name" -> row
18321
18387
  byOwner = /* @__PURE__ */ new Map();
18322
18388
  // ownerKey -> rows
18389
+ lineages = new EntryLineageIndex();
18390
+ // instance -> first row's lineage
18323
18391
  // version + emitter
18324
18392
  version = 0;
18325
18393
  emitter = new PromptEmitter();
@@ -18503,7 +18571,7 @@ var init_prompt_registry = __esm({
18503
18571
  }
18504
18572
  /** Owner lineage (root → leaf) of a prompt this registry holds, or undefined when it holds none. */
18505
18573
  lineageOf(entry) {
18506
- return this.listAllIndexed().find((row) => row.instance === entry)?.lineage;
18574
+ return this.lineages.lineageOf(entry);
18507
18575
  }
18508
18576
  /** List instances by owner path (e.g. "app:Portal/plugin:Okta") */
18509
18577
  listByOwner(ownerPath) {
@@ -18516,6 +18584,7 @@ var init_prompt_registry = __esm({
18516
18584
  this.byName.clear();
18517
18585
  this.byOwnerAndName.clear();
18518
18586
  this.byOwner.clear();
18587
+ this.lineages.rebuild(effective);
18519
18588
  for (const r of effective) {
18520
18589
  this.byQualifiedId.set(r.qualifiedId, r);
18521
18590
  const listByName = this.byName.get(r.baseName) ?? [];
@@ -18842,8 +18911,18 @@ var init_ui_shared = __esm({
18842
18911
  manifests = /* @__PURE__ */ new Map();
18843
18912
  resourceMeta = /* @__PURE__ */ new Map();
18844
18913
  resolver;
18845
- constructor(resolver) {
18914
+ options;
18915
+ constructor(resolver, options = {}) {
18846
18916
  this.resolver = resolver;
18917
+ this.options = options;
18918
+ }
18919
+ /** Tool-level `ui.escapeStringResults` wins over the server-wide default. */
18920
+ stringResultOptions(uiConfig) {
18921
+ const toolSetting = uiConfig?.["escapeStringResults"];
18922
+ return {
18923
+ escapeStringResults: typeof toolSetting === "boolean" ? toolSetting : this.options.escapeStringResults,
18924
+ logger: this.options.logger
18925
+ };
18847
18926
  }
18848
18927
  getStaticWidget(name44) {
18849
18928
  return this.widgets.get(name44);
@@ -18882,7 +18961,8 @@ var init_ui_shared = __esm({
18882
18961
  template,
18883
18962
  resolver: this.resolver,
18884
18963
  resourceMode,
18885
- sizing: extractSizing(uiConfig)
18964
+ sizing: extractSizing(uiConfig),
18965
+ ...this.stringResultOptions(uiConfig)
18886
18966
  });
18887
18967
  this.widgets.set(toolName, result.html);
18888
18968
  this.manifests.set(toolName, {
@@ -18959,7 +19039,8 @@ var init_ui_shared = __esm({
18959
19039
  platformType,
18960
19040
  resolver: this.resolver,
18961
19041
  resourceMode,
18962
- sizing: extractSizing(uiConfig)
19042
+ sizing: extractSizing(uiConfig),
19043
+ ...this.stringResultOptions(uiConfig)
18963
19044
  });
18964
19045
  return { meta: result.meta };
18965
19046
  }
@@ -19218,7 +19299,7 @@ var init_ui = __esm({
19218
19299
  });
19219
19300
 
19220
19301
  // libs/sdk/src/resource/flows/read-resource.flow.ts
19221
- var import_auth19, import_lazy_zod51, import_protocol34, import_utils46, inputSchema7, outputSchema7, stateSchema7, plan7, name7, Stage7, ReadResourceFlow;
19302
+ var import_auth19, import_lazy_zod51, import_protocol34, import_utils46, inputSchema7, outputSchema7, stateSchema7, plan7, name7, Stage7, resolvedResources, ReadResourceFlow;
19222
19303
  var init_read_resource_flow = __esm({
19223
19304
  "libs/sdk/src/resource/flows/read-resource.flow.ts"() {
19224
19305
  "use strict";
@@ -19229,6 +19310,7 @@ var init_read_resource_flow = __esm({
19229
19310
  init_remote_capabilities_utils();
19230
19311
  init_common();
19231
19312
  init_errors();
19313
+ init_resolved_entries();
19232
19314
  init_hooks_utils();
19233
19315
  init_flow_context_providers();
19234
19316
  init_ui();
@@ -19270,17 +19352,19 @@ var init_read_resource_flow = __esm({
19270
19352
  };
19271
19353
  name7 = "resources:read-resource";
19272
19354
  ({ Stage: Stage7 } = FlowHooksOf(name7));
19355
+ resolvedResources = new ResolvedEntries();
19273
19356
  ReadResourceFlow = class extends FlowBase {
19274
19357
  static async resolveHookOwnerId(rawInput, scope) {
19275
- const parsed = inputSchema7.safeParse(rawInput);
19276
- if (!parsed.success) return void 0;
19277
- const findResource = () => scope.resources.findResourceForUri(parsed.data.request.params.uri)?.instance;
19278
- let resource = findResource();
19279
- if (!resource) {
19358
+ const uri = rawInput?.request?.params?.uri;
19359
+ if (typeof uri !== "string") return void 0;
19360
+ let match = scope.resources.findResourceForUri(uri);
19361
+ if (!match) {
19280
19362
  await loadRemoteAppCapabilities(scope);
19281
- resource = findResource();
19363
+ match = scope.resources.findResourceForUri(uri);
19282
19364
  }
19283
- return resource ? appOwnerIdOf(scope.resources.lineageOf(resource) ?? [], resource.owner) : void 0;
19365
+ if (!match) return void 0;
19366
+ resolvedResources.remember(rawInput, uri, match);
19367
+ return appOwnerIdOf(scope.resources.lineageOf(match.instance) ?? [], match.instance.owner);
19284
19368
  }
19285
19369
  logger = this.scopeLogger.child("ReadResourceFlow");
19286
19370
  async parseInput() {
@@ -19365,7 +19449,7 @@ var init_read_resource_flow = __esm({
19365
19449
  return;
19366
19450
  }
19367
19451
  }
19368
- const match = this.scope.resources.findResourceForUri(uri);
19452
+ const match = resolvedResources.take(this.rawInput, uri) ?? this.scope.resources.findResourceForUri(uri);
19369
19453
  if (!match) {
19370
19454
  this.logger.warn(`findResource: resource for URI "${uri}" not found`);
19371
19455
  throw new ResourceNotFoundError(uri);
@@ -19425,14 +19509,8 @@ var init_read_resource_flow = __esm({
19425
19509
  const { resource, input, params } = this.state.required;
19426
19510
  try {
19427
19511
  const sessionKey = this.state.sessionId ?? ctx.authInfo?.sessionId ?? `req-${Date.now()}-${Buffer.from((0, import_utils46.randomBytes)(16)).toString("hex")}`;
19428
- const resourceViews = await resource.providers.buildViews(sessionKey, new Map(this.deps));
19429
- const mergedContextDeps = new Map(this.deps);
19430
- for (const [token, instance] of resourceViews.context) {
19431
- if (!mergedContextDeps.has(token)) {
19432
- mergedContextDeps.set(token, instance);
19433
- }
19434
- }
19435
- const contextProviders = new FlowContextProviders(resource.providers, mergedContextDeps);
19512
+ const resourceViews = await resource.providers.buildViews(sessionKey, new Map(this.deps), this.scope.providers);
19513
+ const contextProviders = new FlowContextProviders(resource.providers, resourceViews.context);
19436
19514
  const context = resource.create(input.uri, params, { ...ctx, contextProviders });
19437
19515
  this.appendContextHooks(hooksBoundTo(this.scope.hooks.getClsHooks(resource.record.provide), context));
19438
19516
  context.mark("createResourceContext");
@@ -20679,6 +20757,8 @@ var init_resource_registry = __esm({
20679
20757
  // "ownerKey:name" -> row
20680
20758
  byOwner = /* @__PURE__ */ new Map();
20681
20759
  // ownerKey -> rows
20760
+ lineages = new EntryLineageIndex();
20761
+ // instance -> first row's lineage
20682
20762
  // version + emitter
20683
20763
  version = 0;
20684
20764
  emitter = new ResourceEmitter();
@@ -20891,7 +20971,7 @@ var init_resource_registry = __esm({
20891
20971
  }
20892
20972
  /** Owner lineage (root → leaf) of a resource this registry holds, or undefined when it holds none. */
20893
20973
  lineageOf(entry) {
20894
- return this.listAllIndexed().find((row) => row.instance === entry)?.lineage;
20974
+ return this.lineages.lineageOf(entry);
20895
20975
  }
20896
20976
  /** List instances by owner path (e.g. "app:Portal/plugin:Okta") */
20897
20977
  listByOwner(ownerPath) {
@@ -20906,6 +20986,7 @@ var init_resource_registry = __esm({
20906
20986
  this.byUriTemplate.clear();
20907
20987
  this.byOwnerAndName.clear();
20908
20988
  this.byOwner.clear();
20989
+ this.lineages.rebuild(effective);
20909
20990
  for (const r of effective) {
20910
20991
  this.byQualifiedId.set(r.qualifiedId, r);
20911
20992
  const listByName = this.byName.get(r.baseName) ?? [];
@@ -21498,7 +21579,7 @@ function linkedAbortController(signal) {
21498
21579
  else signal?.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
21499
21580
  return controller;
21500
21581
  }
21501
- var import_auth23, import_guard5, import_lazy_zod57, import_protocol39, import_adapters4, import_utils49, inputSchema13, outputSchema12, stateSchema12, plan12, name12, Stage12, CallToolFlow;
21582
+ var import_auth23, import_guard5, import_lazy_zod57, import_protocol39, import_adapters4, import_utils49, inputSchema13, outputSchema12, stateSchema12, plan12, name12, Stage12, resolvedTools, CallToolFlow;
21502
21583
  var init_call_tool_flow = __esm({
21503
21584
  "libs/sdk/src/tool/flows/call-tool.flow.ts"() {
21504
21585
  "use strict";
@@ -21515,6 +21596,7 @@ var init_call_tool_flow = __esm({
21515
21596
  init_tool_metadata();
21516
21597
  init_helpers();
21517
21598
  init_errors();
21599
+ init_resolved_entries();
21518
21600
  init_hooks_utils();
21519
21601
  init_flow_context_providers();
21520
21602
  init_task_id();
@@ -21589,6 +21671,7 @@ var init_call_tool_flow = __esm({
21589
21671
  };
21590
21672
  name12 = "tools:call-tool";
21591
21673
  ({ Stage: Stage12 } = FlowHooksOf(name12));
21674
+ resolvedTools = new ResolvedEntries();
21592
21675
  CallToolFlow = class extends FlowBase {
21593
21676
  static async resolveHookOwnerId(rawInput, scope) {
21594
21677
  const toolName = rawInput?.request?.params?.name;
@@ -21598,7 +21681,9 @@ var init_call_tool_flow = __esm({
21598
21681
  await loadRemoteAppCapabilities(scope);
21599
21682
  tool = lookupTool(scope, toolName);
21600
21683
  }
21601
- return tool ? hookOwnerIdOf(scope.tools.lineageOf(tool) ?? [], tool.owner) : void 0;
21684
+ if (!tool) return void 0;
21685
+ resolvedTools.remember(rawInput, toolName, tool);
21686
+ return hookOwnerIdOf(scope.tools.lineageOf(tool) ?? [], tool.owner);
21602
21687
  }
21603
21688
  logger = this.scopeLogger.child("CallToolFlow");
21604
21689
  async parseInput() {
@@ -21641,7 +21726,7 @@ var init_call_tool_flow = __esm({
21641
21726
  async findTool() {
21642
21727
  this.logger.verbose("findTool:start");
21643
21728
  const { name: name44 } = this.state.required.input;
21644
- const tool = lookupTool(this.scope, name44);
21729
+ const tool = resolvedTools.take(this.rawInput, name44) ?? lookupTool(this.scope, name44);
21645
21730
  if (tool && tool.fullName !== name44 && tool.name !== name44) {
21646
21731
  const [, alias] = toolNameCandidates(name44);
21647
21732
  this.logger.warn(
@@ -21944,14 +22029,8 @@ var init_call_tool_flow = __esm({
21944
22029
  const progressToken = this.state.progressToken;
21945
22030
  try {
21946
22031
  const sessionKey = authInfo?.sessionId ?? "anonymous";
21947
- const toolViews = await tool.providers.buildViews(sessionKey, new Map(this.deps));
21948
- const mergedContextDeps = new Map(this.deps);
21949
- for (const [token, instance] of toolViews.context) {
21950
- if (!mergedContextDeps.has(token)) {
21951
- mergedContextDeps.set(token, instance);
21952
- }
21953
- }
21954
- const contextProviders = new FlowContextProviders(tool.providers, mergedContextDeps);
22032
+ const toolViews = await tool.providers.buildViews(sessionKey, new Map(this.deps), this.scope.providers);
22033
+ const contextProviders = new FlowContextProviders(tool.providers, toolViews.context);
21955
22034
  const executionAbort = linkedAbortController(ctx.signal);
21956
22035
  this.state.set("executionAbort", executionAbort);
21957
22036
  const context = tool.create(input.arguments, {
@@ -23022,8 +23101,8 @@ var init_tool_registry = __esm({
23022
23101
  // "providerId:name" -> row (best-effort)
23023
23102
  byOwner = /* @__PURE__ */ new Map();
23024
23103
  // ownerKey -> rows
23025
- byInstance = /* @__PURE__ */ new Map();
23026
- // instance -> first row
23104
+ lineages = new EntryLineageIndex();
23105
+ // instance -> first row's lineage
23027
23106
  // version + emitter
23028
23107
  version = 0;
23029
23108
  emitter = new ToolEmitter();
@@ -23243,10 +23322,9 @@ var init_tool_registry = __esm({
23243
23322
  this.byOwnerAndName.clear();
23244
23323
  this.byProviderAndName.clear();
23245
23324
  this.byOwner.clear();
23246
- this.byInstance.clear();
23325
+ this.lineages.rebuild(effective);
23247
23326
  for (const r of effective) {
23248
23327
  this.byQualifiedId.set(r.qualifiedId, r);
23249
- if (!this.byInstance.has(r.instance)) this.byInstance.set(r.instance, r);
23250
23328
  const listByName = this.byName.get(r.baseName) ?? [];
23251
23329
  listByName.push(r);
23252
23330
  this.byName.set(r.baseName, listByName);
@@ -23268,7 +23346,7 @@ var init_tool_registry = __esm({
23268
23346
  }
23269
23347
  /** Owner lineage (root → leaf) of a tool this registry holds, or undefined when it holds none. */
23270
23348
  lineageOf(entry) {
23271
- return this.byInstance.get(entry)?.lineage;
23349
+ return this.lineages.lineageOf(entry);
23272
23350
  }
23273
23351
  /** List instances by owner path (e.g. "app:Portal/plugin:Okta") */
23274
23352
  listByOwner(ownerPath) {
@@ -28264,6 +28342,10 @@ var init_plugin_registry = __esm({
28264
28342
  const providers = new ProviderRegistry(rec.metadata.providers ?? [], this.providers);
28265
28343
  await providers.ready;
28266
28344
  const providerHooks = normalizeHooksFromProviders(providers);
28345
+ const { pluginInstance, dynamicProviders } = await this.instantiatePlugin(rec, deps);
28346
+ if (dynamicProviders) {
28347
+ await providers.addDynamicProviders(dynamicProviders);
28348
+ }
28267
28349
  const pluginOwner = {
28268
28350
  kind: "plugin",
28269
28351
  id: rec.metadata.name,
@@ -28295,32 +28377,6 @@ var init_plugin_registry = __esm({
28295
28377
  return providers.getProviderInfo(token2.provide);
28296
28378
  });
28297
28379
  this.providers.mergeFromRegistry(providers, exported);
28298
- const depsTokens = [...deps];
28299
- const depsInstances = await Promise.all(depsTokens.map((t) => this.providers.resolveBootstrapDep(t)));
28300
- let pluginInstance;
28301
- let optionDerivedProviders = [];
28302
- if (rec.kind === "CLASS" /* CLASS */) {
28303
- const klass = rec.useClass;
28304
- pluginInstance = new klass(...depsInstances);
28305
- } else if (rec.kind === "CLASS_TOKEN" /* CLASS_TOKEN */) {
28306
- const klass = rec.provide;
28307
- pluginInstance = new klass(...depsInstances);
28308
- } else if (rec.kind === "FACTORY" /* FACTORY */) {
28309
- const factoryDeps = [...rec.inject()];
28310
- const args = [];
28311
- for (const d of factoryDeps) args.push(await this.providers.resolveBootstrapDep(d));
28312
- const produced = rec.useFactory(...args);
28313
- if (isDynamicPluginClass(rec.provide) && !(produced instanceof rec.provide)) {
28314
- pluginInstance = new rec.provide(produced);
28315
- optionDerivedProviders = collectDynamicProviders(rec.provide, produced);
28316
- } else {
28317
- pluginInstance = produced;
28318
- }
28319
- } else if (rec.kind === "VALUE" /* VALUE */) {
28320
- pluginInstance = rec.useValue;
28321
- } else {
28322
- throw new InvalidRegistryKindError("plugin", rec.kind);
28323
- }
28324
28380
  const pluginScope = rec.metadata.scope ?? "app";
28325
28381
  if (this.scopeInfo?.isStandaloneApp && pluginScope === "server") {
28326
28382
  throw new InvalidPluginScopeError(
@@ -28354,9 +28410,7 @@ var init_plugin_registry = __esm({
28354
28410
  if (contextExtensions && contextExtensions.length > 0) {
28355
28411
  installContextExtensions(rec.metadata.name, contextExtensions);
28356
28412
  }
28357
- const dynamicProviders = optionDerivedProviders.length > 0 ? dedupePluginProviders([...optionDerivedProviders, ...rec.providers ?? []]) : rec.providers;
28358
28413
  if (dynamicProviders) {
28359
- await providers.addDynamicProviders(dynamicProviders);
28360
28414
  const normalized = dynamicProviders.map((p) => normalizeProvider(p));
28361
28415
  const singletons = providers.getAllSingletons();
28362
28416
  const exported2 = normalized.map((def) => ({
@@ -28379,6 +28433,39 @@ var init_plugin_registry = __esm({
28379
28433
  );
28380
28434
  }
28381
28435
  }
28436
+ /** Builds the plugin instance and the providers it contributes; a factory's options exist only once it has run. */
28437
+ async instantiatePlugin(rec, deps) {
28438
+ const depsInstances = await Promise.all([...deps].map((t) => this.providers.resolveBootstrapDep(t)));
28439
+ switch (rec.kind) {
28440
+ case "CLASS" /* CLASS */:
28441
+ return {
28442
+ pluginInstance: new rec.useClass(...depsInstances),
28443
+ dynamicProviders: rec.providers
28444
+ };
28445
+ case "CLASS_TOKEN" /* CLASS_TOKEN */:
28446
+ return {
28447
+ pluginInstance: new rec.provide(...depsInstances),
28448
+ dynamicProviders: rec.providers
28449
+ };
28450
+ case "VALUE" /* VALUE */:
28451
+ return { pluginInstance: rec.useValue, dynamicProviders: rec.providers };
28452
+ case "FACTORY" /* FACTORY */: {
28453
+ const args = [];
28454
+ for (const d of rec.inject()) args.push(await this.providers.resolveBootstrapDep(d));
28455
+ const produced = rec.useFactory(...args);
28456
+ if (isDynamicPluginClass(rec.provide) && !(produced instanceof rec.provide)) {
28457
+ const optionDerived = collectDynamicProviders(rec.provide, produced);
28458
+ return {
28459
+ pluginInstance: new rec.provide(produced),
28460
+ dynamicProviders: optionDerived.length > 0 ? dedupePluginProviders([...optionDerived, ...rec.providers ?? []]) : rec.providers
28461
+ };
28462
+ }
28463
+ return { pluginInstance: produced, dynamicProviders: rec.providers };
28464
+ }
28465
+ default:
28466
+ throw new InvalidRegistryKindError("plugin", rec.kind);
28467
+ }
28468
+ }
28382
28469
  };
28383
28470
  }
28384
28471
  });
@@ -31406,12 +31493,13 @@ async function dispatch20260728(options) {
31406
31493
  return outcome.kind === "result" ? { kind: "result", result: decorate(outcome.result) } : outcome;
31407
31494
  }
31408
31495
  if (method === "server/discover") {
31496
+ const instructions = await composeInstructions?.({ authInfo });
31409
31497
  return {
31410
31498
  kind: "result",
31411
- result: decorate(buildDiscoverResult(scope, composeInstructions?.()))
31499
+ result: decorate(buildDiscoverResult(scope, instructions))
31412
31500
  };
31413
31501
  }
31414
- const serverOptions = buildScopedServerOptions(scope, composeInstructions?.() ?? "");
31502
+ const serverOptions = buildScopedServerOptions(scope);
31415
31503
  const handlers = createMcpHandlers({ scope, serverOptions, composeInstructions });
31416
31504
  const handler = handlers.find((entry) => methodOfSchema(entry.requestSchema) === method);
31417
31505
  if (!handler) {
@@ -43545,7 +43633,17 @@ function findCompletionReference(scope, ref) {
43545
43633
  if (ref.type === "ref/prompt") return { prompt: scope.prompts.findByName(ref.name) };
43546
43634
  return { resource: scope.resources.findResourceForUri(ref.uri)?.instance };
43547
43635
  }
43548
- var import_lazy_zod79, import_protocol49, inputSchema29, outputSchema27, PromptRefSchema, ResourceRefSchema, stateSchema27, plan27, name28, Stage28, CompleteFlow;
43636
+ function referenceKeyOf(ref) {
43637
+ return ref.type === "ref/prompt" ? `prompt:${ref.name}` : `resource:${ref.uri}`;
43638
+ }
43639
+ function isWidgetToolNameCompletion(ref, argumentName) {
43640
+ return ref.type === "ref/resource" && ref.uri.startsWith("ui://widget/") && argumentName === "toolName";
43641
+ }
43642
+ function isListedTool(tool, listedNames) {
43643
+ const baseName = tool.metadata.id ?? tool.metadata.name;
43644
+ return listedNames.has(baseName) || listedNames.has(`${tool.owner.id}:${baseName}`);
43645
+ }
43646
+ var import_lazy_zod79, import_protocol49, inputSchema29, outputSchema27, PromptRefSchema, ResourceRefSchema, CompletionRefSchema, stateSchema27, plan27, name28, Stage28, resolvedReferences, MAX_TOOL_LIST_PAGES, CompleteFlow;
43549
43647
  var init_complete_flow = __esm({
43550
43648
  "libs/sdk/src/completion/flows/complete.flow.ts"() {
43551
43649
  "use strict";
@@ -43554,6 +43652,7 @@ var init_complete_flow = __esm({
43554
43652
  init_remote_capabilities_utils();
43555
43653
  init_common();
43556
43654
  init_errors();
43655
+ init_resolved_entries();
43557
43656
  init_ui();
43558
43657
  init_lineage_utils();
43559
43658
  inputSchema29 = import_lazy_zod79.z.object({
@@ -43569,8 +43668,9 @@ var init_complete_flow = __esm({
43569
43668
  type: import_lazy_zod79.z.literal("ref/resource"),
43570
43669
  uri: import_lazy_zod79.z.string()
43571
43670
  });
43671
+ CompletionRefSchema = import_lazy_zod79.z.discriminatedUnion("type", [PromptRefSchema, ResourceRefSchema]);
43572
43672
  stateSchema27 = import_lazy_zod79.z.object({
43573
- ref: import_lazy_zod79.z.discriminatedUnion("type", [PromptRefSchema, ResourceRefSchema]),
43673
+ ref: CompletionRefSchema,
43574
43674
  argument: import_lazy_zod79.z.object({
43575
43675
  name: import_lazy_zod79.z.string(),
43576
43676
  value: import_lazy_zod79.z.string()
@@ -43578,25 +43678,33 @@ var init_complete_flow = __esm({
43578
43678
  // z.any() used because PromptEntry and ResourceEntry are complex abstract class types
43579
43679
  prompt: import_lazy_zod79.z.any().optional(),
43580
43680
  resource: import_lazy_zod79.z.any().optional(),
43681
+ widgetTools: import_lazy_zod79.z.array(import_lazy_zod79.z.instanceof(ToolEntry)).optional(),
43581
43682
  output: outputSchema27
43582
43683
  });
43583
43684
  plan27 = {
43584
- pre: ["parseInput", "findReference"],
43685
+ pre: ["parseInput", "findReference", "findWidgetTools"],
43585
43686
  execute: ["complete"],
43586
43687
  finalize: ["finalize"]
43587
43688
  };
43588
43689
  name28 = "completion:complete";
43589
43690
  ({ Stage: Stage28 } = FlowHooksOf(name28));
43691
+ resolvedReferences = new ResolvedEntries();
43692
+ MAX_TOOL_LIST_PAGES = 1e3;
43590
43693
  CompleteFlow = class extends FlowBase {
43591
43694
  static async resolveHookOwnerId(rawInput, scope) {
43592
- const parsed = inputSchema29.safeParse(rawInput);
43695
+ const parsed = CompletionRefSchema.safeParse(
43696
+ rawInput?.request?.params?.ref
43697
+ );
43593
43698
  if (!parsed.success) return void 0;
43594
- const { ref } = parsed.data.request.params;
43595
- let { prompt, resource } = findCompletionReference(scope, ref);
43596
- if (!prompt && !resource) {
43699
+ const ref = parsed.data;
43700
+ let reference = findCompletionReference(scope, ref);
43701
+ if (!reference.prompt && !reference.resource) {
43597
43702
  await loadRemoteAppCapabilities(scope);
43598
- ({ prompt, resource } = findCompletionReference(scope, ref));
43703
+ reference = findCompletionReference(scope, ref);
43599
43704
  }
43705
+ const { prompt, resource } = reference;
43706
+ if (!prompt && !resource) return void 0;
43707
+ resolvedReferences.remember(rawInput, referenceKeyOf(ref), reference);
43600
43708
  if (prompt) return appOwnerIdOf(scope.prompts.lineageOf(prompt) ?? [], prompt.owner);
43601
43709
  return resource ? appOwnerIdOf(scope.resources.lineageOf(resource) ?? [], resource.owner) : void 0;
43602
43710
  }
@@ -43633,10 +43741,43 @@ var init_complete_flow = __esm({
43633
43741
  }
43634
43742
  async findReference() {
43635
43743
  this.logger.verbose("findReference:start");
43636
- const { prompt, resource } = findCompletionReference(this.scope, this.state.required.ref);
43744
+ const { ref } = this.state.required;
43745
+ const { prompt, resource } = resolvedReferences.take(this.rawInput, referenceKeyOf(ref)) ?? findCompletionReference(this.scope, ref);
43637
43746
  this.state.set({ prompt, resource });
43638
43747
  this.logger.verbose("findReference:done");
43639
43748
  }
43749
+ async findWidgetTools() {
43750
+ const { ref, argument } = this.state.required;
43751
+ if (!isWidgetToolNameCompletion(ref, argument.name)) return;
43752
+ this.logger.verbose("findWidgetTools:start");
43753
+ const uiTools = this.scope.tools.getTools().filter((tool) => hasUIConfig(tool.metadata));
43754
+ const listedNames = uiTools.length > 0 ? await this.listToolNames() : /* @__PURE__ */ new Set();
43755
+ this.state.set(
43756
+ "widgetTools",
43757
+ uiTools.filter((tool) => isListedTool(tool, listedNames))
43758
+ );
43759
+ this.logger.verbose("findWidgetTools:done");
43760
+ }
43761
+ /** Every tool name `tools/list` returns this caller, across all pages; none when listing fails. */
43762
+ async listToolNames() {
43763
+ const names = /* @__PURE__ */ new Set();
43764
+ let cursor;
43765
+ try {
43766
+ for (let page = 0; page < MAX_TOOL_LIST_PAGES; page++) {
43767
+ const { tools, nextCursor } = await this.scope.runFlowForOutput("tools:list-tools", {
43768
+ request: { method: "tools/list", params: cursor ? { cursor } : {} },
43769
+ ctx: this.input.ctx
43770
+ });
43771
+ for (const tool of tools) names.add(tool.name);
43772
+ if (!nextCursor) break;
43773
+ cursor = nextCursor;
43774
+ }
43775
+ } catch (e) {
43776
+ this.logger.warn(`findWidgetTools: tools/list failed, offering no tool names: ${e}`);
43777
+ names.clear();
43778
+ }
43779
+ return names;
43780
+ }
43640
43781
  async complete() {
43641
43782
  this.logger.verbose("complete:start");
43642
43783
  const { ref, argument } = this.state.required;
@@ -43674,9 +43815,8 @@ var init_complete_flow = __esm({
43674
43815
  this.logger.debug(
43675
43816
  `complete: resource completion for URI "${uri}" argument "${argName}" with value "${argValue}"`
43676
43817
  );
43677
- if (uri.startsWith("ui://widget/") && argName === "toolName") {
43678
- const toolsWithUI = this.scope.tools.getTools().filter((t) => hasUIConfig(t.metadata));
43679
- const toolNames = toolsWithUI.map((t) => t.metadata.id ?? t.metadata.name);
43818
+ if (isWidgetToolNameCompletion(ref, argName)) {
43819
+ const toolNames = (this.state.widgetTools ?? []).map((t) => t.metadata.id ?? t.metadata.name);
43680
43820
  const prefix = argValue.toLowerCase();
43681
43821
  values = toolNames.filter((name44) => name44.toLowerCase().startsWith(prefix));
43682
43822
  total = values.length;
@@ -43720,6 +43860,9 @@ var init_complete_flow = __esm({
43720
43860
  __decorateClass([
43721
43861
  Stage28("findReference")
43722
43862
  ], CompleteFlow.prototype, "findReference", 1);
43863
+ __decorateClass([
43864
+ Stage28("findWidgetTools")
43865
+ ], CompleteFlow.prototype, "findWidgetTools", 1);
43723
43866
  __decorateClass([
43724
43867
  Stage28("complete")
43725
43868
  ], CompleteFlow.prototype, "complete", 1);
@@ -49330,7 +49473,6 @@ var init_search_skills_flow = __esm({
49330
49473
  import_lazy_zod95 = require("@frontmcp/lazy-zod");
49331
49474
  init_common();
49332
49475
  init_errors();
49333
- init_skill_authorities_helper();
49334
49476
  init_skill_filter_helper();
49335
49477
  TELEMETRY_ACCESSOR_TOKEN = /* @__PURE__ */ Symbol.for("frontmcp:observability:telemetry-accessor");
49336
49478
  inputSchema33 = import_lazy_zod95.z.object({
@@ -49438,8 +49580,10 @@ var init_search_skills_flow = __esm({
49438
49580
  const visibility = result.metadata.visibility ?? "both";
49439
49581
  return visibility === "mcp" || visibility === "both";
49440
49582
  });
49441
- const authVisibleResults = await this.filterResultsByAuthorities(mcpVisibleResults);
49442
- const servableResults = this.scope.skills ? await filterServableSkillResults(this.scope, this.scope.skills, authVisibleResults) : authVisibleResults;
49583
+ const registry = this.scope.skills;
49584
+ const ctx = this.rawInput["ctx"];
49585
+ const authInfo = ctx?.["authInfo"] ?? {};
49586
+ const servableResults = registry ? await filterDiscoverableSkillResults(this.scope, registry, mcpVisibleResults, { authInfo }) : mcpVisibleResults;
49443
49587
  const skills = servableResults.map((result) => ({
49444
49588
  id: result.metadata.id ?? result.metadata.name,
49445
49589
  name: result.metadata.name,
@@ -49475,25 +49619,6 @@ var init_search_skills_flow = __esm({
49475
49619
  this.respond(output);
49476
49620
  this.logger.verbose("finalize:done");
49477
49621
  }
49478
- /**
49479
- * Remove search results the caller is not authorized to discover.
49480
- *
49481
- * Search-result metadata is projected from `SkillContent` and does NOT carry
49482
- * the `authorities` field, so we resolve the live skill entry (by id/name)
49483
- * to read its declared authorities, then evaluate via the scope's engine.
49484
- * No-op when no authorities engine is configured; results unchanged.
49485
- *
49486
- * Evaluated WITHOUT request input — `fromInput`/ReBAC-by-input policies can't
49487
- * be evaluated at search time and will be treated as a denial. Use
49488
- * role/permission/claims-based authorities for discoverable skills.
49489
- */
49490
- async filterResultsByAuthorities(results) {
49491
- const registry = this.scope.skills;
49492
- if (!registry) return results;
49493
- const ctx = this.rawInput["ctx"];
49494
- const authInfo = ctx?.["authInfo"] ?? {};
49495
- return filterSkillMetadataByAuthorities(this.scope, registry, results, authInfo);
49496
- }
49497
49622
  };
49498
49623
  __decorateClass([
49499
49624
  Stage32("parseInput")
@@ -49525,6 +49650,7 @@ var init_load_skill_flow = __esm({
49525
49650
  init_common();
49526
49651
  init_errors();
49527
49652
  init_skill_authorities_helper();
49653
+ init_skill_entry_resolver();
49528
49654
  init_skill_filter_helper();
49529
49655
  init_skill_http_utils();
49530
49656
  init_skill_utils();
@@ -49626,13 +49752,14 @@ var init_load_skill_flow = __esm({
49626
49752
  const ctx = this.rawInput["ctx"];
49627
49753
  const authInfo = ctx?.["authInfo"] ?? {};
49628
49754
  const loadResults = [];
49755
+ const resolveEntry = createSkillEntryResolver(skillRegistry);
49629
49756
  for (const skillId of skillIds) {
49630
49757
  const result = await skillRegistry.loadSkill(skillId);
49631
49758
  if (!result) {
49632
49759
  warnings.push(`Skill "${skillId}" not found`);
49633
49760
  continue;
49634
49761
  }
49635
- const entry = this.findSkillEntry(skillId, result.skill.id);
49762
+ const entry = resolveEntry(skillId, result.skill.id);
49636
49763
  if (entry) {
49637
49764
  if (!await isSkillServable(this.scope, entry)) {
49638
49765
  warnings.push(`Skill "${skillId}" not found`);
@@ -49645,17 +49772,6 @@ var init_load_skill_flow = __esm({
49645
49772
  this.state.set({ loadResults, warnings });
49646
49773
  this.logger.verbose("loadSkills:done", { loaded: loadResults.length, notFound: warnings.length });
49647
49774
  }
49648
- /**
49649
- * Resolve the registered skill entry that backs a loaded skill, so its
49650
- * `authorities` metadata can be evaluated. Matches by the requested id, the
49651
- * resolved content id, and finally by display name — covering id/name/
49652
- * qualified-name lookups the registry's `loadSkill` accepts.
49653
- */
49654
- findSkillEntry(requestedId, resolvedId) {
49655
- const registry = this.scope.skills;
49656
- if (!registry) return void 0;
49657
- return registry.findByName(requestedId) ?? registry.findByQualifiedName(requestedId) ?? registry.findByName(resolvedId) ?? registry.getSkills(true).find((s) => (s.metadata.id ?? s.name) === resolvedId || s.metadata.name === resolvedId);
49658
- }
49659
49775
  async activateSessions() {
49660
49776
  this.logger.verbose("activateSessions:start");
49661
49777
  const { activateSession, policyMode, loadResults } = this.state.required;
@@ -50651,6 +50767,7 @@ var init_skills_api_flow = __esm({
50651
50767
  init_skills_http();
50652
50768
  init_auth3();
50653
50769
  init_skill_authorities_helper();
50770
+ init_skill_entry_resolver();
50654
50771
  init_skill_filter_helper();
50655
50772
  init_skill_http_utils();
50656
50773
  init_skill_utils();
@@ -50835,7 +50952,7 @@ var init_skills_api_flow = __esm({
50835
50952
  return;
50836
50953
  }
50837
50954
  const { skill, availableTools, missingTools, isComplete, warning } = loadResult;
50838
- const skillEntry = skillRegistry.getSkills(true).find((s) => s.metadata.id === skill.id || s.metadata.id === void 0 && s.name === skill.id);
50955
+ const skillEntry = createSkillEntryResolver(skillRegistry)(skillId, skill.id);
50839
50956
  if (skillEntry) {
50840
50957
  if (!await isSkillServable(this.scope, skillEntry)) {
50841
50958
  respondNotFound();
@@ -50928,8 +51045,9 @@ var init_skills_api_flow = __esm({
50928
51045
  const visibility = r.metadata.visibility ?? "both";
50929
51046
  return visibility !== "mcp";
50930
51047
  });
50931
- filteredResults = await this.filterHttpResultsByAuthorities(filteredResults, skillRegistry);
50932
- filteredResults = await filterServableSkillResults(this.scope, skillRegistry, filteredResults);
51048
+ filteredResults = await filterDiscoverableSkillResults(this.scope, skillRegistry, filteredResults, {
51049
+ authInfo: this.httpAuthInfo()
51050
+ });
50933
51051
  if (options.category) {
50934
51052
  filteredResults = filteredResults.filter((r) => r.metadata.category === options.category);
50935
51053
  }
@@ -51004,14 +51122,6 @@ var init_skills_api_flow = __esm({
51004
51122
  const user = request?.authSession?.user;
51005
51123
  return user ? { user } : {};
51006
51124
  }
51007
- /**
51008
- * Filter search results (whose projected metadata lacks `authorities`) down
51009
- * to skills the caller can discover, by resolving the live skill entry to
51010
- * read its declared authorities. No-op when no engine is configured.
51011
- */
51012
- async filterHttpResultsByAuthorities(results, skillRegistry) {
51013
- return filterSkillMetadataByAuthorities(this.scope, skillRegistry, results, this.httpAuthInfo());
51014
- }
51015
51125
  async handleListSkills(options, skillRegistry) {
51016
51126
  const allSkills = skillRegistry.getSkills({ includeHidden: false, visibility: "http" });
51017
51127
  let filteredSkills = await filterServableSkills(
@@ -53790,6 +53900,7 @@ function buildPerSkillResourceRecord(scope, skill, opts = {}) {
53790
53900
  }
53791
53901
  async function registerPerSkillResources(options) {
53792
53902
  const { scope, resourceRegistry, skills, logger, resolveLastModified } = options;
53903
+ const registered = [];
53793
53904
  for (const skill of skills) {
53794
53905
  let lastModified;
53795
53906
  if (resolveLastModified) {
@@ -53804,6 +53915,11 @@ async function registerPerSkillResources(options) {
53804
53915
  try {
53805
53916
  const record = buildPerSkillResourceRecord(scope, skill, { lastModified });
53806
53917
  resourceRegistry.registerDynamicResource(record);
53918
+ registered.push({
53919
+ skillPath: skill.getSkillPath(),
53920
+ metadata: record.metadata,
53921
+ extensionKeys: Object.keys(skillExtensionMetadata(skill))
53922
+ });
53807
53923
  logger.verbose(`Registered SEP-2640 per-skill resource: ${record.metadata.uri}`);
53808
53924
  } catch (err) {
53809
53925
  logger.warn(
@@ -53811,6 +53927,32 @@ async function registerPerSkillResources(options) {
53811
53927
  );
53812
53928
  }
53813
53929
  }
53930
+ if (registered.length > 0) {
53931
+ scope.skills?.subscribe({ immediate: false }, () => {
53932
+ const served = servedSkillsByPath(scope);
53933
+ for (const resource of registered) {
53934
+ const skill = served.get(resource.skillPath);
53935
+ if (skill) refreshFromSkill(resource, skill);
53936
+ }
53937
+ });
53938
+ }
53939
+ }
53940
+ function servedSkillsByPath(scope) {
53941
+ const served = /* @__PURE__ */ new Map();
53942
+ for (const skill of getSepVisibleSkills(scope)) {
53943
+ const skillPath = skill.getSkillPath();
53944
+ if (!served.has(skillPath)) served.set(skillPath, skill);
53945
+ }
53946
+ return served;
53947
+ }
53948
+ function refreshFromSkill(resource, skill) {
53949
+ const extensions = skillExtensionMetadata(skill);
53950
+ for (const key of resource.extensionKeys) {
53951
+ if (!(key in extensions)) Reflect.deleteProperty(resource.metadata, key);
53952
+ }
53953
+ Object.assign(resource.metadata, extensions);
53954
+ resource.metadata["description"] = skill.metadata.description;
53955
+ resource.extensionKeys = Object.keys(extensions);
53814
53956
  }
53815
53957
  var init_sep_2640_per_skill = __esm({
53816
53958
  "libs/sdk/src/skill/sep-2640/sep-2640.per-skill.ts"() {
@@ -55120,15 +55262,6 @@ var init_handle_sse_flow = __esm({
55120
55262
  }
55121
55263
  });
55122
55264
 
55123
- // libs/sdk/src/transport/transport.types.ts
55124
- var STATELESS_SESSION_ID;
55125
- var init_transport_types = __esm({
55126
- "libs/sdk/src/transport/transport.types.ts"() {
55127
- "use strict";
55128
- STATELESS_SESSION_ID = "__stateless__";
55129
- }
55130
- });
55131
-
55132
55265
  // libs/sdk/src/transport/flows/handle.stateless-http.flow.ts
55133
55266
  var import_lazy_zod104, import_protocol53, plan39, stateSchema39, name40, Stage40, HandleStatelessHttpFlow;
55134
55267
  var init_handle_stateless_http_flow = __esm({
@@ -56495,8 +56628,7 @@ function sanitizeName(raw) {
56495
56628
  return s.length > MAX_SKILL_NAME_CHARS ? `${s.slice(0, MAX_SKILL_NAME_CHARS)}\u2026` : s;
56496
56629
  }
56497
56630
  function buildSkillsCatalogSummary(skillRegistry, options = {}) {
56498
- if (!skillRegistry) return "";
56499
- const skills = skillRegistry.getSkills({ visibility: "mcp" });
56631
+ const skills = options.skills ?? skillRegistry?.getSkills({ visibility: "mcp" }) ?? [];
56500
56632
  if (skills.length === 0) return "";
56501
56633
  const pointers = options.mcpResources === false ? METHOD_POINTERS : RESOURCE_POINTERS;
56502
56634
  const lines = [pointers.header, ""];
@@ -56537,7 +56669,10 @@ function composeInitializeInstructions(options) {
56537
56669
  if (policy === "off") {
56538
56670
  return joinSections([user, channel2]);
56539
56671
  }
56540
- const catalog = buildSkillsCatalogSummary(options.skillRegistry, { mcpResources: options.mcpResources });
56672
+ const catalog = buildSkillsCatalogSummary(options.skillRegistry, {
56673
+ mcpResources: options.mcpResources,
56674
+ skills: options.skills
56675
+ });
56541
56676
  if (policy === "prepend") {
56542
56677
  return joinSections([catalog, channel2, user]);
56543
56678
  }
@@ -56548,6 +56683,60 @@ function buildChannelInstructions(channels) {
56548
56683
  const hasTwoWay = channels.getChannelInstances().some((ch) => ch.twoWay);
56549
56684
  return hasTwoWay ? "Events arrive as <channel> tags. Reply with the channel-reply tool." : "Events arrive as <channel> tags.";
56550
56685
  }
56686
+ async function composeCallerInstructions(scope, options = {}) {
56687
+ const skillsConfig = scope.metadata.skillsConfig;
56688
+ const composeOptions = {
56689
+ userInstructions: scope.metadata.instructions,
56690
+ channelInstructions: buildChannelInstructions(scope.channels),
56691
+ skillRegistry: scope.skills,
56692
+ policy: skillsConfig?.injectInstructions,
56693
+ mcpResources: skillsConfig?.mcpResources
56694
+ };
56695
+ const withUriHints = options.skillUriHints === true && skillUriHintsEnabled(scope);
56696
+ const listsSkills = withUriHints || includesSkillCatalog(composeOptions);
56697
+ let skills = [];
56698
+ if (listsSkills) {
56699
+ try {
56700
+ skills = await skillsVisibleTo(scope, options.ctx);
56701
+ } catch (error) {
56702
+ scope.logger.warn("initialize instructions: left the skills out, the skills:filter flow failed", {
56703
+ error: error instanceof Error ? error.message : String(error)
56704
+ });
56705
+ }
56706
+ }
56707
+ const composed = composeInitializeInstructions({ ...composeOptions, skills });
56708
+ const uriHints = withUriHints ? buildSkillUriHints(skills, scope.skills?.getSep2640InstructionUris?.() ?? []) : "";
56709
+ return [composed, uriHints].filter((section) => section.length > 0).join("\n\n---\n\n");
56710
+ }
56711
+ function buildSkillUriHints(skills, extraUris = []) {
56712
+ if (skills.length === 0) return "";
56713
+ const lines = ["Available skills (load via resources/read):"];
56714
+ for (const skill of skills) {
56715
+ lines.push(`- skill://${skill.getSkillPath()}/SKILL.md \u2014 ${skill.metadata.description}`);
56716
+ }
56717
+ for (const extra of extraUris) {
56718
+ lines.push(`- ${extra}`);
56719
+ }
56720
+ return lines.join("\n");
56721
+ }
56722
+ function skillUriHintsEnabled(scope) {
56723
+ const skillsConfig = scope.metadata.skillsConfig;
56724
+ if (!skillsConfig?.sep2640InInstructions || skillsConfig.mcpResources === false) return false;
56725
+ const serverInstructions = (scope.metadata.instructions ?? "").trim();
56726
+ return !(skillsConfig.injectInstructions === "replace" && serverInstructions.length > 0);
56727
+ }
56728
+ function includesSkillCatalog(options) {
56729
+ const policy = options.policy ?? DEFAULT_POLICY;
56730
+ if (policy === "off") return false;
56731
+ return !(policy === "replace" && (options.userInstructions ?? "").trim().length > 0);
56732
+ }
56733
+ async function skillsVisibleTo(scope, ctx) {
56734
+ const visible = scope.skills?.getSkills({ visibility: "mcp" }) ?? [];
56735
+ if (visible.length === 0) return [];
56736
+ const authInfo = ctx?.authInfo ?? {};
56737
+ const authorized = await filterSkillsByAuthorities(scope, visible, authInfo);
56738
+ return filterServableSkills(scope, authorized, ctx);
56739
+ }
56551
56740
  function joinSections(sections) {
56552
56741
  return sections.map((s) => (s ?? "").trim()).filter((s) => s.length > 0).join("\n\n---\n\n");
56553
56742
  }
@@ -56556,6 +56745,8 @@ var init_skill_instructions_helper = __esm({
56556
56745
  "libs/sdk/src/skill/skill-instructions.helper.ts"() {
56557
56746
  "use strict";
56558
56747
  init_sep_2640_constants();
56748
+ init_skill_authorities_helper();
56749
+ init_skill_filter_helper();
56559
56750
  DEFAULT_POLICY = "append";
56560
56751
  MAX_SKILL_CATALOG_CHARS = 16e3;
56561
56752
  TRUNCATION_FOOTER_RESERVE = 160;
@@ -56684,18 +56875,8 @@ var init_transport_local_adapter = __esm({
56684
56875
  const elicitationCapability = this.scope.metadata.elicitation?.enabled ? { elicitation: {} } : {};
56685
56876
  const channelCapabilities = this.scope.channels?.getCapabilities() ?? {};
56686
56877
  const skillsCapabilities = this.scope.skills?.getCapabilities() ?? {};
56687
- const composeInstructions = () => {
56688
- const composed = composeInitializeInstructions({
56689
- userInstructions: this.scope.metadata.instructions,
56690
- channelInstructions: buildChannelInstructions(this.scope.channels),
56691
- skillRegistry: this.scope.skills,
56692
- policy: this.scope.metadata.skillsConfig?.injectInstructions,
56693
- mcpResources: this.scope.metadata.skillsConfig?.mcpResources
56694
- });
56695
- const sep2640Hints = this.buildSkillInstructionHints();
56696
- return [composed, sep2640Hints].filter((s) => s.length > 0).join("\n\n---\n\n");
56697
- };
56698
- const instructions = composeInstructions();
56878
+ const composeInstructions = (caller) => composeCallerInstructions(this.scope, { ctx: caller, skillUriHints: true });
56879
+ const instructions = "";
56699
56880
  const mergedCapabilities = mergeExperimental([
56700
56881
  remoteCapabilities,
56701
56882
  // Pre-advertise for remote apps (may be overwritten by local)
@@ -56945,34 +57126,6 @@ var init_transport_local_adapter = __esm({
56945
57126
  const appObj = app;
56946
57127
  return "urlType" in appObj && appObj["standalone"] !== true;
56947
57128
  }
56948
- /**
56949
- * SEP-2640 §Discovery — opt-in `instructions` text listing each
56950
- * MCP-visible skill's `skill://` URI. Returns an empty string unless
56951
- * `skillsConfig.sep2640InInstructions` is true and the `skill://`
56952
- * resources are served (`skillsConfig.mcpResources` is not false). Also
56953
- * empty under `injectInstructions: 'replace'` with non-empty server
56954
- * instructions, which must then be sent alone.
56955
- */
56956
- buildSkillInstructionHints() {
56957
- const skillRegistry = this.scope.skills;
56958
- if (!skillRegistry?.hasAny()) return "";
56959
- const skillsConfig = this.scope.metadata?.skillsConfig;
56960
- if (!skillsConfig?.sep2640InInstructions || skillsConfig.mcpResources === false) return "";
56961
- const serverInstructions = (this.scope.metadata.instructions ?? "").trim();
56962
- if (skillsConfig.injectInstructions === "replace" && serverInstructions.length > 0) return "";
56963
- const visible = skillRegistry.getSkills({ visibility: "mcp" });
56964
- if (visible.length === 0) return "";
56965
- const lines = ["Available skills (load via resources/read):"];
56966
- for (const skill of visible) {
56967
- const uri = `skill://${skill.getSkillPath()}/SKILL.md`;
56968
- lines.push(`- ${uri} \u2014 ${skill.metadata.description}`);
56969
- }
56970
- const extras = skillRegistry.getSep2640InstructionUris?.() ?? [];
56971
- for (const extra of extras) {
56972
- lines.push(`- ${extra}`);
56973
- }
56974
- return lines.join("\n");
56975
- }
56976
57129
  /**
56977
57130
  * Build capabilities that should be pre-advertised for remote apps.
56978
57131
  * Remote apps load their tools/resources/prompts asynchronously after connection,
@@ -59619,7 +59772,10 @@ var init_scope_instance = __esm({
59619
59772
  this.logger.verbose("Created UI resolver with CDN overrides", { overrides: Object.keys(cdnOverrides) });
59620
59773
  }
59621
59774
  }
59622
- this.toolUIRegistry = new ToolUIRegistry(uiResolver);
59775
+ this.toolUIRegistry = new ToolUIRegistry(uiResolver, {
59776
+ escapeStringResults: this.metadata.ui?.escapeStringResults,
59777
+ logger: this.logger
59778
+ });
59623
59779
  if (!this.cliMode) {
59624
59780
  await this.compileUIWidgets();
59625
59781
  }
@@ -61112,26 +61268,37 @@ var init_provider_registry = __esm({
61112
61268
  *
61113
61269
  * @param sessionKey - Unique context/session identifier for CONTEXT-scoped providers
61114
61270
  * @param contextProviders - Optional pre-built CONTEXT-scoped providers (e.g., FrontMcpContext)
61271
+ * @param contextSource - The ancestor registry whose views built `contextProviders`. Tokens this registry's
61272
+ * hierarchy defines below it are resolved from their own nearest definition instead of the pre-built instance,
61273
+ * so an app's plugin providers are not shadowed by the definition another app merged into the scope.
61115
61274
  * @returns ProviderViews with global and context provider maps (session/request as aliases)
61116
61275
  */
61117
- async buildViews(sessionKey, contextProviders) {
61276
+ async buildViews(sessionKey, contextProviders, contextSource) {
61118
61277
  validateSessionId(sessionKey);
61119
61278
  const global = this.getAllSingletons();
61120
61279
  let sessionProviders;
61280
+ const ownDefs = (contextSource && this.defsBelow(contextSource)) ?? /* @__PURE__ */ new Map();
61121
61281
  if (this.sessionCacheEnabled) {
61122
61282
  let cached = this.sessionStores.get(sessionKey);
61123
61283
  if (!cached) {
61124
- cached = { providers: /* @__PURE__ */ new Map(), lastAccess: Date.now() };
61284
+ cached = { providers: /* @__PURE__ */ new Map(), bySource: /* @__PURE__ */ new Map(), lastAccess: Date.now() };
61125
61285
  this.sessionStores.set(sessionKey, cached);
61126
61286
  } else {
61127
61287
  cached.lastAccess = Date.now();
61128
61288
  }
61129
61289
  sessionProviders = cached.providers;
61290
+ if (contextSource && ownDefs.size > 0) {
61291
+ sessionProviders = cached.bySource.get(contextSource);
61292
+ if (!sessionProviders) {
61293
+ sessionProviders = /* @__PURE__ */ new Map();
61294
+ cached.bySource.set(contextSource, sessionProviders);
61295
+ }
61296
+ }
61130
61297
  }
61131
61298
  const requestTokens = requestScopedTokens(contextProviders);
61132
61299
  const contextStore = new Map(sessionProviders ?? []);
61133
61300
  for (const [token, instance] of contextProviders ?? []) {
61134
- contextStore.set(token, instance);
61301
+ if (!ownDefs.has(token)) contextStore.set(token, instance);
61135
61302
  }
61136
61303
  for (const token of this.order) {
61137
61304
  const rec = this.defs.get(token);
@@ -61146,6 +61313,18 @@ var init_provider_registry = __esm({
61146
61313
  if (contextStore.has(token)) continue;
61147
61314
  await this.buildIntoStoreWithViews(token, rec, contextStore, sessionKey, contextStore, global);
61148
61315
  }
61316
+ for (const [token, { registry, rec }] of ownDefs) {
61317
+ if (registry === this || contextStore.has(token)) continue;
61318
+ if (registry.getProviderScope(rec) !== import_di39.ProviderScope.CONTEXT) continue;
61319
+ await registry.buildIntoStoreWithViews(
61320
+ token,
61321
+ rec,
61322
+ contextStore,
61323
+ sessionKey,
61324
+ contextStore,
61325
+ registry.getAllSingletons()
61326
+ );
61327
+ }
61149
61328
  if (sessionProviders) {
61150
61329
  for (const [token, instance] of contextStore) {
61151
61330
  if (!sessionProviders.has(token) && !this.dependsOnAny(token, requestTokens)) {
@@ -61158,6 +61337,14 @@ var init_provider_registry = __esm({
61158
61337
  context: contextStore
61159
61338
  };
61160
61339
  }
61340
+ /** Nearest definition of each token declared between this registry and `ancestor`; undefined when `ancestor` is not above it. */
61341
+ defsBelow(ancestor) {
61342
+ if (this === ancestor) return /* @__PURE__ */ new Map();
61343
+ const owned = this.parentProviders?.defsBelow(ancestor);
61344
+ if (!owned) return void 0;
61345
+ for (const [token, rec] of this.defs) owned.set(token, { registry: this, rec });
61346
+ return owned;
61347
+ }
61161
61348
  dependsOnAny(token, targets, visited = /* @__PURE__ */ new Set()) {
61162
61349
  if (targets.has(token)) return true;
61163
61350
  if (visited.has(token)) return false;
@@ -61243,6 +61430,15 @@ var init_provider_registry = __esm({
61243
61430
  if (v !== void 0) return v;
61244
61431
  throw new ProviderNotInstantiatedError((0, import_di39.tokenName)(token), "GLOBAL", "parent");
61245
61432
  }
61433
+ await up.registry.buildIntoStoreWithViews(
61434
+ token,
61435
+ up.rec,
61436
+ contextStore,
61437
+ scopeKey,
61438
+ contextStore,
61439
+ up.registry.getAllSingletons()
61440
+ );
61441
+ return contextStore.get(token);
61246
61442
  }
61247
61443
  throw new ProviderDependencyError(`Cannot resolve dependency ${(0, import_di39.tokenName)(token)} from views`);
61248
61444
  }
@@ -62907,14 +63103,8 @@ var init_front_mcp = __esm({
62907
63103
  prompts: { listChanged: true }
62908
63104
  } : {};
62909
63105
  const channelCapabilities = scope.channels?.getCapabilities() ?? {};
62910
- const composeInstructions = () => composeInitializeInstructions({
62911
- userInstructions: scope.metadata.instructions,
62912
- channelInstructions: buildChannelInstructions(scope.channels),
62913
- skillRegistry: scope.skills,
62914
- policy: scope.metadata.skillsConfig?.injectInstructions,
62915
- mcpResources: scope.metadata.skillsConfig?.mcpResources
62916
- });
62917
- const instructions = composeInstructions();
63106
+ const composeInstructions = (caller) => composeCallerInstructions(scope, { ctx: caller });
63107
+ const instructions = "";
62918
63108
  const serverOptions = {
62919
63109
  instructions,
62920
63110
  capabilities: {
@@ -65520,6 +65710,7 @@ __export(index_exports, {
65520
65710
  channelsConfigSchema: () => channelsConfigSchema,
65521
65711
  clearCreateCache: () => clearCreateCache,
65522
65712
  compareVersions: () => compareVersions,
65713
+ composeCallerInstructions: () => composeCallerInstructions,
65523
65714
  composeInitializeInstructions: () => composeInitializeInstructions,
65524
65715
  computeIssuer: () => computeIssuer,
65525
65716
  computeResource: () => computeResource,
@@ -66709,6 +66900,7 @@ var ChannelListHook = FlowHooksOf("channels:list");
66709
66900
  channelsConfigSchema,
66710
66901
  clearCreateCache,
66711
66902
  compareVersions,
66903
+ composeCallerInstructions,
66712
66904
  composeInitializeInstructions,
66713
66905
  computeIssuer,
66714
66906
  computeResource,