sunpeak 0.18.2 → 0.18.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/commands/inspect.mjs +392 -4
- package/bin/lib/sandbox-server.mjs +11 -1
- package/dist/chatgpt/index.cjs +1 -1
- package/dist/chatgpt/index.js +1 -1
- package/dist/claude/index.cjs +1 -1
- package/dist/claude/index.js +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/use-request-teardown.d.ts +21 -0
- package/dist/host/chatgpt/index.cjs +1 -1
- package/dist/host/chatgpt/index.js +1 -1
- package/dist/index.cjs +110 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +68 -31
- package/dist/index.js.map +1 -1
- package/dist/inspector/hosts.d.ts +12 -0
- package/dist/inspector/index.cjs +1 -1
- package/dist/inspector/index.js +1 -1
- package/dist/inspector/mcp-app-host.d.ts +3 -0
- package/dist/inspector/simple-sidebar.d.ts +1 -1
- package/dist/inspector/use-mcp-connection.d.ts +9 -1
- package/dist/{inspector-ClhpqKLi.js → inspector-CjSoXm6N.js} +497 -117
- package/dist/inspector-CjSoXm6N.js.map +1 -0
- package/dist/{inspector-CByJjmPD.cjs → inspector-DRD_Q66E.cjs} +498 -118
- package/dist/inspector-DRD_Q66E.cjs.map +1 -0
- package/dist/mcp/index.cjs +38 -33
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +35 -30
- package/dist/mcp/index.js.map +1 -1
- package/dist/style.css +8 -0
- package/dist/{use-app-X7JbGskk.js → use-app-BNbz1uzj.js} +51 -42
- package/dist/use-app-BNbz1uzj.js.map +1 -0
- package/dist/{use-app-D2h-aiyr.cjs → use-app-Dqh20JPP.cjs} +93 -72
- package/dist/use-app-Dqh20JPP.cjs.map +1 -0
- package/package.json +2 -2
- package/template/dist/albums/albums.html +3 -3
- package/template/dist/albums/albums.json +1 -1
- package/template/dist/carousel/carousel.html +3 -3
- package/template/dist/carousel/carousel.json +1 -1
- package/template/dist/map/map.html +3 -3
- package/template/dist/map/map.json +1 -1
- package/template/dist/review/review.html +3 -3
- package/template/dist/review/review.json +1 -1
- package/template/node_modules/.vite/deps/_metadata.json +3 -3
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +51 -42
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +56 -50
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +52 -43
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -1
- package/template/node_modules/.vite-mcp/deps/_metadata.json +22 -22
- package/template/tests/e2e/albums.spec.ts +19 -15
- package/template/tests/live/albums.spec.ts +10 -0
- package/dist/inspector-CByJjmPD.cjs.map +0 -1
- package/dist/inspector-ClhpqKLi.js.map +0 -1
- package/dist/use-app-D2h-aiyr.cjs.map +0 -1
- package/dist/use-app-X7JbGskk.js.map +0 -1
|
@@ -486,7 +486,9 @@ function ClaudeConversation({ children, screenWidth, displayMode, platform, onRe
|
|
|
486
486
|
style: {
|
|
487
487
|
transform: "translate(0)",
|
|
488
488
|
backgroundColor: "var(--sim-bg-conversation, var(--color-background-primary))",
|
|
489
|
-
color: "var(--color-text-primary)"
|
|
489
|
+
color: "var(--color-text-primary)",
|
|
490
|
+
fontFamily: "var(--font-sans)",
|
|
491
|
+
WebkitFontSmoothing: "antialiased"
|
|
490
492
|
},
|
|
491
493
|
children: [
|
|
492
494
|
isFullscreen && /* @__PURE__ */ jsxs("div", {
|
|
@@ -520,17 +522,20 @@ function ClaudeConversation({ children, screenWidth, displayMode, platform, onRe
|
|
|
520
522
|
style: { backgroundColor: "var(--sim-bg-conversation, var(--color-background-primary))" },
|
|
521
523
|
children: /* @__PURE__ */ jsx("div", {
|
|
522
524
|
className: "max-w-[48rem] mx-auto",
|
|
523
|
-
children: /* @__PURE__ */ jsx("
|
|
524
|
-
|
|
525
|
-
name: "userInput",
|
|
526
|
-
disabled: true,
|
|
527
|
-
placeholder: "Reply to sunpeak...",
|
|
528
|
-
className: "w-full rounded-xl px-4 py-2.5 text-sm",
|
|
525
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
526
|
+
className: "relative rounded-[20px] px-4 py-2.5",
|
|
529
527
|
style: {
|
|
530
528
|
backgroundColor: "var(--sim-bg-reply-input, var(--color-background-secondary))",
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
529
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.035), 0 0 0 0.5px var(--color-border-tertiary)"
|
|
530
|
+
},
|
|
531
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
532
|
+
className: "w-full text-base outline-none opacity-50",
|
|
533
|
+
style: {
|
|
534
|
+
lineHeight: "1.4",
|
|
535
|
+
color: "var(--color-text-tertiary)"
|
|
536
|
+
},
|
|
537
|
+
children: "Reply to sunpeak..."
|
|
538
|
+
})
|
|
534
539
|
})
|
|
535
540
|
})
|
|
536
541
|
})
|
|
@@ -558,8 +563,14 @@ function ClaudeConversation({ children, screenWidth, displayMode, platform, onRe
|
|
|
558
563
|
children: /* @__PURE__ */ jsx("div", {
|
|
559
564
|
className: "max-w-[48rem] mx-auto flex justify-end",
|
|
560
565
|
children: /* @__PURE__ */ jsx("div", {
|
|
561
|
-
className: "inline-
|
|
562
|
-
style: {
|
|
566
|
+
className: "inline-flex rounded-xl max-w-[85%] break-words",
|
|
567
|
+
style: {
|
|
568
|
+
padding: "10px 16px",
|
|
569
|
+
lineHeight: "22.4px",
|
|
570
|
+
fontSize: "16px",
|
|
571
|
+
fontWeight: 430,
|
|
572
|
+
backgroundColor: "var(--sim-bg-user-bubble, var(--color-background-tertiary))"
|
|
573
|
+
},
|
|
563
574
|
children: userMessage
|
|
564
575
|
})
|
|
565
576
|
})
|
|
@@ -629,17 +640,18 @@ function ClaudeConversation({ children, screenWidth, displayMode, platform, onRe
|
|
|
629
640
|
children: /* @__PURE__ */ jsx("div", {
|
|
630
641
|
className: "max-w-[48rem] mx-auto px-4 py-4",
|
|
631
642
|
children: /* @__PURE__ */ jsx("div", {
|
|
632
|
-
className: "relative",
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
className: "w-full
|
|
643
|
+
className: "relative rounded-[20px] px-4 py-2.5",
|
|
644
|
+
style: {
|
|
645
|
+
backgroundColor: "var(--sim-bg-reply-input, var(--color-background-secondary))",
|
|
646
|
+
boxShadow: "0 4px 20px rgba(0, 0, 0, 0.035), 0 0 0 0.5px var(--color-border-tertiary)"
|
|
647
|
+
},
|
|
648
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
649
|
+
className: "w-full text-base outline-none opacity-50",
|
|
639
650
|
style: {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
651
|
+
lineHeight: "1.4",
|
|
652
|
+
color: "var(--color-text-tertiary)"
|
|
653
|
+
},
|
|
654
|
+
children: "Reply to sunpeak..."
|
|
643
655
|
})
|
|
644
656
|
})
|
|
645
657
|
})
|
|
@@ -650,17 +662,32 @@ function ClaudeConversation({ children, screenWidth, displayMode, platform, onRe
|
|
|
650
662
|
}
|
|
651
663
|
//#endregion
|
|
652
664
|
//#region src/claude/claude-host.ts
|
|
665
|
+
/**
|
|
666
|
+
* Claude host version info — matches what Claude reports via the MCP protocol.
|
|
667
|
+
* Verified against production Claude on 2026-03-25.
|
|
668
|
+
*/
|
|
653
669
|
var CLAUDE_HOST_INFO = {
|
|
654
670
|
name: "Claude",
|
|
655
671
|
version: "1.0.0"
|
|
656
672
|
};
|
|
673
|
+
/**
|
|
674
|
+
* Claude host capabilities — matches what Claude reports via the MCP protocol.
|
|
675
|
+
* Verified against production Claude on 2026-03-25.
|
|
676
|
+
*
|
|
677
|
+
* Notable: Claude supports downloadFile, updateModelContext.image, and
|
|
678
|
+
* message.text. serverTools and serverResources both report listChanged.
|
|
679
|
+
* No sandbox.permissions (no microphone etc.). No PiP display mode.
|
|
680
|
+
*/
|
|
657
681
|
var CLAUDE_HOST_CAPABILITIES = {
|
|
658
682
|
openLinks: {},
|
|
659
|
-
serverTools: {},
|
|
660
|
-
serverResources: {},
|
|
661
683
|
downloadFile: {},
|
|
684
|
+
serverTools: { listChanged: true },
|
|
685
|
+
serverResources: { listChanged: true },
|
|
662
686
|
logging: {},
|
|
663
|
-
updateModelContext: {
|
|
687
|
+
updateModelContext: {
|
|
688
|
+
text: {},
|
|
689
|
+
image: {}
|
|
690
|
+
},
|
|
664
691
|
message: { text: {} },
|
|
665
692
|
sandbox: {}
|
|
666
693
|
};
|
|
@@ -679,35 +706,100 @@ registerHostShell({
|
|
|
679
706
|
applyTheme: applyClaudeTheme,
|
|
680
707
|
hostInfo: CLAUDE_HOST_INFO,
|
|
681
708
|
hostCapabilities: CLAUDE_HOST_CAPABILITIES,
|
|
682
|
-
userAgent: "claude",
|
|
683
709
|
styleVariables: {
|
|
684
710
|
...DEFAULT_STYLE_VARIABLES,
|
|
685
|
-
"--color-background-primary": "light-dark(
|
|
686
|
-
"--color-background-secondary": "light-dark(
|
|
687
|
-
"--color-background-tertiary": "light-dark(
|
|
688
|
-
"--color-background-inverse": "light-dark(
|
|
689
|
-
"--color-
|
|
690
|
-
"--color-
|
|
691
|
-
"--color-
|
|
692
|
-
"--color-
|
|
693
|
-
"--color-
|
|
694
|
-
"--color-
|
|
695
|
-
"--color-
|
|
711
|
+
"--color-background-primary": "light-dark(rgba(255, 255, 255, 1), rgba(48, 48, 46, 1))",
|
|
712
|
+
"--color-background-secondary": "light-dark(rgba(245, 244, 237, 1), rgba(38, 38, 36, 1))",
|
|
713
|
+
"--color-background-tertiary": "light-dark(rgba(250, 249, 245, 1), rgba(20, 20, 19, 1))",
|
|
714
|
+
"--color-background-inverse": "light-dark(rgba(20, 20, 19, 1), rgba(250, 249, 245, 1))",
|
|
715
|
+
"--color-background-ghost": "light-dark(rgba(255, 255, 255, 0), rgba(48, 48, 46, 0))",
|
|
716
|
+
"--color-background-info": "light-dark(rgba(214, 228, 246, 1), rgba(37, 62, 95, 1))",
|
|
717
|
+
"--color-background-danger": "light-dark(rgba(247, 236, 236, 1), rgba(96, 42, 40, 1))",
|
|
718
|
+
"--color-background-success": "light-dark(rgba(233, 241, 220, 1), rgba(27, 70, 20, 1))",
|
|
719
|
+
"--color-background-warning": "light-dark(rgba(246, 238, 223, 1), rgba(72, 58, 15, 1))",
|
|
720
|
+
"--color-background-disabled": "light-dark(rgba(255, 255, 255, 0.5), rgba(48, 48, 46, 0.5))",
|
|
721
|
+
"--color-text-primary": "light-dark(rgba(20, 20, 19, 1), rgba(250, 249, 245, 1))",
|
|
722
|
+
"--color-text-secondary": "light-dark(rgba(61, 61, 58, 1), rgba(194, 192, 182, 1))",
|
|
723
|
+
"--color-text-tertiary": "light-dark(rgba(115, 114, 108, 1), rgba(156, 154, 146, 1))",
|
|
724
|
+
"--color-text-inverse": "light-dark(rgba(255, 255, 255, 1), rgba(20, 20, 19, 1))",
|
|
725
|
+
"--color-text-ghost": "light-dark(rgba(115, 114, 108, 0.5), rgba(156, 154, 146, 0.5))",
|
|
726
|
+
"--color-text-info": "light-dark(rgba(50, 102, 173, 1), rgba(128, 170, 221, 1))",
|
|
727
|
+
"--color-text-danger": "light-dark(rgba(127, 44, 40, 1), rgba(238, 136, 132, 1))",
|
|
728
|
+
"--color-text-success": "light-dark(rgba(38, 91, 25, 1), rgba(122, 185, 72, 1))",
|
|
729
|
+
"--color-text-warning": "light-dark(rgba(90, 72, 21, 1), rgba(209, 160, 65, 1))",
|
|
730
|
+
"--color-text-disabled": "light-dark(rgba(20, 20, 19, 0.5), rgba(250, 249, 245, 0.5))",
|
|
731
|
+
"--color-border-primary": "light-dark(rgba(31, 30, 29, 0.4), rgba(222, 220, 209, 0.4))",
|
|
732
|
+
"--color-border-secondary": "light-dark(rgba(31, 30, 29, 0.3), rgba(222, 220, 209, 0.3))",
|
|
733
|
+
"--color-border-tertiary": "light-dark(rgba(31, 30, 29, 0.15), rgba(222, 220, 209, 0.15))",
|
|
734
|
+
"--color-border-inverse": "light-dark(rgba(255, 255, 255, 0.3), rgba(20, 20, 19, 0.15))",
|
|
735
|
+
"--color-border-ghost": "light-dark(rgba(31, 30, 29, 0), rgba(222, 220, 209, 0))",
|
|
736
|
+
"--color-border-info": "light-dark(rgba(70, 130, 213, 1), rgba(70, 130, 213, 1))",
|
|
737
|
+
"--color-border-danger": "light-dark(rgba(167, 61, 57, 1), rgba(205, 92, 88, 1))",
|
|
738
|
+
"--color-border-success": "light-dark(rgba(67, 116, 38, 1), rgba(89, 145, 48, 1))",
|
|
739
|
+
"--color-border-warning": "light-dark(rgba(128, 92, 31, 1), rgba(168, 120, 41, 1))",
|
|
740
|
+
"--color-border-disabled": "light-dark(rgba(31, 30, 29, 0.1), rgba(222, 220, 209, 0.1))",
|
|
741
|
+
"--color-ring-primary": "light-dark(rgba(20, 20, 19, 0.7), rgba(250, 249, 245, 0.7))",
|
|
742
|
+
"--color-ring-secondary": "light-dark(rgba(61, 61, 58, 0.7), rgba(194, 192, 182, 0.7))",
|
|
743
|
+
"--color-ring-inverse": "light-dark(rgba(255, 255, 255, 0.7), rgba(20, 20, 19, 0.7))",
|
|
744
|
+
"--color-ring-info": "light-dark(rgba(50, 102, 173, 0.5), rgba(128, 170, 221, 0.5))",
|
|
745
|
+
"--color-ring-danger": "light-dark(rgba(167, 61, 57, 0.5), rgba(205, 92, 88, 0.5))",
|
|
746
|
+
"--color-ring-success": "light-dark(rgba(67, 116, 38, 0.5), rgba(89, 145, 48, 0.5))",
|
|
747
|
+
"--color-ring-warning": "light-dark(rgba(128, 92, 31, 0.5), rgba(168, 120, 41, 0.5))",
|
|
748
|
+
"--font-sans": "\"Anthropic Sans\", system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif",
|
|
749
|
+
"--font-mono": "ui-monospace, monospace",
|
|
750
|
+
"--font-text-xs-size": "12px",
|
|
751
|
+
"--font-text-sm-size": "14px",
|
|
752
|
+
"--font-text-md-size": "16px",
|
|
753
|
+
"--font-text-lg-size": "20px",
|
|
754
|
+
"--font-heading-xs-size": "12px",
|
|
755
|
+
"--font-heading-sm-size": "14px",
|
|
756
|
+
"--font-heading-md-size": "16px",
|
|
757
|
+
"--font-heading-lg-size": "20px",
|
|
758
|
+
"--font-heading-xl-size": "24px",
|
|
759
|
+
"--font-heading-2xl-size": "28px",
|
|
760
|
+
"--font-heading-3xl-size": "36px",
|
|
761
|
+
"--font-text-md-line-height": "1.4",
|
|
762
|
+
"--font-text-lg-line-height": "1.25",
|
|
763
|
+
"--font-heading-lg-line-height": "1.25",
|
|
764
|
+
"--font-heading-2xl-line-height": "1.1",
|
|
765
|
+
"--font-heading-3xl-line-height": "1",
|
|
766
|
+
"--border-radius-xs": "4px",
|
|
767
|
+
"--border-radius-sm": "6px",
|
|
768
|
+
"--border-radius-md": "8px",
|
|
769
|
+
"--border-radius-lg": "10px",
|
|
770
|
+
"--border-width-regular": "0.5px"
|
|
696
771
|
},
|
|
697
772
|
pageStyles: {
|
|
698
|
-
"--sim-bg-sidebar": "light-dark(
|
|
699
|
-
"--sim-bg-conversation": "light-dark(
|
|
700
|
-
"--sim-bg-user-bubble": "light-dark(
|
|
701
|
-
"--sim-bg-reply-input": "light-dark(
|
|
702
|
-
}
|
|
773
|
+
"--sim-bg-sidebar": "light-dark(rgb(250, 249, 245), rgb(38, 38, 36))",
|
|
774
|
+
"--sim-bg-conversation": "light-dark(rgb(250, 249, 245), rgb(38, 38, 36))",
|
|
775
|
+
"--sim-bg-user-bubble": "light-dark(rgb(240, 238, 230), rgb(20, 20, 19))",
|
|
776
|
+
"--sim-bg-reply-input": "light-dark(rgb(255, 255, 255), rgb(48, 48, 46))"
|
|
777
|
+
},
|
|
778
|
+
availableDisplayModes: ["inline", "fullscreen"],
|
|
779
|
+
fontCss: `@font-face {
|
|
780
|
+
font-family: "Anthropic Sans";
|
|
781
|
+
src: url("https://assets-proxy.anthropic.com/claude-ai/v2/assets/v1/cc27851ad-CFxw3nG7.woff2") format("woff2");
|
|
782
|
+
font-weight: 300 800;
|
|
783
|
+
font-style: normal;
|
|
784
|
+
font-display: swap;
|
|
785
|
+
font-feature-settings: "dlig" 0;
|
|
786
|
+
}
|
|
787
|
+
@font-face {
|
|
788
|
+
font-family: "Anthropic Sans";
|
|
789
|
+
src: url("https://assets-proxy.anthropic.com/claude-ai/v2/assets/v1/c9d3a3a49-BI1hrwN4.woff2") format("woff2");
|
|
790
|
+
font-weight: 300 800;
|
|
791
|
+
font-style: italic;
|
|
792
|
+
font-display: swap;
|
|
793
|
+
font-feature-settings: "dlig" 0;
|
|
794
|
+
}`
|
|
703
795
|
});
|
|
704
796
|
//#endregion
|
|
705
|
-
//#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.
|
|
706
|
-
var G = "2026-01-26",
|
|
797
|
+
//#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.3.1_@modelcontextprotocol+sdk@1.27.1_zod@4.3.6__react-_cd1fb28fd87e0bddd0a29eba0721855d/node_modules/@modelcontextprotocol/ext-apps/dist/src/app-bridge.js
|
|
798
|
+
var G = "2026-01-26", p = union([literal("light"), literal("dark")]).describe("Color theme preference for the host environment."), D = union([
|
|
707
799
|
literal("inline"),
|
|
708
800
|
literal("fullscreen"),
|
|
709
801
|
literal("pip")
|
|
710
|
-
]).describe("Display mode for UI presentation."),
|
|
802
|
+
]).describe("Display mode for UI presentation."), AQ = record(union([
|
|
711
803
|
literal("--color-background-primary"),
|
|
712
804
|
literal("--color-background-secondary"),
|
|
713
805
|
literal("--color-background-tertiary"),
|
|
@@ -809,7 +901,7 @@ for compatibility with Zod schema generation. Both are functionally equivalent f
|
|
|
809
901
|
object({ isError: boolean().optional().describe("True if the host failed to open the URL (e.g., due to security policy).") }).passthrough();
|
|
810
902
|
object({ isError: boolean().optional().describe("True if the download failed (e.g., user cancelled or host denied).") }).passthrough();
|
|
811
903
|
object({ isError: boolean().optional().describe("True if the host rejected or failed to deliver the message.") }).passthrough();
|
|
812
|
-
var
|
|
904
|
+
var L = object({
|
|
813
905
|
method: literal("ui/notifications/sandbox-proxy-ready"),
|
|
814
906
|
params: object({})
|
|
815
907
|
}), j = object({
|
|
@@ -844,22 +936,25 @@ object({
|
|
|
844
936
|
method: literal("ui/notifications/tool-cancelled"),
|
|
845
937
|
params: object({ reason: string().optional().describe("Optional reason for the cancellation (e.g., \"user action\", \"timeout\").") })
|
|
846
938
|
});
|
|
847
|
-
var
|
|
848
|
-
variables:
|
|
849
|
-
css:
|
|
939
|
+
var c = object({ fonts: string().optional() }), n = object({
|
|
940
|
+
variables: AQ.optional().describe("CSS variables for theming the app."),
|
|
941
|
+
css: c.optional().describe("CSS blocks that apps can inject.")
|
|
850
942
|
});
|
|
851
943
|
object({
|
|
852
944
|
method: literal("ui/resource-teardown"),
|
|
853
945
|
params: object({})
|
|
854
946
|
});
|
|
855
|
-
var
|
|
947
|
+
var H = record(string(), unknown()), O = object({
|
|
856
948
|
text: object({}).optional().describe("Host supports text content blocks."),
|
|
857
949
|
image: object({}).optional().describe("Host supports image content blocks."),
|
|
858
950
|
audio: object({}).optional().describe("Host supports audio content blocks."),
|
|
859
951
|
resource: object({}).optional().describe("Host supports resource content blocks."),
|
|
860
952
|
resourceLink: object({}).optional().describe("Host supports resource link content blocks."),
|
|
861
953
|
structuredContent: object({}).optional().describe("Host supports structured content.")
|
|
862
|
-
}),
|
|
954
|
+
}), M = object({
|
|
955
|
+
method: literal("ui/notifications/request-teardown"),
|
|
956
|
+
params: object({}).optional()
|
|
957
|
+
}), i = object({
|
|
863
958
|
experimental: object({}).optional().describe("Experimental features (structure TBD)."),
|
|
864
959
|
openLinks: object({}).optional().describe("Host supports opening external URLs."),
|
|
865
960
|
downloadFile: object({}).optional().describe("Host supports file downloads via ui/download-file."),
|
|
@@ -872,11 +967,11 @@ var R = record(string(), unknown()), O = object({
|
|
|
872
967
|
}).optional().describe("Sandbox configuration applied by the host."),
|
|
873
968
|
updateModelContext: O.optional().describe("Host accepts context updates (ui/update-model-context) to be included in the model's context for future turns."),
|
|
874
969
|
message: O.optional().describe("Host supports receiving content messages (ui/message) from the view.")
|
|
875
|
-
}),
|
|
970
|
+
}), l = object({
|
|
876
971
|
experimental: object({}).optional().describe("Experimental features (structure TBD)."),
|
|
877
972
|
tools: object({ listChanged: boolean().optional().describe("App supports tools/list_changed notifications.") }).optional().describe("App exposes MCP-style tools that the host can call."),
|
|
878
973
|
availableDisplayModes: array(D).optional().describe("Display modes the app supports.")
|
|
879
|
-
}),
|
|
974
|
+
}), v = object({
|
|
880
975
|
method: literal("ui/notifications/initialized"),
|
|
881
976
|
params: object({}).optional()
|
|
882
977
|
});
|
|
@@ -905,18 +1000,18 @@ var W = object({
|
|
|
905
1000
|
params: object({ mode: D.describe("The display mode being requested.") })
|
|
906
1001
|
});
|
|
907
1002
|
object({ mode: D.describe("The display mode that was actually set. May differ from requested if not supported.") }).passthrough();
|
|
908
|
-
var
|
|
1003
|
+
var r = union([literal("model"), literal("app")]).describe("Tool visibility scope - who can access the tool.");
|
|
909
1004
|
object({
|
|
910
1005
|
resourceUri: string().optional(),
|
|
911
|
-
visibility: array(
|
|
1006
|
+
visibility: array(r).optional().describe(`Who can access this tool. Default: ["model", "app"]
|
|
912
1007
|
- "model": Tool visible to and callable by the agent
|
|
913
1008
|
- "app": Tool callable by the app from this server only`)
|
|
914
1009
|
});
|
|
915
1010
|
object({ mimeTypes: array(string()).optional().describe("Array of supported MIME types for UI resources.\nMust include `\"text/html;profile=mcp-app\"` for MCP Apps support.") });
|
|
916
|
-
var
|
|
1011
|
+
var C = object({
|
|
917
1012
|
method: literal("ui/download-file"),
|
|
918
1013
|
params: object({ contents: array(union([EmbeddedResourceSchema, ResourceLinkSchema])).describe("Resource contents to download — embedded (inline data) or linked (host fetches). Uses standard MCP resource types.") })
|
|
919
|
-
}),
|
|
1014
|
+
}), S = object({
|
|
920
1015
|
method: literal("ui/message"),
|
|
921
1016
|
params: object({
|
|
922
1017
|
role: literal("user").describe("Message role, currently only \"user\" is supported."),
|
|
@@ -936,13 +1031,13 @@ object({
|
|
|
936
1031
|
method: literal("ui/notifications/tool-result"),
|
|
937
1032
|
params: CallToolResultSchema.describe("Standard MCP tool execution result.")
|
|
938
1033
|
});
|
|
939
|
-
var
|
|
1034
|
+
var y = object({
|
|
940
1035
|
toolInfo: object({
|
|
941
1036
|
id: RequestIdSchema.optional().describe("JSON-RPC id of the tools/call request."),
|
|
942
1037
|
tool: ToolSchema.describe("Tool definition including name, inputSchema, etc.")
|
|
943
1038
|
}).optional().describe("Metadata of the tool call that instantiated this App."),
|
|
944
|
-
theme:
|
|
945
|
-
styles:
|
|
1039
|
+
theme: p.optional().describe("Current color theme preference."),
|
|
1040
|
+
styles: n.optional().describe("Style configuration for theming the app."),
|
|
946
1041
|
displayMode: D.optional().describe("How the UI is currently displayed."),
|
|
947
1042
|
availableDisplayModes: array(D).optional().describe("Display modes the host supports."),
|
|
948
1043
|
containerDimensions: union([object({ height: number().describe("Fixed container height in pixels.") }), object({ maxHeight: union([number(), _undefined()]).optional().describe("Maximum container height in pixels.") })]).and(union([object({ width: number().describe("Fixed container width in pixels.") }), object({ maxWidth: union([number(), _undefined()]).optional().describe("Maximum container width in pixels.") })])).optional().describe(`Container dimensions. Represents the dimensions of the iframe or other
|
|
@@ -968,27 +1063,27 @@ container holding the app. Specify either width or maxWidth, and either height o
|
|
|
968
1063
|
}).passthrough();
|
|
969
1064
|
object({
|
|
970
1065
|
method: literal("ui/notifications/host-context-changed"),
|
|
971
|
-
params:
|
|
1066
|
+
params: y.describe("Partial context update containing only changed fields.")
|
|
972
1067
|
});
|
|
973
|
-
var
|
|
1068
|
+
var f = object({
|
|
974
1069
|
method: literal("ui/update-model-context"),
|
|
975
1070
|
params: object({
|
|
976
1071
|
content: array(ContentBlockSchema).optional().describe("Context content blocks (text, image, etc.)."),
|
|
977
1072
|
structuredContent: record(string(), unknown().describe("Structured content for machine-readable context data.")).optional().describe("Structured content for machine-readable context data.")
|
|
978
1073
|
})
|
|
979
|
-
}),
|
|
1074
|
+
}), d = object({
|
|
980
1075
|
method: literal("ui/initialize"),
|
|
981
1076
|
params: object({
|
|
982
1077
|
appInfo: ImplementationSchema.describe("App identification (name and version)."),
|
|
983
|
-
appCapabilities:
|
|
1078
|
+
appCapabilities: l.describe("Features and capabilities this app provides."),
|
|
984
1079
|
protocolVersion: string().describe("Protocol version this app supports.")
|
|
985
1080
|
})
|
|
986
1081
|
});
|
|
987
1082
|
object({
|
|
988
1083
|
protocolVersion: string().describe("Negotiated protocol version string (e.g., \"2025-11-21\")."),
|
|
989
1084
|
hostInfo: ImplementationSchema.describe("Host application identification and version."),
|
|
990
|
-
hostCapabilities:
|
|
991
|
-
hostContext:
|
|
1085
|
+
hostCapabilities: i.describe("Features and capabilities provided by the host."),
|
|
1086
|
+
hostContext: y.describe("Rich context about the host environment.")
|
|
992
1087
|
}).passthrough();
|
|
993
1088
|
var N = class {
|
|
994
1089
|
eventTarget;
|
|
@@ -1024,8 +1119,8 @@ var N = class {
|
|
|
1024
1119
|
sessionId;
|
|
1025
1120
|
setProtocolVersion;
|
|
1026
1121
|
};
|
|
1027
|
-
var
|
|
1028
|
-
var
|
|
1122
|
+
var aQ = [G];
|
|
1123
|
+
var tQ = class extends Protocol {
|
|
1029
1124
|
_client;
|
|
1030
1125
|
_hostInfo;
|
|
1031
1126
|
_capabilities;
|
|
@@ -1037,7 +1132,7 @@ var oQ = class extends Protocol {
|
|
|
1037
1132
|
this._client = X;
|
|
1038
1133
|
this._hostInfo = Y;
|
|
1039
1134
|
this._capabilities = Z;
|
|
1040
|
-
this._hostContext = $?.hostContext || {}, this.setRequestHandler(
|
|
1135
|
+
this._hostContext = $?.hostContext || {}, this.setRequestHandler(d, (K) => this._oninitialize(K)), this.setRequestHandler(PingRequestSchema, (K, J) => {
|
|
1041
1136
|
return this.onping?.(K.params, J), {};
|
|
1042
1137
|
}), this.setRequestHandler(W, (K) => {
|
|
1043
1138
|
return { mode: this._hostContext.displayMode ?? "inline" };
|
|
@@ -1054,13 +1149,13 @@ var oQ = class extends Protocol {
|
|
|
1054
1149
|
this.setNotificationHandler(P, (Y) => X(Y.params));
|
|
1055
1150
|
}
|
|
1056
1151
|
set onsandboxready(X) {
|
|
1057
|
-
this.setNotificationHandler(
|
|
1152
|
+
this.setNotificationHandler(L, (Y) => X(Y.params));
|
|
1058
1153
|
}
|
|
1059
1154
|
set oninitialized(X) {
|
|
1060
|
-
this.setNotificationHandler(
|
|
1155
|
+
this.setNotificationHandler(v, (Y) => X(Y.params));
|
|
1061
1156
|
}
|
|
1062
1157
|
set onmessage(X) {
|
|
1063
|
-
this.setRequestHandler(
|
|
1158
|
+
this.setRequestHandler(S, async (Y, Z) => {
|
|
1064
1159
|
return X(Y.params, Z);
|
|
1065
1160
|
});
|
|
1066
1161
|
}
|
|
@@ -1070,10 +1165,13 @@ var oQ = class extends Protocol {
|
|
|
1070
1165
|
});
|
|
1071
1166
|
}
|
|
1072
1167
|
set ondownloadfile(X) {
|
|
1073
|
-
this.setRequestHandler(
|
|
1168
|
+
this.setRequestHandler(C, async (Y, Z) => {
|
|
1074
1169
|
return X(Y.params, Z);
|
|
1075
1170
|
});
|
|
1076
1171
|
}
|
|
1172
|
+
set onrequestteardown(X) {
|
|
1173
|
+
this.setNotificationHandler(M, (Y) => X(Y.params));
|
|
1174
|
+
}
|
|
1077
1175
|
set onrequestdisplaymode(X) {
|
|
1078
1176
|
this.setRequestHandler(W, async (Y, Z) => {
|
|
1079
1177
|
return X(Y.params, Z);
|
|
@@ -1085,7 +1183,7 @@ var oQ = class extends Protocol {
|
|
|
1085
1183
|
});
|
|
1086
1184
|
}
|
|
1087
1185
|
set onupdatemodelcontext(X) {
|
|
1088
|
-
this.setRequestHandler(
|
|
1186
|
+
this.setRequestHandler(f, async (Y, Z) => {
|
|
1089
1187
|
return X(Y.params, Z);
|
|
1090
1188
|
});
|
|
1091
1189
|
}
|
|
@@ -1147,7 +1245,7 @@ var oQ = class extends Protocol {
|
|
|
1147
1245
|
async _oninitialize(X) {
|
|
1148
1246
|
let Y = X.params.protocolVersion;
|
|
1149
1247
|
return this._appCapabilities = X.params.appCapabilities, this._appInfo = X.params.appInfo, {
|
|
1150
|
-
protocolVersion:
|
|
1248
|
+
protocolVersion: aQ.includes(Y) ? Y : G,
|
|
1151
1249
|
hostCapabilities: this.getCapabilities(),
|
|
1152
1250
|
hostInfo: this._hostInfo,
|
|
1153
1251
|
hostContext: this._hostContext
|
|
@@ -1157,7 +1255,7 @@ var oQ = class extends Protocol {
|
|
|
1157
1255
|
let Y = {}, Z = !1;
|
|
1158
1256
|
for (let $ of Object.keys(X)) {
|
|
1159
1257
|
let K = this._hostContext[$], J = X[$];
|
|
1160
|
-
if (
|
|
1258
|
+
if (sQ(K, J)) continue;
|
|
1161
1259
|
Y[$] = J, Z = !0;
|
|
1162
1260
|
}
|
|
1163
1261
|
if (Z) this._hostContext = X, this.sendHostContextChange(Y);
|
|
@@ -1202,7 +1300,7 @@ var oQ = class extends Protocol {
|
|
|
1202
1300
|
return this.request({
|
|
1203
1301
|
method: "ui/resource-teardown",
|
|
1204
1302
|
params: X
|
|
1205
|
-
},
|
|
1303
|
+
}, H, Y);
|
|
1206
1304
|
}
|
|
1207
1305
|
sendResourceTeardown = this.teardownResource;
|
|
1208
1306
|
async connect(X) {
|
|
@@ -1248,7 +1346,7 @@ var oQ = class extends Protocol {
|
|
|
1248
1346
|
return super.connect(X);
|
|
1249
1347
|
}
|
|
1250
1348
|
};
|
|
1251
|
-
function
|
|
1349
|
+
function sQ(X, Y) {
|
|
1252
1350
|
return JSON.stringify(X) === JSON.stringify(Y);
|
|
1253
1351
|
}
|
|
1254
1352
|
//#endregion
|
|
@@ -1282,10 +1380,11 @@ var McpAppHost = class {
|
|
|
1282
1380
|
_prevDisplayMode;
|
|
1283
1381
|
_pendingToolInput = null;
|
|
1284
1382
|
_pendingToolResult = null;
|
|
1383
|
+
_messageListener = null;
|
|
1285
1384
|
constructor(options = {}) {
|
|
1286
1385
|
this.options = options;
|
|
1287
1386
|
this._prevDisplayMode = options.hostContext?.displayMode;
|
|
1288
|
-
this.bridge = new
|
|
1387
|
+
this.bridge = new tQ(null, options.hostInfo ?? DEFAULT_HOST_INFO, options.hostCapabilities ?? DEFAULT_HOST_CAPABILITIES, { hostContext: options.hostContext });
|
|
1289
1388
|
this.bridge.oninitialized = () => {
|
|
1290
1389
|
this._initialized = true;
|
|
1291
1390
|
if (this._pendingToolInput) {
|
|
@@ -1298,38 +1397,35 @@ var McpAppHost = class {
|
|
|
1298
1397
|
}
|
|
1299
1398
|
};
|
|
1300
1399
|
this.bridge.onopenlink = async ({ url }) => {
|
|
1301
|
-
console.log("[MCP App] openLink:", url);
|
|
1302
1400
|
if (this.options.onOpenLink) this.options.onOpenLink(url);
|
|
1303
|
-
else {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
}
|
|
1310
|
-
} catch {
|
|
1311
|
-
console.warn("[MCP App] openLink blocked invalid URL:", url);
|
|
1312
|
-
return {};
|
|
1313
|
-
}
|
|
1314
|
-
window.open(url, "_blank");
|
|
1401
|
+
else try {
|
|
1402
|
+
const parsed = new URL(url);
|
|
1403
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") console.warn("[MCP App] openLink blocked non-http(s) URL:", url);
|
|
1404
|
+
else window.open(url, "_blank");
|
|
1405
|
+
} catch {
|
|
1406
|
+
console.warn("[MCP App] openLink blocked invalid URL:", url);
|
|
1315
1407
|
}
|
|
1316
|
-
|
|
1408
|
+
const ack = {};
|
|
1409
|
+
console.log(`%c[MCP ↓]%c host → app: %copenLink ack`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", ack);
|
|
1410
|
+
return ack;
|
|
1317
1411
|
};
|
|
1318
1412
|
this.bridge.onmessage = async ({ role, content }) => {
|
|
1319
1413
|
if (this.options.onMessage) this.options.onMessage(role, content);
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
});
|
|
1324
|
-
return {};
|
|
1414
|
+
const ack = {};
|
|
1415
|
+
console.log(`%c[MCP ↓]%c host → app: %csendMessage ack`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", ack);
|
|
1416
|
+
return ack;
|
|
1325
1417
|
};
|
|
1326
1418
|
this.bridge.onrequestdisplaymode = async ({ mode }) => {
|
|
1327
1419
|
this.options.onDisplayModeChange?.(mode);
|
|
1328
|
-
|
|
1420
|
+
const result = { mode };
|
|
1421
|
+
console.log(`%c[MCP ↓]%c host → app: %crequestDisplayMode result`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", result);
|
|
1422
|
+
return result;
|
|
1329
1423
|
};
|
|
1330
1424
|
this.bridge.onupdatemodelcontext = async ({ content, structuredContent }) => {
|
|
1331
1425
|
this.options.onUpdateModelContext?.(content ?? [], structuredContent);
|
|
1332
|
-
|
|
1426
|
+
const ack = {};
|
|
1427
|
+
console.log(`%c[MCP ↓]%c host → app: %cupdateModelContext ack`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", ack);
|
|
1428
|
+
return ack;
|
|
1333
1429
|
};
|
|
1334
1430
|
this.bridge.onsizechange = (params) => {
|
|
1335
1431
|
this.options.onSizeChanged?.(params);
|
|
@@ -1346,17 +1442,24 @@ var McpAppHost = class {
|
|
|
1346
1442
|
}
|
|
1347
1443
|
};
|
|
1348
1444
|
this.bridge.oncalltool = async (params) => {
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1445
|
+
let result;
|
|
1446
|
+
if (this.options.onCallTool) result = await this.options.onCallTool(params);
|
|
1447
|
+
else result = { content: [{
|
|
1352
1448
|
type: "text",
|
|
1353
1449
|
text: `[Inspector] Tool "${params.name}" called (no handler configured)`
|
|
1354
1450
|
}] };
|
|
1451
|
+
console.log(`%c[MCP ↓]%c host → app: %ccallServerTool result(${params.name})`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", result);
|
|
1452
|
+
return result;
|
|
1355
1453
|
};
|
|
1356
1454
|
this.bridge.ondownloadfile = async ({ contents }) => {
|
|
1357
1455
|
if (this.options.onDownloadFile) this.options.onDownloadFile(contents);
|
|
1358
|
-
|
|
1359
|
-
|
|
1456
|
+
const ack = {};
|
|
1457
|
+
console.log(`%c[MCP ↓]%c host → app: %cdownloadFile ack`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", ack);
|
|
1458
|
+
return ack;
|
|
1459
|
+
};
|
|
1460
|
+
this.bridge.onrequestteardown = () => {
|
|
1461
|
+
if (this.options.onRequestTeardown) this.options.onRequestTeardown();
|
|
1462
|
+
else console.log("[MCP App] requestTeardown (app requested close)");
|
|
1360
1463
|
};
|
|
1361
1464
|
this.bridge.onsandboxready = () => {
|
|
1362
1465
|
this.options.onSandboxReady?.();
|
|
@@ -1366,7 +1469,18 @@ var McpAppHost = class {
|
|
|
1366
1469
|
* Connect to an iframe's contentWindow.
|
|
1367
1470
|
*/
|
|
1368
1471
|
async connectToIframe(contentWindow) {
|
|
1472
|
+
if (this._messageListener) window.removeEventListener("message", this._messageListener);
|
|
1369
1473
|
this._contentWindow = contentWindow;
|
|
1474
|
+
this._messageListener = (event) => {
|
|
1475
|
+
if (event.source !== contentWindow) return;
|
|
1476
|
+
const data = event.data;
|
|
1477
|
+
if (!data || typeof data !== "object") return;
|
|
1478
|
+
const method = data.method;
|
|
1479
|
+
if (method?.startsWith("sunpeak/") || method === "ui/notifications/sandbox-proxy-ready") return;
|
|
1480
|
+
const label = method ?? (data.id != null ? `response #${data.id}` : "unknown");
|
|
1481
|
+
console.log(`%c[MCP ↑]%c app → host: %c${label}`, "color:#6ee7b7", "color:inherit", "color:#93c5fd", data);
|
|
1482
|
+
};
|
|
1483
|
+
window.addEventListener("message", this._messageListener);
|
|
1370
1484
|
const transport = new N(contentWindow, contentWindow);
|
|
1371
1485
|
await this.bridge.connect(transport);
|
|
1372
1486
|
}
|
|
@@ -1401,11 +1515,12 @@ var McpAppHost = class {
|
|
|
1401
1515
|
this._fenceCleanup = cleanup;
|
|
1402
1516
|
window.addEventListener("message", handler);
|
|
1403
1517
|
try {
|
|
1404
|
-
|
|
1518
|
+
const fenceMsg = {
|
|
1405
1519
|
jsonrpc: "2.0",
|
|
1406
1520
|
method: "sunpeak/fence",
|
|
1407
1521
|
params: { fenceId: id }
|
|
1408
|
-
}
|
|
1522
|
+
};
|
|
1523
|
+
win.postMessage(fenceMsg, "*");
|
|
1409
1524
|
} catch {
|
|
1410
1525
|
cleanup();
|
|
1411
1526
|
resolve();
|
|
@@ -1418,6 +1533,7 @@ var McpAppHost = class {
|
|
|
1418
1533
|
* to commit its DOM before firing onDisplayModeReady.
|
|
1419
1534
|
*/
|
|
1420
1535
|
setHostContext(context) {
|
|
1536
|
+
console.log(`%c[MCP ↓]%c host → app: %csetHostContext`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", context);
|
|
1421
1537
|
this.bridge.setHostContext(context);
|
|
1422
1538
|
const currentMode = context.displayMode;
|
|
1423
1539
|
if (currentMode && currentMode !== this._prevDisplayMode) {
|
|
@@ -1434,6 +1550,7 @@ var McpAppHost = class {
|
|
|
1434
1550
|
*/
|
|
1435
1551
|
sendToolInput(args) {
|
|
1436
1552
|
const params = { arguments: args };
|
|
1553
|
+
console.log(`%c[MCP ↓]%c host → app: %csendToolInput`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", params);
|
|
1437
1554
|
if (this._initialized) this.bridge.sendToolInput(params);
|
|
1438
1555
|
else this._pendingToolInput = params;
|
|
1439
1556
|
}
|
|
@@ -1442,6 +1559,7 @@ var McpAppHost = class {
|
|
|
1442
1559
|
* If the app hasn't initialized yet, the result is queued.
|
|
1443
1560
|
*/
|
|
1444
1561
|
sendToolResult(result) {
|
|
1562
|
+
console.log(`%c[MCP ↓]%c host → app: %csendToolResult`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", result);
|
|
1445
1563
|
if (this._initialized) this.bridge.sendToolResult(result);
|
|
1446
1564
|
else this._pendingToolResult = result;
|
|
1447
1565
|
}
|
|
@@ -1451,6 +1569,7 @@ var McpAppHost = class {
|
|
|
1451
1569
|
*/
|
|
1452
1570
|
sendToolInputPartial(args) {
|
|
1453
1571
|
const params = { arguments: args };
|
|
1572
|
+
console.log(`%c[MCP ↓]%c host → app: %csendToolInputPartial`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", params);
|
|
1454
1573
|
if (this._initialized) this.bridge.sendToolInputPartial(params);
|
|
1455
1574
|
}
|
|
1456
1575
|
/**
|
|
@@ -1459,6 +1578,7 @@ var McpAppHost = class {
|
|
|
1459
1578
|
*/
|
|
1460
1579
|
sendToolCancelled(reason) {
|
|
1461
1580
|
const params = reason ? { reason } : {};
|
|
1581
|
+
console.log(`%c[MCP ↓]%c host → app: %csendToolCancelled`, "color:#f9a8d4", "color:inherit", "color:#93c5fd", params);
|
|
1462
1582
|
if (this._initialized) this.bridge.sendToolCancelled(params);
|
|
1463
1583
|
}
|
|
1464
1584
|
/**
|
|
@@ -1482,6 +1602,10 @@ var McpAppHost = class {
|
|
|
1482
1602
|
* Close the connection.
|
|
1483
1603
|
*/
|
|
1484
1604
|
async close() {
|
|
1605
|
+
if (this._messageListener) {
|
|
1606
|
+
window.removeEventListener("message", this._messageListener);
|
|
1607
|
+
this._messageListener = null;
|
|
1608
|
+
}
|
|
1485
1609
|
this._fenceCleanup?.();
|
|
1486
1610
|
this._fenceCleanup = null;
|
|
1487
1611
|
try {
|
|
@@ -1592,7 +1716,7 @@ function generateSandboxProxyHtml(platformScript) {
|
|
|
1592
1716
|
<head>
|
|
1593
1717
|
<meta name="color-scheme" content="${colorScheme}" />
|
|
1594
1718
|
<style>
|
|
1595
|
-
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; }
|
|
1719
|
+
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: transparent; }
|
|
1596
1720
|
iframe { border: none; width: 100%; height: 100%; display: block; }
|
|
1597
1721
|
</style>
|
|
1598
1722
|
</head>
|
|
@@ -1655,6 +1779,16 @@ iframe { border: none; width: 100%; height: 100%; display: block; }
|
|
|
1655
1779
|
return;
|
|
1656
1780
|
}
|
|
1657
1781
|
|
|
1782
|
+
// Sync color-scheme on the inner iframe element when theme changes.
|
|
1783
|
+
// This ensures prefers-color-scheme resolves correctly inside the app.
|
|
1784
|
+
// Important: do NOT set color-scheme on the proxy's own document —
|
|
1785
|
+
// changing it from the initial 'dark' causes Chrome to re-evaluate
|
|
1786
|
+
// the CSS Canvas as opaque white, blocking the host's conversation
|
|
1787
|
+
// background from showing through the transparent proxy.
|
|
1788
|
+
if (data.method === 'ui/notifications/host-context-changed' && data.params && data.params.theme) {
|
|
1789
|
+
if (innerFrame) innerFrame.style.colorScheme = data.params.theme;
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1658
1792
|
// Forward all other messages to the inner iframe
|
|
1659
1793
|
if (innerWindow) {
|
|
1660
1794
|
try { innerWindow.postMessage(data, '*'); } catch(e) { /* detached */ }
|
|
@@ -2507,15 +2641,17 @@ function useMcpConnection(initialServerUrl) {
|
|
|
2507
2641
|
const [error, setError] = useState();
|
|
2508
2642
|
const [simulations, setSimulations] = useState();
|
|
2509
2643
|
const [hasReconnected, setHasReconnected] = useState(false);
|
|
2510
|
-
const reconnect = useCallback(async (url) => {
|
|
2644
|
+
const reconnect = useCallback(async (url, auth) => {
|
|
2511
2645
|
setHasReconnected(true);
|
|
2512
2646
|
setStatus("connecting");
|
|
2513
2647
|
setError(void 0);
|
|
2514
2648
|
try {
|
|
2649
|
+
const body = { url };
|
|
2650
|
+
if (auth && auth.type !== "none") body.auth = auth;
|
|
2515
2651
|
const res = await fetch("/__sunpeak/connect", {
|
|
2516
2652
|
method: "POST",
|
|
2517
2653
|
headers: { "Content-Type": "application/json" },
|
|
2518
|
-
body: JSON.stringify(
|
|
2654
|
+
body: JSON.stringify(body)
|
|
2519
2655
|
});
|
|
2520
2656
|
if (!res.ok) {
|
|
2521
2657
|
let message = `Connection failed (${res.status})`;
|
|
@@ -2534,6 +2670,12 @@ function useMcpConnection(initialServerUrl) {
|
|
|
2534
2670
|
setSimulations(void 0);
|
|
2535
2671
|
}
|
|
2536
2672
|
}, []);
|
|
2673
|
+
const setConnected = useCallback((sims) => {
|
|
2674
|
+
setHasReconnected(true);
|
|
2675
|
+
setStatus("connected");
|
|
2676
|
+
setError(void 0);
|
|
2677
|
+
setSimulations(sims);
|
|
2678
|
+
}, []);
|
|
2537
2679
|
useEffect(() => {
|
|
2538
2680
|
if (!initialServerUrl) return;
|
|
2539
2681
|
let cancelled = false;
|
|
@@ -2559,7 +2701,8 @@ function useMcpConnection(initialServerUrl) {
|
|
|
2559
2701
|
error,
|
|
2560
2702
|
simulations,
|
|
2561
2703
|
hasReconnected,
|
|
2562
|
-
reconnect
|
|
2704
|
+
reconnect,
|
|
2705
|
+
setConnected
|
|
2563
2706
|
};
|
|
2564
2707
|
}
|
|
2565
2708
|
//#endregion
|
|
@@ -3043,22 +3186,144 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3043
3186
|
defaultHost
|
|
3044
3187
|
});
|
|
3045
3188
|
const [serverUrl, setServerUrl] = React.useState(mcpServerUrl ?? "");
|
|
3189
|
+
const [authType, setAuthType] = React.useState("none");
|
|
3190
|
+
const [bearerToken, setBearerToken] = React.useState("");
|
|
3191
|
+
const [oauthScopes, setOauthScopes] = React.useState("");
|
|
3192
|
+
const [oauthClientId, setOauthClientId] = React.useState("");
|
|
3193
|
+
const [oauthClientSecret, setOauthClientSecret] = React.useState("");
|
|
3194
|
+
const [oauthStatus, setOauthStatus] = React.useState("none");
|
|
3195
|
+
const [oauthError, setOauthError] = React.useState();
|
|
3046
3196
|
const connection = useMcpConnection(mcpServerUrl || void 0);
|
|
3047
3197
|
const [prodResources, setProdResources] = React.useState(state.urlProdResources ?? defaultProdResources);
|
|
3048
3198
|
const [isRunning, setIsRunning] = React.useState(false);
|
|
3049
3199
|
const [hasRun, setHasRun] = React.useState(false);
|
|
3050
3200
|
const [showCheck, setShowCheck] = React.useState(false);
|
|
3051
3201
|
const checkTimerRef = React.useRef(void 0);
|
|
3202
|
+
const oauthCleanupRef = React.useRef(void 0);
|
|
3052
3203
|
React.useEffect(() => {
|
|
3053
3204
|
state.setSelectedSimulationName(effectiveSimulationName);
|
|
3054
3205
|
}, [effectiveSimulationName]);
|
|
3206
|
+
const currentAuthConfig = React.useMemo(() => {
|
|
3207
|
+
if (authType === "bearer" && bearerToken) return {
|
|
3208
|
+
type: "bearer",
|
|
3209
|
+
bearerToken
|
|
3210
|
+
};
|
|
3211
|
+
if (authType === "oauth") return { type: "oauth" };
|
|
3212
|
+
}, [authType, bearerToken]);
|
|
3055
3213
|
const prevServerUrlRef = React.useRef(serverUrl);
|
|
3056
3214
|
React.useEffect(() => {
|
|
3057
3215
|
const urlChanged = serverUrl !== prevServerUrlRef.current;
|
|
3058
3216
|
prevServerUrlRef.current = serverUrl;
|
|
3059
3217
|
if (!urlChanged) return;
|
|
3060
|
-
if (serverUrl)
|
|
3061
|
-
|
|
3218
|
+
if (serverUrl) {
|
|
3219
|
+
setOauthStatus("none");
|
|
3220
|
+
setOauthError(void 0);
|
|
3221
|
+
if (authType === "oauth") return;
|
|
3222
|
+
connection.reconnect(serverUrl, currentAuthConfig);
|
|
3223
|
+
}
|
|
3224
|
+
}, [
|
|
3225
|
+
serverUrl,
|
|
3226
|
+
connection.reconnect,
|
|
3227
|
+
authType,
|
|
3228
|
+
currentAuthConfig
|
|
3229
|
+
]);
|
|
3230
|
+
const handleStartOAuth = React.useCallback(async () => {
|
|
3231
|
+
if (!serverUrl || demoMode) return;
|
|
3232
|
+
setOauthStatus("authorizing");
|
|
3233
|
+
setOauthError(void 0);
|
|
3234
|
+
const popup = window.open("about:blank", `sunpeak-oauth-${Date.now()}`, "width=600,height=700,popup=yes");
|
|
3235
|
+
try {
|
|
3236
|
+
const res = await fetch("/__sunpeak/oauth/start", {
|
|
3237
|
+
method: "POST",
|
|
3238
|
+
headers: { "Content-Type": "application/json" },
|
|
3239
|
+
body: JSON.stringify({
|
|
3240
|
+
url: serverUrl,
|
|
3241
|
+
scope: oauthScopes || void 0,
|
|
3242
|
+
clientId: oauthClientId || void 0,
|
|
3243
|
+
clientSecret: oauthClientSecret || void 0
|
|
3244
|
+
})
|
|
3245
|
+
});
|
|
3246
|
+
if (!res.ok) {
|
|
3247
|
+
let message = `OAuth start failed (${res.status})`;
|
|
3248
|
+
try {
|
|
3249
|
+
const json = await res.json();
|
|
3250
|
+
if (json.error) message = json.error;
|
|
3251
|
+
} catch {}
|
|
3252
|
+
throw new Error(message);
|
|
3253
|
+
}
|
|
3254
|
+
const data = await res.json();
|
|
3255
|
+
if (data.error) {
|
|
3256
|
+
popup?.close();
|
|
3257
|
+
setOauthError(data.error);
|
|
3258
|
+
setOauthStatus("error");
|
|
3259
|
+
return;
|
|
3260
|
+
}
|
|
3261
|
+
if (data.status === "authorized") {
|
|
3262
|
+
popup?.close();
|
|
3263
|
+
setOauthStatus("authorized");
|
|
3264
|
+
connection.setConnected(data.simulations);
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3267
|
+
if (data.status === "redirect" && data.authUrl) {
|
|
3268
|
+
if (!popup || popup.closed) {
|
|
3269
|
+
setOauthError("Popup was blocked. Allow popups for this site and try again.");
|
|
3270
|
+
setOauthStatus("error");
|
|
3271
|
+
return;
|
|
3272
|
+
}
|
|
3273
|
+
popup.location.href = data.authUrl;
|
|
3274
|
+
let checkClosed;
|
|
3275
|
+
let bc;
|
|
3276
|
+
const cleanup = () => {
|
|
3277
|
+
clearInterval(checkClosed);
|
|
3278
|
+
window.removeEventListener("message", handleMessage);
|
|
3279
|
+
bc?.close();
|
|
3280
|
+
oauthCleanupRef.current = void 0;
|
|
3281
|
+
};
|
|
3282
|
+
oauthCleanupRef.current?.();
|
|
3283
|
+
oauthCleanupRef.current = cleanup;
|
|
3284
|
+
const handleOAuthResult = (result) => {
|
|
3285
|
+
cleanup();
|
|
3286
|
+
if (result.error) {
|
|
3287
|
+
setOauthError(result.errorDescription || result.error);
|
|
3288
|
+
setOauthStatus("error");
|
|
3289
|
+
} else if (result.success) {
|
|
3290
|
+
setOauthStatus("authorized");
|
|
3291
|
+
connection.setConnected(result.simulations);
|
|
3292
|
+
}
|
|
3293
|
+
};
|
|
3294
|
+
const handleMessage = (event) => {
|
|
3295
|
+
if (event.origin !== window.location.origin) return;
|
|
3296
|
+
if (event.data?.type !== "sunpeak-oauth-callback") return;
|
|
3297
|
+
handleOAuthResult(event.data);
|
|
3298
|
+
};
|
|
3299
|
+
window.addEventListener("message", handleMessage);
|
|
3300
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
3301
|
+
bc = new BroadcastChannel("sunpeak-oauth");
|
|
3302
|
+
bc.onmessage = (event) => {
|
|
3303
|
+
if (event.data?.type !== "sunpeak-oauth-callback") return;
|
|
3304
|
+
handleOAuthResult(event.data);
|
|
3305
|
+
};
|
|
3306
|
+
}
|
|
3307
|
+
checkClosed = setInterval(() => {
|
|
3308
|
+
if (popup?.closed) {
|
|
3309
|
+
cleanup();
|
|
3310
|
+
setOauthStatus((prev) => prev === "authorizing" ? "none" : prev);
|
|
3311
|
+
}
|
|
3312
|
+
}, 500);
|
|
3313
|
+
}
|
|
3314
|
+
} catch (err) {
|
|
3315
|
+
popup?.close();
|
|
3316
|
+
setOauthError(err instanceof Error ? err.message : String(err));
|
|
3317
|
+
setOauthStatus("error");
|
|
3318
|
+
}
|
|
3319
|
+
}, [
|
|
3320
|
+
serverUrl,
|
|
3321
|
+
oauthScopes,
|
|
3322
|
+
oauthClientId,
|
|
3323
|
+
oauthClientSecret,
|
|
3324
|
+
demoMode,
|
|
3325
|
+
connection
|
|
3326
|
+
]);
|
|
3062
3327
|
React.useEffect(() => {
|
|
3063
3328
|
if (connection.simulations) setSimulations(connection.simulations);
|
|
3064
3329
|
else if (connection.status === "error" && connection.hasReconnected) setSimulations({});
|
|
@@ -3090,7 +3355,10 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3090
3355
|
React.useEffect(() => {
|
|
3091
3356
|
setHasRun(false);
|
|
3092
3357
|
}, [effectiveSimulationName]);
|
|
3093
|
-
React.useEffect(() => () =>
|
|
3358
|
+
React.useEffect(() => () => {
|
|
3359
|
+
clearTimeout(checkTimerRef.current);
|
|
3360
|
+
oauthCleanupRef.current?.();
|
|
3361
|
+
}, []);
|
|
3094
3362
|
const handleRun = React.useCallback(async () => {
|
|
3095
3363
|
const caller = onCallToolDirect ?? onCallTool;
|
|
3096
3364
|
const sim = simulations[effectiveSimulationName];
|
|
@@ -3145,16 +3413,26 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3145
3413
|
const ctx = { ...state.hostContext };
|
|
3146
3414
|
if (styleVars) ctx.styles = { variables: styleVars };
|
|
3147
3415
|
if (userAgent) ctx.userAgent = userAgent;
|
|
3416
|
+
if (activeShell?.availableDisplayModes) ctx.availableDisplayModes = activeShell.availableDisplayModes;
|
|
3148
3417
|
return ctx;
|
|
3149
3418
|
}, [state.hostContext, activeShell]);
|
|
3419
|
+
const { displayMode, setDisplayMode } = state;
|
|
3150
3420
|
React.useEffect(() => {
|
|
3421
|
+
const modes = activeShell?.availableDisplayModes;
|
|
3422
|
+
if (modes && !modes.includes(displayMode)) setDisplayMode("inline");
|
|
3423
|
+
}, [
|
|
3424
|
+
activeShell,
|
|
3425
|
+
displayMode,
|
|
3426
|
+
setDisplayMode
|
|
3427
|
+
]);
|
|
3428
|
+
React.useLayoutEffect(() => {
|
|
3151
3429
|
const vars = activeShell?.styleVariables;
|
|
3152
3430
|
if (!vars) return;
|
|
3153
3431
|
const root = document.documentElement;
|
|
3154
3432
|
for (const [key, value] of Object.entries(vars)) if (value) root.style.setProperty(key, value);
|
|
3155
3433
|
}, [activeShell]);
|
|
3156
3434
|
const prevPageStyleKeysRef = React.useRef([]);
|
|
3157
|
-
React.
|
|
3435
|
+
React.useLayoutEffect(() => {
|
|
3158
3436
|
const root = document.documentElement;
|
|
3159
3437
|
for (const key of prevPageStyleKeysRef.current) root.style.removeProperty(key);
|
|
3160
3438
|
const pageStyles = activeShell?.pageStyles;
|
|
@@ -3167,6 +3445,22 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3167
3445
|
prevPageStyleKeysRef.current = keys;
|
|
3168
3446
|
} else prevPageStyleKeysRef.current = [];
|
|
3169
3447
|
}, [activeShell]);
|
|
3448
|
+
React.useLayoutEffect(() => {
|
|
3449
|
+
const fontCss = activeShell?.fontCss;
|
|
3450
|
+
const id = "sunpeak-host-fonts";
|
|
3451
|
+
const existing = document.getElementById(id);
|
|
3452
|
+
if (!fontCss) {
|
|
3453
|
+
existing?.remove();
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
if (existing) existing.textContent = fontCss;
|
|
3457
|
+
else {
|
|
3458
|
+
const style = document.createElement("style");
|
|
3459
|
+
style.id = id;
|
|
3460
|
+
style.textContent = fontCss;
|
|
3461
|
+
document.head.appendChild(style);
|
|
3462
|
+
}
|
|
3463
|
+
}, [activeShell]);
|
|
3170
3464
|
const handleCallTool = React.useCallback((params) => {
|
|
3171
3465
|
if (activeSimulationName) {
|
|
3172
3466
|
const mock = simulations[activeSimulationName]?.serverTools?.[params.name];
|
|
@@ -3370,6 +3664,92 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3370
3664
|
disabled: demoMode
|
|
3371
3665
|
})
|
|
3372
3666
|
}),
|
|
3667
|
+
!demoMode && /* @__PURE__ */ jsx(SidebarCollapsibleControl, {
|
|
3668
|
+
label: "Authentication",
|
|
3669
|
+
defaultCollapsed: authType === "none",
|
|
3670
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3671
|
+
className: "space-y-1",
|
|
3672
|
+
children: [
|
|
3673
|
+
/* @__PURE__ */ jsx(SidebarSelect, {
|
|
3674
|
+
value: authType,
|
|
3675
|
+
onChange: (value) => {
|
|
3676
|
+
const newType = value;
|
|
3677
|
+
setAuthType(newType);
|
|
3678
|
+
setOauthStatus("none");
|
|
3679
|
+
setOauthError(void 0);
|
|
3680
|
+
if (newType === "none" && serverUrl) connection.reconnect(serverUrl);
|
|
3681
|
+
},
|
|
3682
|
+
options: [
|
|
3683
|
+
{
|
|
3684
|
+
value: "none",
|
|
3685
|
+
label: "None"
|
|
3686
|
+
},
|
|
3687
|
+
{
|
|
3688
|
+
value: "bearer",
|
|
3689
|
+
label: "Bearer Token"
|
|
3690
|
+
},
|
|
3691
|
+
{
|
|
3692
|
+
value: "oauth",
|
|
3693
|
+
label: "OAuth"
|
|
3694
|
+
}
|
|
3695
|
+
]
|
|
3696
|
+
}),
|
|
3697
|
+
authType === "bearer" && /* @__PURE__ */ jsx(SidebarInput, {
|
|
3698
|
+
type: "password",
|
|
3699
|
+
value: bearerToken,
|
|
3700
|
+
onChange: (value) => {
|
|
3701
|
+
setBearerToken(value);
|
|
3702
|
+
if (serverUrl && value) connection.reconnect(serverUrl, {
|
|
3703
|
+
type: "bearer",
|
|
3704
|
+
bearerToken: value
|
|
3705
|
+
});
|
|
3706
|
+
},
|
|
3707
|
+
applyOnBlur: true,
|
|
3708
|
+
placeholder: "Paste your token"
|
|
3709
|
+
}),
|
|
3710
|
+
authType === "oauth" && /* @__PURE__ */ jsxs("div", {
|
|
3711
|
+
className: "space-y-1",
|
|
3712
|
+
children: [
|
|
3713
|
+
/* @__PURE__ */ jsx(SidebarInput, {
|
|
3714
|
+
value: oauthClientId,
|
|
3715
|
+
onChange: setOauthClientId,
|
|
3716
|
+
applyOnBlur: true,
|
|
3717
|
+
placeholder: "Client ID (optional)"
|
|
3718
|
+
}),
|
|
3719
|
+
oauthClientId && /* @__PURE__ */ jsx(SidebarInput, {
|
|
3720
|
+
type: "password",
|
|
3721
|
+
value: oauthClientSecret,
|
|
3722
|
+
onChange: setOauthClientSecret,
|
|
3723
|
+
applyOnBlur: true,
|
|
3724
|
+
placeholder: "Client Secret (optional)"
|
|
3725
|
+
}),
|
|
3726
|
+
/* @__PURE__ */ jsx(SidebarInput, {
|
|
3727
|
+
value: oauthScopes,
|
|
3728
|
+
onChange: setOauthScopes,
|
|
3729
|
+
applyOnBlur: true,
|
|
3730
|
+
placeholder: "Scopes (optional)"
|
|
3731
|
+
}),
|
|
3732
|
+
/* @__PURE__ */ jsx("button", {
|
|
3733
|
+
type: "button",
|
|
3734
|
+
onClick: handleStartOAuth,
|
|
3735
|
+
disabled: !serverUrl || oauthStatus === "authorizing",
|
|
3736
|
+
className: "w-full h-7 text-xs rounded-md px-2 transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
|
|
3737
|
+
style: {
|
|
3738
|
+
backgroundColor: oauthStatus === "authorized" ? "#22c55e" : "var(--color-text-primary)",
|
|
3739
|
+
color: "var(--color-background-primary)"
|
|
3740
|
+
},
|
|
3741
|
+
children: oauthStatus === "authorizing" ? "Authorizing…" : oauthStatus === "authorized" ? "Authorized" : "Authorize"
|
|
3742
|
+
}),
|
|
3743
|
+
oauthError && /* @__PURE__ */ jsx("div", {
|
|
3744
|
+
className: "text-[9px]",
|
|
3745
|
+
style: { color: "var(--color-text-danger, #dc2626)" },
|
|
3746
|
+
children: oauthError
|
|
3747
|
+
})
|
|
3748
|
+
]
|
|
3749
|
+
})
|
|
3750
|
+
]
|
|
3751
|
+
})
|
|
3752
|
+
}, `auth-${authType === "none" ? "none" : "active"}`),
|
|
3373
3753
|
!hideInspectorModes && !demoMode && /* @__PURE__ */ jsx(SidebarCheckbox, {
|
|
3374
3754
|
checked: prodResources,
|
|
3375
3755
|
onChange: setProdResources,
|
|
@@ -3525,7 +3905,7 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3525
3905
|
value: "fullscreen",
|
|
3526
3906
|
label: "Full"
|
|
3527
3907
|
}
|
|
3528
|
-
]
|
|
3908
|
+
].filter((opt) => !activeShell?.availableDisplayModes || activeShell.availableDisplayModes.includes(opt.value))
|
|
3529
3909
|
})
|
|
3530
3910
|
}),
|
|
3531
3911
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -3807,4 +4187,4 @@ function Inspector({ children, simulations: initialSimulations = {}, appName = "
|
|
|
3807
4187
|
//#endregion
|
|
3808
4188
|
export { DEFAULT_STYLE_VARIABLES as S, McpAppHost as _, SidebarControl as a, getRegisteredHosts as b, SidebarTextarea as c, ThemeProvider as d, useThemeContext as f, extractResourceCSP as g, IframeResource as h, SidebarCollapsibleControl as i, SidebarToggle as l, useInspectorState as m, resolveServerToolResult as n, SidebarInput as o, useMcpConnection as p, SidebarCheckbox as r, SidebarSelect as s, Inspector as t, SimpleSidebar as u, SCREEN_WIDTHS as v, registerHostShell as x, getHostShell as y };
|
|
3809
4189
|
|
|
3810
|
-
//# sourceMappingURL=inspector-
|
|
4190
|
+
//# sourceMappingURL=inspector-CjSoXm6N.js.map
|