@vantageos/mosaic 0.4.0 → 0.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 (150) hide show
  1. package/CHANGELOG.md +39 -15
  2. package/README.md +114 -5
  3. package/dist/PipelineBoard-FucyGArR.d.cts +759 -0
  4. package/dist/PipelineBoard-FucyGArR.d.ts +759 -0
  5. package/dist/PipelineBoard.markdown-DIcvrS-2.d.cts +16 -0
  6. package/dist/PipelineBoard.markdown-DIcvrS-2.d.ts +16 -0
  7. package/dist/{StatusBadge.schema-1tOjB4Ir.d.cts → StatusBadge.schema-BEjSH2_4.d.cts} +2 -2
  8. package/dist/{StatusBadge.schema-1tOjB4Ir.d.ts → StatusBadge.schema-BEjSH2_4.d.ts} +2 -2
  9. package/dist/{Tabs.schema-BzcEyeq8.d.cts → Tabs.schema-Dqr6vwV3.d.cts} +2 -2
  10. package/dist/{Tabs.schema-BzcEyeq8.d.ts → Tabs.schema-Dqr6vwV3.d.ts} +2 -2
  11. package/dist/Timeline-Coo_3tA_.d.cts +114 -0
  12. package/dist/Timeline-Coo_3tA_.d.ts +114 -0
  13. package/dist/Timeline.markdown-C6UPDv1H.d.cts +4 -0
  14. package/dist/Timeline.markdown-C6UPDv1H.d.ts +4 -0
  15. package/dist/TransactionPreview-BzWDn8kE.d.cts +391 -0
  16. package/dist/TransactionPreview-BzWDn8kE.d.ts +391 -0
  17. package/dist/TransactionPreview.markdown-Dpb0VYgN.d.cts +7 -0
  18. package/dist/TransactionPreview.markdown-Dpb0VYgN.d.ts +7 -0
  19. package/dist/artifacts.cjs +186 -2
  20. package/dist/artifacts.cjs.map +1 -1
  21. package/dist/artifacts.js +186 -2
  22. package/dist/artifacts.js.map +1 -1
  23. package/dist/confirmation.cjs +724 -2
  24. package/dist/confirmation.cjs.map +1 -1
  25. package/dist/confirmation.d.cts +2 -1
  26. package/dist/confirmation.d.ts +2 -1
  27. package/dist/confirmation.js +722 -4
  28. package/dist/confirmation.js.map +1 -1
  29. package/dist/display.cjs +1551 -203
  30. package/dist/display.cjs.map +1 -1
  31. package/dist/display.d.cts +6 -229
  32. package/dist/display.d.ts +6 -229
  33. package/dist/display.js +1535 -206
  34. package/dist/display.js.map +1 -1
  35. package/dist/forms.cjs +139 -46
  36. package/dist/forms.cjs.map +1 -1
  37. package/dist/forms.d.cts +2 -2
  38. package/dist/forms.d.ts +2 -2
  39. package/dist/forms.js +139 -46
  40. package/dist/forms.js.map +1 -1
  41. package/dist/host.cjs +822 -0
  42. package/dist/host.cjs.map +1 -0
  43. package/dist/host.d.cts +287 -0
  44. package/dist/host.d.ts +287 -0
  45. package/dist/host.js +794 -0
  46. package/dist/host.js.map +1 -0
  47. package/dist/{index-CwXVgtGb.d.cts → index-BadRcCbm.d.cts} +28 -11
  48. package/dist/{index-CwXVgtGb.d.ts → index-BadRcCbm.d.ts} +28 -11
  49. package/dist/index.cjs +2198 -247
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.d.cts +42 -8
  52. package/dist/index.d.ts +42 -8
  53. package/dist/index.js +2163 -251
  54. package/dist/index.js.map +1 -1
  55. package/dist/input.d.cts +2 -2
  56. package/dist/input.d.ts +2 -2
  57. package/dist/media.cjs +186 -2
  58. package/dist/media.cjs.map +1 -1
  59. package/dist/media.d.cts +1 -1
  60. package/dist/media.d.ts +1 -1
  61. package/dist/media.js +186 -2
  62. package/dist/media.js.map +1 -1
  63. package/dist/preact/artifacts.js +186 -2
  64. package/dist/preact/artifacts.js.map +1 -1
  65. package/dist/preact/confirmation.d.ts +321 -1
  66. package/dist/preact/confirmation.js +625 -4
  67. package/dist/preact/confirmation.js.map +1 -1
  68. package/dist/preact/display.d.ts +544 -47
  69. package/dist/preact/display.js +1190 -126
  70. package/dist/preact/display.js.map +1 -1
  71. package/dist/preact/forms.d.ts +32 -15
  72. package/dist/preact/forms.js +139 -46
  73. package/dist/preact/forms.js.map +1 -1
  74. package/dist/preact/host.d.ts +307 -0
  75. package/dist/preact/host.js +875 -0
  76. package/dist/preact/host.js.map +1 -0
  77. package/dist/preact/media.d.ts +37 -1
  78. package/dist/preact/media.js +423 -0
  79. package/dist/preact/media.js.map +1 -1
  80. package/dist/preact/progress.d.ts +92 -1
  81. package/dist/preact/progress.js +465 -3
  82. package/dist/preact/progress.js.map +1 -1
  83. package/dist/progress.cjs +521 -2
  84. package/dist/progress.cjs.map +1 -1
  85. package/dist/progress.d.cts +2 -1
  86. package/dist/progress.d.ts +2 -1
  87. package/dist/progress.js +518 -3
  88. package/dist/progress.js.map +1 -1
  89. package/dist/react/artifacts.cjs +186 -2
  90. package/dist/react/artifacts.cjs.map +1 -1
  91. package/dist/react/artifacts.js +186 -2
  92. package/dist/react/artifacts.js.map +1 -1
  93. package/dist/react/confirmation.cjs +626 -2
  94. package/dist/react/confirmation.cjs.map +1 -1
  95. package/dist/react/confirmation.d.cts +3 -3
  96. package/dist/react/confirmation.d.ts +3 -3
  97. package/dist/react/confirmation.js +625 -4
  98. package/dist/react/confirmation.js.map +1 -1
  99. package/dist/react/display.cjs +1076 -123
  100. package/dist/react/display.cjs.map +1 -1
  101. package/dist/react/display.d.cts +13 -27
  102. package/dist/react/display.d.ts +13 -27
  103. package/dist/react/display.js +1064 -126
  104. package/dist/react/display.js.map +1 -1
  105. package/dist/react/forms.cjs +139 -46
  106. package/dist/react/forms.cjs.map +1 -1
  107. package/dist/react/forms.d.cts +1 -1
  108. package/dist/react/forms.d.ts +1 -1
  109. package/dist/react/forms.js +139 -46
  110. package/dist/react/forms.js.map +1 -1
  111. package/dist/react/host.cjs +910 -0
  112. package/dist/react/host.cjs.map +1 -0
  113. package/dist/react/host.d.cts +24 -0
  114. package/dist/react/host.d.ts +24 -0
  115. package/dist/react/host.js +875 -0
  116. package/dist/react/host.js.map +1 -0
  117. package/dist/react/input.d.cts +1 -1
  118. package/dist/react/input.d.ts +1 -1
  119. package/dist/react/media.cjs +426 -0
  120. package/dist/react/media.cjs.map +1 -1
  121. package/dist/react/media.d.cts +19 -1
  122. package/dist/react/media.d.ts +19 -1
  123. package/dist/react/media.js +423 -0
  124. package/dist/react/media.js.map +1 -1
  125. package/dist/react/progress.cjs +467 -2
  126. package/dist/react/progress.cjs.map +1 -1
  127. package/dist/react/progress.d.cts +1 -1
  128. package/dist/react/progress.d.ts +1 -1
  129. package/dist/react/progress.js +465 -3
  130. package/dist/react/progress.js.map +1 -1
  131. package/dist/server/resource.cjs +151 -0
  132. package/dist/server/resource.cjs.map +1 -0
  133. package/dist/server/resource.d.cts +90 -0
  134. package/dist/server/resource.d.ts +90 -0
  135. package/dist/server/resource.js +147 -0
  136. package/dist/server/resource.js.map +1 -0
  137. package/dist/server.cjs +1100 -25
  138. package/dist/server.cjs.map +1 -1
  139. package/dist/server.d.cts +84 -5
  140. package/dist/server.d.ts +84 -5
  141. package/dist/server.js +1087 -27
  142. package/dist/server.js.map +1 -1
  143. package/package.json +250 -233
  144. package/registry.yaml +44 -2
  145. package/dist/Alert.schema-LPJE5gFP.d.cts +0 -71
  146. package/dist/Alert.schema-LPJE5gFP.d.ts +0 -71
  147. package/dist/ProgressBar.schema-CdVYx0Wq.d.cts +0 -22
  148. package/dist/ProgressBar.schema-CdVYx0Wq.d.ts +0 -22
  149. package/dist/{ConfirmDialog-B3CQQGmJ.d.cts → ConfirmDialog-BCtOcmHe.d.cts} +1 -1
  150. package/dist/{ConfirmDialog-B3CQQGmJ.d.ts → ConfirmDialog-BCtOcmHe.d.ts} +1 -1
@@ -0,0 +1,90 @@
1
+ declare const MCP_APP_MIME_TYPE: "text/html;profile=mcp-app";
2
+ interface McpAppCsp {
3
+ connectDomains?: string[];
4
+ resourceDomains?: string[];
5
+ frameDomains?: string[];
6
+ baseUriDomains?: string[];
7
+ }
8
+ type OpenAiEntrypoint = {
9
+ type: "global";
10
+ } | {
11
+ type: "thread";
12
+ } | {
13
+ type: "file";
14
+ extensions: string[];
15
+ };
16
+ /** ChatGPT display modes. `pip` is not one (openai/mcp-extensions docs/spec.md l.843-890). */
17
+ type ChatGptDisplayMode = "inline" | "fullscreen";
18
+ interface McpAppOpenAiInput {
19
+ /** `openai/outputTemplate`: compatibility alias of `_meta.ui.resourceUri` (tool level; fleet ruling, additive). */
20
+ outputTemplate?: string;
21
+ /** `_meta["openai/ui"].availableDisplayModes` on the resource content item (spec l.843-890). */
22
+ availableDisplayModes?: ChatGptDisplayMode[];
23
+ /** `_meta["openai/ui"].preferredDisplayMode` on the resource content item (spec l.843-890). */
24
+ preferredDisplayMode?: ChatGptDisplayMode;
25
+ /** `_meta["openai/ui"].entrypoints` on the tool descriptor (spec l.59, l.116). */
26
+ entrypoints?: OpenAiEntrypoint[];
27
+ }
28
+ /** Who sees a tool: `"model"` (agent tool list) and/or `"app"` (callable from the view). */
29
+ type ToolVisibility = "model" | "app";
30
+ interface McpAppResourceInput {
31
+ uri: `ui://${string}`;
32
+ html: string;
33
+ csp?: McpAppCsp;
34
+ /** The URL this MCP server is served at. Claude's `ui.domain` is DERIVED from it. */
35
+ servedUrl?: string;
36
+ prefersBorder?: boolean;
37
+ openai?: McpAppOpenAiInput;
38
+ /**
39
+ * Tool-level `_meta.ui.visibility` (MCP Apps spec 2026-01-26, ext-apps-spec.mdx l.332,
40
+ * l.395-401). Omitted = the spec default `["model", "app"]`. `["app"]` makes an app-only tool
41
+ * (refresh, UI-only sort/filter; l.1490) that hosts MUST keep out of the agent's tool list.
42
+ * OpenAI: ignored when the App is invoked as an entrypoint.
43
+ */
44
+ visibility?: ToolVisibility[];
45
+ /**
46
+ * Allow Claude host fonts (`hostContext.styles.css.fonts`): adds `https://assets.claude.ai` to
47
+ * `csp.resourceDomains` (Claude transparent-theming page).
48
+ */
49
+ hostFonts?: boolean;
50
+ }
51
+ interface McpAppResourceMetaUi {
52
+ csp: Required<McpAppCsp>;
53
+ prefersBorder?: boolean;
54
+ domain?: string;
55
+ }
56
+ interface McpAppResourceOutput {
57
+ resource: {
58
+ uri: `ui://${string}`;
59
+ mimeType: typeof MCP_APP_MIME_TYPE;
60
+ text: string;
61
+ _meta: {
62
+ ui: McpAppResourceMetaUi;
63
+ "openai/ui"?: {
64
+ availableDisplayModes?: ChatGptDisplayMode[];
65
+ preferredDisplayMode?: ChatGptDisplayMode;
66
+ };
67
+ };
68
+ };
69
+ toolMeta: {
70
+ ui: {
71
+ resourceUri: `ui://${string}`;
72
+ visibility?: ToolVisibility[];
73
+ };
74
+ "openai/outputTemplate"?: string;
75
+ "openai/ui"?: {
76
+ entrypoints: OpenAiEntrypoint[];
77
+ };
78
+ };
79
+ }
80
+ /**
81
+ * Claude's stable app origin: `{sha256(mcpServerUrl) first 32 hex}.claudemcpcontent.com`.
82
+ * Source: https://claude.com/docs/connectors/building/mcp-apps/getting-started, section
83
+ * "Set ui.domain for Claude" (same derivation as the `@modelcontextprotocol/ext-apps/server`
84
+ * example). Known answer: "https://example.com/mcp" ->
85
+ * "c3d80a4ed901ee05b21755a88273b4a4.claudemcpcontent.com".
86
+ */
87
+ declare function deriveClaudeAppDomain(servedUrl: string): string;
88
+ declare function buildMcpAppResource(input: McpAppResourceInput): McpAppResourceOutput;
89
+
90
+ export { type ChatGptDisplayMode, MCP_APP_MIME_TYPE, type McpAppCsp, type McpAppOpenAiInput, type McpAppResourceInput, type McpAppResourceMetaUi, type McpAppResourceOutput, type OpenAiEntrypoint, type ToolVisibility, buildMcpAppResource, deriveClaudeAppDomain };
@@ -0,0 +1,147 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ // src/server/mcp-app-resource.ts
4
+
5
+ // src/host/style-variables.ts
6
+ var MCP_STYLE_VARIABLE_KEYS = [
7
+ "--color-background-primary",
8
+ "--color-background-secondary",
9
+ "--color-background-tertiary",
10
+ "--color-background-inverse",
11
+ "--color-background-ghost",
12
+ "--color-background-info",
13
+ "--color-background-danger",
14
+ "--color-background-success",
15
+ "--color-background-warning",
16
+ "--color-background-disabled",
17
+ "--color-text-primary",
18
+ "--color-text-secondary",
19
+ "--color-text-tertiary",
20
+ "--color-text-inverse",
21
+ "--color-text-info",
22
+ "--color-text-danger",
23
+ "--color-text-success",
24
+ "--color-text-warning",
25
+ "--color-text-disabled",
26
+ "--color-text-ghost",
27
+ "--color-border-primary",
28
+ "--color-border-secondary",
29
+ "--color-border-tertiary",
30
+ "--color-border-inverse",
31
+ "--color-border-ghost",
32
+ "--color-border-info",
33
+ "--color-border-danger",
34
+ "--color-border-success",
35
+ "--color-border-warning",
36
+ "--color-border-disabled",
37
+ "--color-ring-primary",
38
+ "--color-ring-secondary",
39
+ "--color-ring-inverse",
40
+ "--color-ring-info",
41
+ "--color-ring-danger",
42
+ "--color-ring-success",
43
+ "--color-ring-warning",
44
+ "--font-sans",
45
+ "--font-mono",
46
+ "--font-weight-normal",
47
+ "--font-weight-medium",
48
+ "--font-weight-semibold",
49
+ "--font-weight-bold",
50
+ "--font-text-xs-size",
51
+ "--font-text-sm-size",
52
+ "--font-text-md-size",
53
+ "--font-text-lg-size",
54
+ "--font-heading-xs-size",
55
+ "--font-heading-sm-size",
56
+ "--font-heading-md-size",
57
+ "--font-heading-lg-size",
58
+ "--font-heading-xl-size",
59
+ "--font-heading-2xl-size",
60
+ "--font-heading-3xl-size",
61
+ "--font-text-xs-line-height",
62
+ "--font-text-sm-line-height",
63
+ "--font-text-md-line-height",
64
+ "--font-text-lg-line-height",
65
+ "--font-heading-xs-line-height",
66
+ "--font-heading-sm-line-height",
67
+ "--font-heading-md-line-height",
68
+ "--font-heading-lg-line-height",
69
+ "--font-heading-xl-line-height",
70
+ "--font-heading-2xl-line-height",
71
+ "--font-heading-3xl-line-height",
72
+ "--border-radius-xs",
73
+ "--border-radius-sm",
74
+ "--border-radius-md",
75
+ "--border-radius-lg",
76
+ "--border-radius-xl",
77
+ "--border-radius-full",
78
+ "--border-width-regular",
79
+ "--shadow-hairline",
80
+ "--shadow-sm",
81
+ "--shadow-md",
82
+ "--shadow-lg"
83
+ ];
84
+ var CLAUDE_HOST_FONT_ORIGIN = "https://assets.claude.ai";
85
+ new Set(MCP_STYLE_VARIABLE_KEYS);
86
+
87
+ // src/server/mcp-app-resource.ts
88
+ var MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
89
+ function deriveClaudeAppDomain(servedUrl) {
90
+ const hash = createHash("sha256").update(servedUrl).digest("hex").slice(0, 32);
91
+ return `${hash}.claudemcpcontent.com`;
92
+ }
93
+ function buildMcpAppResource(input) {
94
+ const { uri, html, csp, servedUrl, prefersBorder, openai, visibility, hostFonts } = input;
95
+ const modes = [...openai?.availableDisplayModes ?? [], openai?.preferredDisplayMode];
96
+ if (modes.some((m) => m === "pip")) {
97
+ throw new Error("buildMcpAppResource: display mode pip is refused (inline | fullscreen only)");
98
+ }
99
+ let toolVisibility;
100
+ if (visibility !== void 0) {
101
+ const valid = visibility.every((v) => v === "model" || v === "app");
102
+ if (visibility.length === 0 || !valid) {
103
+ throw new Error(
104
+ 'buildMcpAppResource: visibility must be a non-empty list of "model" | "app"'
105
+ );
106
+ }
107
+ toolVisibility = [...new Set(visibility)];
108
+ }
109
+ const resourceDomains = [...csp?.resourceDomains ?? []];
110
+ if (hostFonts && !resourceDomains.includes(CLAUDE_HOST_FONT_ORIGIN)) {
111
+ resourceDomains.push(CLAUDE_HOST_FONT_ORIGIN);
112
+ }
113
+ const ui = {
114
+ csp: {
115
+ connectDomains: csp?.connectDomains ?? [],
116
+ resourceDomains,
117
+ frameDomains: csp?.frameDomains ?? [],
118
+ baseUriDomains: csp?.baseUriDomains ?? []
119
+ },
120
+ ...prefersBorder === void 0 ? {} : { prefersBorder },
121
+ ...servedUrl ? { domain: deriveClaudeAppDomain(servedUrl) } : {}
122
+ };
123
+ const resourceMeta = { ui };
124
+ if (openai?.availableDisplayModes !== void 0 || openai?.preferredDisplayMode !== void 0) {
125
+ resourceMeta["openai/ui"] = {
126
+ ...openai.availableDisplayModes !== void 0 ? { availableDisplayModes: openai.availableDisplayModes } : {},
127
+ ...openai.preferredDisplayMode !== void 0 ? { preferredDisplayMode: openai.preferredDisplayMode } : {}
128
+ };
129
+ }
130
+ const toolMeta = {
131
+ ui: { resourceUri: uri, ...toolVisibility ? { visibility: toolVisibility } : {} }
132
+ };
133
+ if (openai?.outputTemplate !== void 0) {
134
+ toolMeta["openai/outputTemplate"] = openai.outputTemplate;
135
+ }
136
+ if (openai?.entrypoints !== void 0) {
137
+ toolMeta["openai/ui"] = { entrypoints: openai.entrypoints };
138
+ }
139
+ return {
140
+ resource: { uri, mimeType: MCP_APP_MIME_TYPE, text: html, _meta: resourceMeta },
141
+ toolMeta
142
+ };
143
+ }
144
+
145
+ export { MCP_APP_MIME_TYPE, buildMcpAppResource, deriveClaudeAppDomain };
146
+ //# sourceMappingURL=resource.js.map
147
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/host/style-variables.ts","../../src/server/mcp-app-resource.ts"],"names":[],"mappings":"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","file":"resource.js","sourcesContent":["/**\n * Host style variables and fonts (H02) — framework-agnostic, structural (no ext-apps import).\n *\n * Spec: MCP Apps 2026-01-26 (ext-apps-spec.mdx):\n * l.547-555 `HostContext.styles = { variables?: Record<McpUiStyleVariableKey, string|undefined>,\n * css?: { fonts?: string } }`\n * l.799-888 `McpUiStyleVariableKey`, the 76 standardized keys below (extracted from the spec\n * block by command, not retyped)\n * l.895-905 \"Views should set default fallback values ... to account for hosts who don't pass\n * some or all style variables\": here the mosaic-tokens defaults are the fallback,\n * because only the variables the host passes are written.\n * Claude transparent-theming page: fonts need `https://assets.claude.ai` in `resourceDomains`;\n * html and body backgrounds are set to `transparent`.\n * Composes with ext-apps `applyHostStyleVariables` / `applyDocumentTheme` structurally; either can\n * be used instead, nothing here imports them.\n */\nexport const MCP_STYLE_VARIABLE_KEYS = [\n \"--color-background-primary\",\n \"--color-background-secondary\",\n \"--color-background-tertiary\",\n \"--color-background-inverse\",\n \"--color-background-ghost\",\n \"--color-background-info\",\n \"--color-background-danger\",\n \"--color-background-success\",\n \"--color-background-warning\",\n \"--color-background-disabled\",\n \"--color-text-primary\",\n \"--color-text-secondary\",\n \"--color-text-tertiary\",\n \"--color-text-inverse\",\n \"--color-text-info\",\n \"--color-text-danger\",\n \"--color-text-success\",\n \"--color-text-warning\",\n \"--color-text-disabled\",\n \"--color-text-ghost\",\n \"--color-border-primary\",\n \"--color-border-secondary\",\n \"--color-border-tertiary\",\n \"--color-border-inverse\",\n \"--color-border-ghost\",\n \"--color-border-info\",\n \"--color-border-danger\",\n \"--color-border-success\",\n \"--color-border-warning\",\n \"--color-border-disabled\",\n \"--color-ring-primary\",\n \"--color-ring-secondary\",\n \"--color-ring-inverse\",\n \"--color-ring-info\",\n \"--color-ring-danger\",\n \"--color-ring-success\",\n \"--color-ring-warning\",\n \"--font-sans\",\n \"--font-mono\",\n \"--font-weight-normal\",\n \"--font-weight-medium\",\n \"--font-weight-semibold\",\n \"--font-weight-bold\",\n \"--font-text-xs-size\",\n \"--font-text-sm-size\",\n \"--font-text-md-size\",\n \"--font-text-lg-size\",\n \"--font-heading-xs-size\",\n \"--font-heading-sm-size\",\n \"--font-heading-md-size\",\n \"--font-heading-lg-size\",\n \"--font-heading-xl-size\",\n \"--font-heading-2xl-size\",\n \"--font-heading-3xl-size\",\n \"--font-text-xs-line-height\",\n \"--font-text-sm-line-height\",\n \"--font-text-md-line-height\",\n \"--font-text-lg-line-height\",\n \"--font-heading-xs-line-height\",\n \"--font-heading-sm-line-height\",\n \"--font-heading-md-line-height\",\n \"--font-heading-lg-line-height\",\n \"--font-heading-xl-line-height\",\n \"--font-heading-2xl-line-height\",\n \"--font-heading-3xl-line-height\",\n \"--border-radius-xs\",\n \"--border-radius-sm\",\n \"--border-radius-md\",\n \"--border-radius-lg\",\n \"--border-radius-xl\",\n \"--border-radius-full\",\n \"--border-width-regular\",\n \"--shadow-hairline\",\n \"--shadow-sm\",\n \"--shadow-md\",\n \"--shadow-lg\",\n] as const;\nexport type McpStyleVariableKey = (typeof MCP_STYLE_VARIABLE_KEYS)[number];\nexport interface HostStyles {\n variables: Partial<Record<McpStyleVariableKey, string>>;\n fonts: string | undefined;\n}\n\n/**\n * Host variable -> mosaic-tokens custom properties it drives. Declared mapping (a design\n * decision, not a spec fact); `style-variables.test.ts` asserts every target exists in\n * `mosaic-tokens/src/tokens.css`.\n */\nexport const HOST_TO_MOSAIC_TOKENS: Partial<Record<McpStyleVariableKey, readonly string[]>> = {\n \"--color-background-primary\": [\n \"--mosaic-color-background\",\n \"--mosaic-color-card\",\n \"--mosaic-color-popover\",\n ],\n \"--color-background-secondary\": [\n \"--mosaic-color-muted\",\n \"--mosaic-color-secondary\",\n \"--mosaic-color-accent\",\n ],\n \"--color-text-primary\": [\n \"--mosaic-color-foreground\",\n \"--mosaic-color-card-foreground\",\n \"--mosaic-color-popover-foreground\",\n \"--mosaic-color-secondary-foreground\",\n \"--mosaic-color-accent-foreground\",\n ],\n \"--color-text-secondary\": [\"--mosaic-color-muted-foreground\"],\n \"--color-border-primary\": [\"--mosaic-color-border\", \"--mosaic-color-input\"],\n \"--color-ring-primary\": [\"--mosaic-color-ring\"],\n \"--color-background-danger\": [\"--mosaic-color-danger-50\"],\n \"--color-text-danger\": [\"--mosaic-color-danger-700\"],\n \"--color-border-danger\": [\"--mosaic-color-danger-500\"],\n \"--color-background-success\": [\"--mosaic-color-success-50\"],\n \"--color-text-success\": [\"--mosaic-color-success-700\"],\n \"--color-border-success\": [\"--mosaic-color-success-500\"],\n \"--color-background-warning\": [\"--mosaic-color-warning-50\"],\n \"--color-text-warning\": [\"--mosaic-color-warning-700\"],\n \"--color-border-warning\": [\"--mosaic-color-warning-500\"],\n \"--color-background-info\": [\"--mosaic-color-info-50\"],\n \"--color-text-info\": [\"--mosaic-color-info-700\"],\n \"--color-border-info\": [\"--mosaic-color-info-500\"],\n \"--font-sans\": [\"--mosaic-font-sans\"],\n \"--font-mono\": [\"--mosaic-font-mono\"],\n \"--border-radius-xs\": [\"--mosaic-radius-xs\"],\n \"--border-radius-sm\": [\"--mosaic-radius-sm\"],\n \"--border-radius-md\": [\"--mosaic-radius-md\"],\n \"--border-radius-lg\": [\"--mosaic-radius-lg\"],\n \"--border-radius-xl\": [\"--mosaic-radius-xl\"],\n \"--border-radius-full\": [\"--mosaic-radius-full\"],\n};\n\n/** Origin Claude serves host fonts from; add it to `resourceDomains` to load `styles.css.fonts`. */\nexport const CLAUDE_HOST_FONT_ORIGIN = \"https://assets.claude.ai\";\n\nconst KNOWN = new Set<string>(MCP_STYLE_VARIABLE_KEYS);\n\n/** Reads `hostContext.styles`; unknown keys and non-string values are dropped. */\nexport function readHostStyles(raw: unknown): HostStyles | undefined {\n if (raw === null || typeof raw !== \"object\") return undefined;\n const styles = (raw as Record<string, unknown>).styles;\n if (styles === null || typeof styles !== \"object\") return undefined;\n const s = styles as { variables?: unknown; css?: unknown };\n const variables: HostStyles[\"variables\"] = {};\n if (s.variables !== null && typeof s.variables === \"object\") {\n for (const [k, v] of Object.entries(s.variables as Record<string, unknown>)) {\n if (KNOWN.has(k) && typeof v === \"string\") variables[k as McpStyleVariableKey] = v;\n }\n }\n const css = s.css !== null && typeof s.css === \"object\" ? (s.css as { fonts?: unknown }) : {};\n return { variables, fonts: typeof css.fonts === \"string\" ? css.fonts : undefined };\n}\n\nconst applied = new WeakMap<HTMLElement, string[]>();\n\n/**\n * Writes the host variables on `root`, and the mosaic-tokens custom properties they drive.\n * Variables a previous call set and this one no longer carries are cleared; `undefined` clears\n * all. Variables the host never passed are not written, so mosaic-tokens defaults remain.\n */\nexport function applyHostStyleVariables(styles: HostStyles | undefined, root: HTMLElement): void {\n for (const name of applied.get(root) ?? []) root.style.removeProperty(name);\n const written: string[] = [];\n for (const [host, value] of Object.entries(styles?.variables ?? {})) {\n root.style.setProperty(host, value);\n written.push(host);\n for (const target of HOST_TO_MOSAIC_TOKENS[host as McpStyleVariableKey] ?? []) {\n root.style.setProperty(target, value);\n written.push(target);\n }\n }\n applied.set(root, written);\n}\n\nconst FONT_ATTR = \"data-mosaic-host-fonts\";\n\n/** Injects `styles.css.fonts` as one `<style>` in `<head>`; replaced on change, removed when absent. */\nexport function applyHostFonts(css: string | undefined, doc: Document): void {\n const existing = doc.head.querySelector(`style[${FONT_ATTR}]`);\n if (css === undefined) {\n existing?.remove();\n return;\n }\n const el = existing ?? doc.head.appendChild(doc.createElement(\"style\"));\n el.setAttribute(FONT_ATTR, \"\");\n el.textContent = css;\n}\n\n/** Claude transparent theming: html and body backgrounds are explicitly `transparent`. */\nexport function applyTransparentBackground(doc: Document): void {\n doc.documentElement.style.background = \"transparent\";\n doc.body.style.background = \"transparent\";\n}\n","/**\n * MCP Apps resource helper — server side, pure, no React, no DOM.\n *\n * Emits the MCP Apps (spec 2026-01-26) standard keys FIRST: resource `_meta.ui`\n * ({ csp, prefersBorder?, domain? }) and tool `_meta.ui.resourceUri`. `openai/*` keys are\n * strictly additive and appear only when the caller passes the matching input; a client that\n * ignores them loses nothing.\n *\n * Composition with `@modelcontextprotocol/ext-apps/server` (read at 2.0.3): `registerAppResource`\n * only defaults the MIME type and `registerAppTool` only back-fills the deprecated flat\n * `ui/resourceUri` key; neither computes csp defaults, the Claude `domain`, or any `openai/*`\n * key. This helper produces the metadata those registrars pass through: use `resource._meta` as\n * the resource config `_meta` and the read-result content `_meta`, and `toolMeta` as the tool\n * config `_meta`.\n */\nimport { createHash } from \"node:crypto\";\nimport { CLAUDE_HOST_FONT_ORIGIN } from \"../host/style-variables.js\";\n\nexport const MCP_APP_MIME_TYPE = \"text/html;profile=mcp-app\" as const;\n\nexport interface McpAppCsp {\n connectDomains?: string[];\n resourceDomains?: string[];\n frameDomains?: string[];\n baseUriDomains?: string[];\n}\n\nexport type OpenAiEntrypoint =\n | { type: \"global\" }\n | { type: \"thread\" }\n | { type: \"file\"; extensions: string[] };\n\n/** ChatGPT display modes. `pip` is not one (openai/mcp-extensions docs/spec.md l.843-890). */\nexport type ChatGptDisplayMode = \"inline\" | \"fullscreen\";\n\nexport interface McpAppOpenAiInput {\n /** `openai/outputTemplate`: compatibility alias of `_meta.ui.resourceUri` (tool level; fleet ruling, additive). */\n outputTemplate?: string;\n /** `_meta[\"openai/ui\"].availableDisplayModes` on the resource content item (spec l.843-890). */\n availableDisplayModes?: ChatGptDisplayMode[];\n /** `_meta[\"openai/ui\"].preferredDisplayMode` on the resource content item (spec l.843-890). */\n preferredDisplayMode?: ChatGptDisplayMode;\n /** `_meta[\"openai/ui\"].entrypoints` on the tool descriptor (spec l.59, l.116). */\n entrypoints?: OpenAiEntrypoint[];\n}\n\n/** Who sees a tool: `\"model\"` (agent tool list) and/or `\"app\"` (callable from the view). */\nexport type ToolVisibility = \"model\" | \"app\";\n\nexport interface McpAppResourceInput {\n uri: `ui://${string}`;\n html: string;\n csp?: McpAppCsp;\n /** The URL this MCP server is served at. Claude's `ui.domain` is DERIVED from it. */\n servedUrl?: string;\n prefersBorder?: boolean;\n openai?: McpAppOpenAiInput;\n /**\n * Tool-level `_meta.ui.visibility` (MCP Apps spec 2026-01-26, ext-apps-spec.mdx l.332,\n * l.395-401). Omitted = the spec default `[\"model\", \"app\"]`. `[\"app\"]` makes an app-only tool\n * (refresh, UI-only sort/filter; l.1490) that hosts MUST keep out of the agent's tool list.\n * OpenAI: ignored when the App is invoked as an entrypoint.\n */\n visibility?: ToolVisibility[];\n /**\n * Allow Claude host fonts (`hostContext.styles.css.fonts`): adds `https://assets.claude.ai` to\n * `csp.resourceDomains` (Claude transparent-theming page).\n */\n hostFonts?: boolean;\n}\n\nexport interface McpAppResourceMetaUi {\n csp: Required<McpAppCsp>;\n prefersBorder?: boolean;\n domain?: string;\n}\n\nexport interface McpAppResourceOutput {\n resource: {\n uri: `ui://${string}`;\n mimeType: typeof MCP_APP_MIME_TYPE;\n text: string;\n _meta: {\n ui: McpAppResourceMetaUi;\n \"openai/ui\"?: {\n availableDisplayModes?: ChatGptDisplayMode[];\n preferredDisplayMode?: ChatGptDisplayMode;\n };\n };\n };\n toolMeta: {\n ui: { resourceUri: `ui://${string}`; visibility?: ToolVisibility[] };\n \"openai/outputTemplate\"?: string;\n \"openai/ui\"?: { entrypoints: OpenAiEntrypoint[] };\n };\n}\n\n/**\n * Claude's stable app origin: `{sha256(mcpServerUrl) first 32 hex}.claudemcpcontent.com`.\n * Source: https://claude.com/docs/connectors/building/mcp-apps/getting-started, section\n * \"Set ui.domain for Claude\" (same derivation as the `@modelcontextprotocol/ext-apps/server`\n * example). Known answer: \"https://example.com/mcp\" ->\n * \"c3d80a4ed901ee05b21755a88273b4a4.claudemcpcontent.com\".\n */\nexport function deriveClaudeAppDomain(servedUrl: string): string {\n const hash = createHash(\"sha256\").update(servedUrl).digest(\"hex\").slice(0, 32);\n return `${hash}.claudemcpcontent.com`;\n}\n\nexport function buildMcpAppResource(input: McpAppResourceInput): McpAppResourceOutput {\n const { uri, html, csp, servedUrl, prefersBorder, openai, visibility, hostFonts } = input;\n const modes = [...(openai?.availableDisplayModes ?? []), openai?.preferredDisplayMode];\n if (modes.some((m) => (m as string | undefined) === \"pip\")) {\n throw new Error(\"buildMcpAppResource: display mode pip is refused (inline | fullscreen only)\");\n }\n\n let toolVisibility: ToolVisibility[] | undefined;\n if (visibility !== undefined) {\n const valid = visibility.every((v) => (v as string) === \"model\" || (v as string) === \"app\");\n if (visibility.length === 0 || !valid) {\n throw new Error(\n 'buildMcpAppResource: visibility must be a non-empty list of \"model\" | \"app\"',\n );\n }\n toolVisibility = [...new Set(visibility)];\n }\n const resourceDomains = [...(csp?.resourceDomains ?? [])];\n if (hostFonts && !resourceDomains.includes(CLAUDE_HOST_FONT_ORIGIN)) {\n resourceDomains.push(CLAUDE_HOST_FONT_ORIGIN);\n }\n\n const ui: McpAppResourceMetaUi = {\n csp: {\n connectDomains: csp?.connectDomains ?? [],\n resourceDomains,\n frameDomains: csp?.frameDomains ?? [],\n baseUriDomains: csp?.baseUriDomains ?? [],\n },\n ...(prefersBorder === undefined ? {} : { prefersBorder }),\n ...(servedUrl ? { domain: deriveClaudeAppDomain(servedUrl) } : {}),\n };\n\n // Standard key first, vendor keys after, only when passed.\n const resourceMeta: McpAppResourceOutput[\"resource\"][\"_meta\"] = { ui };\n if (openai?.availableDisplayModes !== undefined || openai?.preferredDisplayMode !== undefined) {\n resourceMeta[\"openai/ui\"] = {\n ...(openai.availableDisplayModes !== undefined\n ? { availableDisplayModes: openai.availableDisplayModes }\n : {}),\n ...(openai.preferredDisplayMode !== undefined\n ? { preferredDisplayMode: openai.preferredDisplayMode }\n : {}),\n };\n }\n\n const toolMeta: McpAppResourceOutput[\"toolMeta\"] = {\n ui: { resourceUri: uri, ...(toolVisibility ? { visibility: toolVisibility } : {}) },\n };\n if (openai?.outputTemplate !== undefined) {\n toolMeta[\"openai/outputTemplate\"] = openai.outputTemplate;\n }\n if (openai?.entrypoints !== undefined) {\n toolMeta[\"openai/ui\"] = { entrypoints: openai.entrypoints };\n }\n\n return {\n resource: { uri, mimeType: MCP_APP_MIME_TYPE, text: html, _meta: resourceMeta },\n toolMeta,\n };\n}\n"]}