sunpeak 0.17.7 → 0.18.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 (90) hide show
  1. package/README.md +52 -44
  2. package/bin/commands/dev.mjs +5 -6
  3. package/bin/commands/inspect.mjs +17 -18
  4. package/bin/lib/inspect/inspect-config.d.mts +2 -2
  5. package/bin/lib/inspect/inspect-config.mjs +2 -2
  6. package/bin/lib/live/chatgpt-page.mjs +2 -2
  7. package/bin/lib/live/host-page.mjs +3 -8
  8. package/bin/lib/sandbox-server.mjs +11 -11
  9. package/bin/sunpeak.js +3 -3
  10. package/dist/chatgpt/chatgpt-conversation.d.ts +1 -1
  11. package/dist/chatgpt/index.cjs +20 -20
  12. package/dist/chatgpt/index.cjs.map +1 -1
  13. package/dist/chatgpt/index.d.ts +10 -10
  14. package/dist/chatgpt/index.js +5 -5
  15. package/dist/chatgpt/index.js.map +1 -1
  16. package/dist/claude/claude-conversation.d.ts +1 -1
  17. package/dist/claude/index.cjs +2 -2
  18. package/dist/claude/index.d.ts +1 -1
  19. package/dist/claude/index.js +2 -2
  20. package/dist/host/chatgpt/index.cjs +0 -40
  21. package/dist/host/chatgpt/index.cjs.map +1 -1
  22. package/dist/host/chatgpt/index.d.ts +0 -3
  23. package/dist/host/chatgpt/index.js +1 -40
  24. package/dist/host/chatgpt/index.js.map +1 -1
  25. package/dist/host/index.cjs +1 -4
  26. package/dist/host/index.cjs.map +1 -1
  27. package/dist/host/index.d.ts +1 -5
  28. package/dist/host/index.js +2 -4
  29. package/dist/host/index.js.map +1 -1
  30. package/dist/index.cjs +9 -10
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.ts +1 -3
  33. package/dist/index.js +4 -4
  34. package/dist/index.js.map +1 -1
  35. package/dist/{simulator → inspector}/hosts.d.ts +3 -3
  36. package/dist/{simulator → inspector}/iframe-resource.d.ts +3 -3
  37. package/dist/inspector/index.cjs +74 -0
  38. package/dist/{simulator → inspector}/index.cjs.map +1 -1
  39. package/dist/{simulator → inspector}/index.d.ts +8 -8
  40. package/dist/{simulator → inspector}/index.js +8 -8
  41. package/dist/{simulator → inspector}/index.js.map +1 -1
  42. package/dist/{simulator/simulator-types.d.ts → inspector/inspector-types.d.ts} +1 -1
  43. package/dist/{simulator/simulator-url.d.ts → inspector/inspector-url.d.ts} +15 -15
  44. package/dist/{simulator/simulator.d.ts → inspector/inspector.d.ts} +3 -3
  45. package/dist/{simulator → inspector}/mcp-app-host.d.ts +5 -5
  46. package/dist/{simulator → inspector}/mock-openai-runtime.d.ts +2 -2
  47. package/dist/{simulator → inspector}/sandbox-proxy.d.ts +1 -1
  48. package/dist/{simulator/use-simulator-state.d.ts → inspector/use-inspector-state.d.ts} +4 -4
  49. package/dist/{simulator → inspector}/use-mcp-connection.d.ts +1 -1
  50. package/dist/{simulator-eU6sQTje.cjs → inspector-CByJjmPD.cjs} +51 -52
  51. package/dist/{simulator-eU6sQTje.cjs.map → inspector-CByJjmPD.cjs.map} +1 -1
  52. package/dist/{simulator-0dAb16Qt.js → inspector-ClhpqKLi.js} +42 -43
  53. package/dist/{simulator-0dAb16Qt.js.map → inspector-ClhpqKLi.js.map} +1 -1
  54. package/dist/{simulator-url-3ATCsPOT.cjs → inspector-url-7qhtJwY6.cjs} +10 -10
  55. package/dist/{simulator-url-3ATCsPOT.cjs.map → inspector-url-7qhtJwY6.cjs.map} +1 -1
  56. package/dist/{simulator-url-BbuuWa7S.js → inspector-url-DuEFmxLP.js} +9 -9
  57. package/dist/{simulator-url-BbuuWa7S.js.map → inspector-url-DuEFmxLP.js.map} +1 -1
  58. package/dist/mcp/index.cjs +146 -12
  59. package/dist/mcp/index.cjs.map +1 -1
  60. package/dist/mcp/index.d.ts +2 -0
  61. package/dist/mcp/index.js +143 -14
  62. package/dist/mcp/index.js.map +1 -1
  63. package/dist/mcp/production-server.d.ts +14 -0
  64. package/dist/mcp/resolve-domain.d.ts +55 -0
  65. package/dist/mcp/types.d.ts +1 -1
  66. package/dist/style.css +12 -12
  67. package/dist/types/resource-config.d.ts +20 -1
  68. package/dist/types/simulation.d.ts +1 -1
  69. package/package.json +7 -20
  70. package/template/dist/albums/albums.html +1 -1
  71. package/template/dist/albums/albums.json +1 -1
  72. package/template/dist/carousel/carousel.html +1 -1
  73. package/template/dist/carousel/carousel.json +1 -1
  74. package/template/dist/map/map.html +1 -1
  75. package/template/dist/map/map.json +1 -1
  76. package/template/dist/review/review.html +1 -1
  77. package/template/dist/review/review.json +1 -1
  78. package/template/playwright.config.ts +1 -1
  79. package/template/src/index-resource.tsx +1 -1
  80. package/template/src/styles/globals.css +2 -2
  81. package/template/tests/e2e/albums.spec.ts +13 -13
  82. package/template/tests/e2e/carousel.spec.ts +11 -11
  83. package/template/tests/e2e/map.spec.ts +16 -16
  84. package/template/tests/e2e/review.spec.ts +25 -25
  85. package/dist/chatgpt/globals.css +0 -2642
  86. package/dist/host/chatgpt/use-file-download.d.ts +0 -33
  87. package/dist/simulator/index.cjs +0 -74
  88. /package/dist/{simulator → inspector}/host-styles.d.ts +0 -0
  89. /package/dist/{simulator → inspector}/simple-sidebar.d.ts +0 -0
  90. /package/dist/{simulator → inspector}/theme-provider.d.ts +0 -0
package/README.md CHANGED
@@ -16,47 +16,48 @@
16
16
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?style=flat&logo=typescript&label=ts&color=FFB800&logoColor=white&labelColor=000035)](https://www.typescriptlang.org/)
17
17
  [![React](https://img.shields.io/badge/React-19-blue?style=flat&logo=react&label=react&color=FFB800&logoColor=white&labelColor=000035)](https://reactjs.org/)
18
18
 
19
- Local-first MCP Apps framework.
19
+ Inspector, testing framework, and app framework for MCP Apps.
20
20
 
21
- Quickstart, build, test, and ship your Claude Connector or ChatGPT App!
22
-
23
- [Demo (Hosted)](https://sunpeak.ai/simulator) ~
21
+ [Demo (Hosted)](https://sunpeak.ai/inspector) ~
24
22
  [Demo (Video)](https://cdn.sunpeak.ai/sunpeak-demo-prod.mp4) ~
25
23
  [Discord](https://discord.gg/FB2QNXqRnw) ~
26
24
  [Documentation](https://sunpeak.ai/docs) ~
27
25
  [GitHub](https://github.com/Sunpeak-AI/sunpeak)
28
26
 
29
- <div align="center">
30
- <a href="https://sunpeak.ai/docs/library/simulator">
31
- <picture>
32
- <img alt="Simulator" src="https://cdn.sunpeak.ai/chatgpt-simulator.png">
33
- </picture>
34
- </a>
35
- </div>
27
+ ## sunpeak is three things
36
28
 
37
- ## Quickstart
29
+ ### 1. Inspector
38
30
 
39
- Requirements: Node (20+), pnpm (10+)
31
+ Test any MCP server in replicated ChatGPT and Claude runtimes — no sunpeak project required.
40
32
 
41
33
  ```bash
42
- pnpm add -g sunpeak
43
- sunpeak new
34
+ sunpeak inspect --server http://localhost:8000/mcp
44
35
  ```
45
36
 
46
- ## Overview
37
+ <div align="center">
38
+ <a href="https://sunpeak.ai/docs/mcp-apps-inspector">
39
+ <picture>
40
+ <img alt="Inspector" src="https://cdn.sunpeak.ai/chatgpt-simulator.png">
41
+ </picture>
42
+ </a>
43
+ </div>
44
+
45
+ - Multi-host inspector replicating ChatGPT and Claude runtimes
46
+ - Toggle themes, display modes, device types from the sidebar or URL params
47
+ - Call real tool handlers or use simulation fixtures for mock data
48
+ - Built into `sunpeak dev` for framework users
47
49
 
48
- `sunpeak` is an npm package that helps you build MCP Apps (interactive UI [resources](https://sunpeak.ai/docs/mcp-apps/mcp/resources)) while keeping your [MCP server](https://sunpeak.ai/docs/mcp-apps/mcp/overview) client-agnostic. Built on the [MCP Apps SDK](https://github.com/modelcontextprotocol/ext-apps) (`@modelcontextprotocol/ext-apps`). `sunpeak` consists of:
50
+ ### 2. Testing Framework
49
51
 
50
- ### The `sunpeak` library
52
+ E2E tests against simulated hosts and live tests against real production hosts.
51
53
 
52
- 1. Runtime APIs: Strongly typed React hooks for interacting with the host runtime (`useApp`, `useToolData`, `useAppState`, `useHostContext`, `useUpdateModelContext`, `useAppTools`), architected to **support generic and platform-specific features** (ChatGPT, Claude, etc.). Host-specific hooks like `useUploadFile`, `useRequestModal`, and `useRequestCheckout` are available via `sunpeak/host/chatgpt`, with `isChatGPT()` / `isClaude()` host detection via `sunpeak/host`.
53
- 2. Multi-host simulator: React component replicating host runtimes (ChatGPT, Claude) to **test Apps locally and automatically** via UI, props, or URL parameters.
54
- 3. Live testing: **Automated tests against real ChatGPT** opens your browser, sends messages, validates your app renders correctly inside the real host. No more manual testing.
55
- 4. MCP server: Serve Resources with mock data to hosts like ChatGPT and Claude with HMR (**no more cache issues or 5-click manual refreshes**).
54
+ - **Simulations**: JSON fixtures defining reproducible tool states ([example below](#simulation))
55
+ - **E2E tests**: Playwright + `createInspectorUrl` against the inspector ([example below](#inspector))
56
+ - **Live tests**: Automated browser tests against real ChatGPT via `sunpeak/test`
56
57
 
57
- ### The `sunpeak` framework
58
+ ### 3. App Framework
58
59
 
59
- Next.js for MCP Apps. Using an example App `sunpeak-app` with a `Review` UI ([MCP resource](https://sunpeak.ai/docs/mcp-apps/mcp/resources)), `sunpeak` projects look like:
60
+ Next.js for MCP Apps. Convention-over-configuration project structure with the inspector and testing built in.
60
61
 
61
62
  ```bash
62
63
  sunpeak-app/
@@ -76,26 +77,33 @@ sunpeak-app/
76
77
  └── package.json
77
78
  ```
78
79
 
79
- 1. Project scaffold: Complete development setup with the `sunpeak` library.
80
- 2. UI components: Production-ready components following MCP App design guidelines.
81
- 3. Convention over configuration:
82
- 1. Create a UI by creating a `.tsx` file in `src/resources/{name}/` that exports a `ResourceConfig` and a React component ([example below](#resource-component)).
83
- 2. Create a tool by creating a `.ts` file in `src/tools/` that exports `tool` (metadata with optional resource link), `schema` (Zod), and a `default` handler ([example below](#tool-file)). Tools without a `resource` field are registered as plain MCP tools (no UI).
84
- 3. Create test state (`Simulation`s) by creating a `.json` file in `tests/simulations/` ([example below](#simulation)).
80
+ - **Runtime APIs**: Strongly typed React hooks (`useToolData`, `useAppState`, `useHostContext`, etc.)
81
+ - **Convention over configuration**: Resources, tools, and simulations are auto-discovered
82
+ - **Multi-platform**: Build once, deploy to ChatGPT, Claude, and future hosts
83
+
84
+ ## Quickstart
85
+
86
+ Requirements: Node (20+), pnpm (10+)
85
87
 
86
- ### The `sunpeak` CLI
88
+ ```bash
89
+ pnpm add -g sunpeak
90
+ sunpeak new
91
+ ```
87
92
 
88
- Commands for managing MCP Apps:
93
+ ## CLI
89
94
 
90
- - `sunpeak new [name] [resources]` - Create a new project
91
- - `sunpeak dev` - Start dev server with MCP endpoint and live simulator
92
- - `sunpeak build` - Build resources and compile tools for production
93
- - `sunpeak start` - Start the production MCP server (real handlers, auth, Zod validation)
94
- - `sunpeak upgrade` - Upgrade sunpeak to latest version
95
+ | Command | Description |
96
+ | ------------------------------------- | ------------------------------------------- |
97
+ | `sunpeak new [name] [resources]` | Create a new project |
98
+ | `sunpeak dev` | Start dev server + inspector + MCP endpoint |
99
+ | `sunpeak inspect --server <url\|cmd>` | Inspect any MCP server (standalone) |
100
+ | `sunpeak build` | Build resources + tools for production |
101
+ | `sunpeak start` | Start production MCP server |
102
+ | `sunpeak upgrade` | Upgrade sunpeak to latest version |
95
103
 
96
104
  ## Example App
97
105
 
98
- Example `Resource`, `Simulation`, and testing file (using the `Simulator`) for an [MCP resource](https://sunpeak.ai/docs/mcp-apps/mcp/resources) called "Review".
106
+ Example `Resource`, `Simulation`, and testing file (using the `Inspector`) for an [MCP resource](https://sunpeak.ai/docs/mcp-apps/mcp/resources) called "Review".
99
107
 
100
108
  ### `Resource` Component
101
109
 
@@ -151,7 +159,7 @@ export default async function (args: Args, extra: ToolHandlerExtra) {
151
159
 
152
160
  ### `Simulation`
153
161
 
154
- Simulation files provide fixture data for testing. Each references a tool by filename and contains the mock input/output:
162
+ Simulation files provide fixture data for testing UIs. Each references a tool by filename and contains the mock input/output:
155
163
 
156
164
  ```jsonc
157
165
  // tests/simulations/review-diff.json
@@ -172,7 +180,7 @@ Simulation files provide fixture data for testing. Each references a tool by fil
172
180
  }
173
181
  ```
174
182
 
175
- ### `Simulator`
183
+ ### `Inspector`
176
184
 
177
185
  ```bash
178
186
  ├── tests/e2e/
@@ -180,15 +188,15 @@ Simulation files provide fixture data for testing. Each references a tool by fil
180
188
  └── package.json
181
189
  ```
182
190
 
183
- The `Simulator` allows you to set **host state** (like host platform, light/dark mode) via URL params, which can be rendered alongside your `Simulation`s and tested via pre-configured Playwright end-to-end tests (`.spec.ts`).
191
+ The `Inspector` allows you to set **host state** (like host platform, light/dark mode) via URL params, which can be rendered alongside your `Simulation`s and tested via pre-configured Playwright end-to-end tests (`.spec.ts`).
184
192
 
185
- Using the `Simulator` and `Simulation`s, you can test all possible App states locally and automatically across hosts (ChatGPT, Claude)!
193
+ Using the `Inspector` and `Simulation`s, you can test all possible App states locally and automatically across hosts (ChatGPT, Claude)!
186
194
 
187
195
  ```ts
188
196
  // tests/e2e/review.spec.ts
189
197
 
190
198
  import { test, expect } from '@playwright/test';
191
- import { createSimulatorUrl } from 'sunpeak/simulator';
199
+ import { createInspectorUrl } from 'sunpeak/inspector';
192
200
 
193
201
  const hosts = ['chatgpt', 'claude'] as const;
194
202
 
@@ -197,7 +205,7 @@ for (const host of hosts) {
197
205
  test.describe('Light Mode', () => {
198
206
  test('should render review title with correct styles', async ({ page }) => {
199
207
  const params = { simulation: 'review-diff', theme: 'light', host }; // Set sim & host state.
200
- await page.goto(createSimulatorUrl(params));
208
+ await page.goto(createInspectorUrl(params));
201
209
 
202
210
  // Resource content renders inside an iframe
203
211
  const iframe = page.frameLocator('iframe');
@@ -128,8 +128,8 @@ function startBuildWatcher(projectRoot, resourcesDir, mcpHandle, { skipInitialBu
128
128
  * Start the Vite development server.
129
129
  *
130
130
  * Starts the MCP server (with Vite HMR for resources) and then launches the
131
- * inspector UI pointed at it. The inspector handles the simulator UI, tool call
132
- * proxying, and resource loading — all through the MCP protocol.
131
+ * inspector pointed at it. The inspector handles the UI, tool call proxying,
132
+ * and resource loading — all through the MCP protocol.
133
133
  */
134
134
  export async function dev(projectRoot = process.cwd(), args = []) {
135
135
  // Check for package.json
@@ -511,8 +511,8 @@ if (import.meta.hot) {
511
511
  startBuildWatcher(projectRoot, resourcesDir, mcpHandle, { skipInitialBuild: isProdResources });
512
512
 
513
513
  // Launch the inspector UI pointed at the local MCP server.
514
- // This serves the simulator UI via Vite, connecting to our MCP server as a client.
515
- // In framework mode, the simulator shows prod-tools/prod-resources toggles instead
514
+ // This serves the inspector UI via Vite, connecting to our MCP server as a client.
515
+ // In framework mode, the inspector shows prod-tools/prod-resources toggles instead
516
516
  // of the server URL input.
517
517
  const mcpUrl = `http://localhost:${mcpPort}/mcp`;
518
518
  await inspectServer({
@@ -531,9 +531,8 @@ if (import.meta.hot) {
531
531
  // The Tailwind plugin is also passed so source CSS (@import "tailwindcss") is processed.
532
532
  ...(isTemplate && {
533
533
  resolveAlias: {
534
- 'sunpeak/simulator': resolve(parentSrc, 'simulator/index.ts'),
534
+ 'sunpeak/inspector': resolve(parentSrc, 'inspector/index.ts'),
535
535
  'sunpeak/style.css': resolve(parentSrc, 'style.css'),
536
- 'sunpeak/chatgpt/globals.css': resolve(parentSrc, 'chatgpt/globals.css'),
537
536
  },
538
537
  vitePlugins: [tailwindcss()],
539
538
  viteCssConfig: lightningcssConfig,
@@ -1,12 +1,12 @@
1
1
  /**
2
- * `sunpeak inspect` — Connect to an external MCP server and launch the simulator.
2
+ * `sunpeak inspect` — Connect to an external MCP server and launch the inspector.
3
3
  *
4
- * This command lets users test their own MCP server in the sunpeak simulator
4
+ * This command lets users test their own MCP server in the sunpeak inspector
5
5
  * without adopting the sunpeak framework conventions. It connects to the server
6
- * via MCP protocol, discovers tools and resources, and serves the simulator UI.
6
+ * via MCP protocol, discovers tools and resources, and serves the inspector UI.
7
7
  *
8
8
  * The core logic lives in `inspectServer()`, which is also used by `sunpeak dev`
9
- * to serve the simulator UI pointed at the local MCP server.
9
+ * to serve the inspector UI pointed at the local MCP server.
10
10
  *
11
11
  * Usage:
12
12
  * sunpeak inspect --server http://localhost:8000/mcp
@@ -57,7 +57,7 @@ function parseArgs(args) {
57
57
 
58
58
  function printHelp() {
59
59
  console.log(`
60
- sunpeak inspect — Test an external MCP server in the simulator
60
+ sunpeak inspect — Test an external MCP server in the inspector
61
61
 
62
62
  Usage:
63
63
  sunpeak inspect --server <url-or-command>
@@ -66,7 +66,7 @@ Options:
66
66
  --server, -s <url|cmd> MCP server URL or stdio command (required)
67
67
  --simulations <dir> Simulation JSON directory (opt-in, no default)
68
68
  --port, -p <number> Dev server port (default: 3000)
69
- --name <string> App name in simulator chrome
69
+ --name <string> App name in inspector chrome
70
70
  --help, -h Show this help
71
71
 
72
72
  Examples:
@@ -210,7 +210,7 @@ function mergeSimulationFixtures(dir, simulations) {
210
210
  * @param {string} appName - Display name
211
211
  * @param {string|null} appIcon - Icon URL or emoji
212
212
  * @param {string} sandboxUrl - Sandbox server URL
213
- * @param {{ defaultProdResources?: boolean, hideSimulatorModes?: boolean }} [modeFlags] - Mode toggles
213
+ * @param {{ defaultProdResources?: boolean, hideInspectorModes?: boolean }} [modeFlags] - Mode toggles
214
214
  */
215
215
  function sunpeakInspectVirtualPlugin(simulations, serverUrl, appName, appIcon, sandboxUrl, modeFlags = {}) {
216
216
  const ENTRY_ID = 'virtual:sunpeak-inspect-entry';
@@ -227,16 +227,15 @@ function sunpeakInspectVirtualPlugin(simulations, serverUrl, appName, appIcon, s
227
227
  return `
228
228
  import { createElement, StrictMode } from 'react';
229
229
  import { createRoot } from 'react-dom/client';
230
- import { Simulator } from 'sunpeak/simulator';
230
+ import { Inspector } from 'sunpeak/inspector';
231
231
  import 'sunpeak/style.css';
232
- import 'sunpeak/chatgpt/globals.css';
233
232
 
234
233
  const simulations = ${JSON.stringify(simulations)};
235
234
  const appName = ${JSON.stringify(appName ?? 'MCP Inspector')};
236
235
  const appIcon = ${JSON.stringify(appIcon ?? null)};
237
236
  const sandboxUrl = ${JSON.stringify(sandboxUrl)};
238
237
  const defaultProdResources = ${JSON.stringify(modeFlags.defaultProdResources ?? false)};
239
- const hideSimulatorModes = ${JSON.stringify(modeFlags.hideSimulatorModes ?? false)};
238
+ const hideInspectorModes = ${JSON.stringify(modeFlags.hideInspectorModes ?? false)};
240
239
 
241
240
  const onCallTool = async (params) => {
242
241
  const res = await fetch('/__sunpeak/call-tool', {
@@ -259,7 +258,7 @@ const onCallToolDirect = async (params) => {
259
258
  const root = createRoot(document.getElementById('root'));
260
259
  root.render(
261
260
  createElement(StrictMode, null,
262
- createElement(Simulator, {
261
+ createElement(Inspector, {
263
262
  simulations,
264
263
  mcpServerUrl: ${JSON.stringify(serverUrl)},
265
264
  appName,
@@ -268,7 +267,7 @@ root.render(
268
267
  onCallTool,
269
268
  onCallToolDirect,
270
269
  defaultProdResources,
271
- hideSimulatorModes,
270
+ hideInspectorModes,
272
271
  })
273
272
  )
274
273
  );
@@ -492,7 +491,7 @@ function readRequestBody(req) {
492
491
 
493
492
  /**
494
493
  * Core inspect server logic. Connects to an MCP server, discovers tools/resources,
495
- * merges simulation fixtures, and serves the simulator UI via Vite.
494
+ * merges simulation fixtures, and serves the inspector UI via Vite.
496
495
  *
497
496
  * Used by both `sunpeak inspect` (CLI) and `sunpeak dev` (programmatic).
498
497
  *
@@ -621,7 +620,7 @@ export async function inspectServer(opts) {
621
620
  </body>
622
621
  </html>`;
623
622
 
624
- const simulatorServerUrl = serverArg;
623
+ const inspectorServerUrl = serverArg;
625
624
 
626
625
  // Create the Vite server.
627
626
  // Use the sunpeak package dir as root to avoid scanning the user's project
@@ -636,11 +635,11 @@ export async function inspectServer(opts) {
636
635
  ...extraVitePlugins,
637
636
  sunpeakInspectVirtualPlugin(
638
637
  simulations,
639
- simulatorServerUrl,
638
+ inspectorServerUrl,
640
639
  serverAppName,
641
640
  serverAppIcon,
642
641
  sandbox.url,
643
- { defaultProdResources, hideSimulatorModes: !frameworkMode }
642
+ { defaultProdResources, hideInspectorModes: !frameworkMode }
644
643
  ),
645
644
  sunpeakInspectEndpointsPlugin(
646
645
  () => mcpConnection.client,
@@ -648,9 +647,9 @@ export async function inspectServer(opts) {
648
647
  { callToolDirect: opts.callToolDirect, simulationsDir }
649
648
  ),
650
649
  // Serve /dist/{name}/{name}.html from the project directory (for Prod Resources mode).
651
- // The Simulator polls these paths via HEAD to check if built resources exist.
650
+ // The Inspector polls these paths via HEAD to check if built resources exist.
652
651
  // Only intercepts .html files under /dist/ — other /dist/ paths (like sunpeak's
653
- // own dist/simulator/index.js) must fall through to Vite's module resolution.
652
+ // own dist/inspector/index.js) must fall through to Vite's module resolution.
654
653
  ...(projectRoot ? [{
655
654
  name: 'sunpeak-dist-serve',
656
655
  configureServer(server) {
@@ -7,7 +7,7 @@ export interface InspectConfigOptions {
7
7
  simulationsDir?: string;
8
8
  /** Host shells to test (default: ['chatgpt', 'claude']) */
9
9
  hosts?: ('chatgpt' | 'claude')[];
10
- /** App name in simulator chrome */
10
+ /** App name in inspector chrome */
11
11
  name?: string;
12
12
  /** Additional Playwright `use` options */
13
13
  use?: Record<string, unknown>;
@@ -15,6 +15,6 @@ export interface InspectConfigOptions {
15
15
 
16
16
  /**
17
17
  * Create a complete Playwright config for testing an external MCP server
18
- * using the sunpeak simulator.
18
+ * using the sunpeak inspector.
19
19
  */
20
20
  export function defineInspectConfig(options: InspectConfigOptions): Record<string, unknown>;
@@ -2,7 +2,7 @@
2
2
  * Playwright config factory for inspect mode (BYOS — Bring Your Own Server).
3
3
  *
4
4
  * Generates a complete Playwright config that starts `sunpeak inspect` as the
5
- * webServer and runs e2e tests against the simulator. Follows the same pattern
5
+ * webServer and runs e2e tests against the inspector. Follows the same pattern
6
6
  * as `defineLiveConfig` for live tests.
7
7
  *
8
8
  * Usage in playwright.config.ts:
@@ -21,7 +21,7 @@ import { getPortSync } from '../get-port.mjs';
21
21
  * @param {string} [options.testDir='tests/e2e'] - Test directory
22
22
  * @param {string} [options.simulationsDir='tests/simulations'] - Simulation JSON directory
23
23
  * @param {string[]} [options.hosts=['chatgpt', 'claude']] - Host shells to test
24
- * @param {string} [options.name] - App name in simulator chrome
24
+ * @param {string} [options.name] - App name in inspector chrome
25
25
  * @param {Object} [options.use] - Additional Playwright `use` options
26
26
  * @returns {import('@playwright/test').PlaywrightTestConfig}
27
27
  */
@@ -11,13 +11,13 @@ import { HostPage } from './host-page.mjs';
11
11
  /**
12
12
  * All ChatGPT DOM selectors in one place for easy maintenance.
13
13
  *
14
- * Last verified: 2026-03-17 via live Playwright inspection.
14
+ * Last verified: 2026-03-24 via live Playwright inspection.
15
15
  */
16
16
  const SELECTORS = {
17
17
  // Chat interface
18
18
  chatInput: '#prompt-textarea',
19
19
  sendButton: '[data-testid="send-button"]',
20
- newChatLink: 'a:has-text("New chat")',
20
+ newChatLink: '[data-testid="create-new-chat-button"]',
21
21
 
22
22
  // Login detection — ChatGPT renders two profile buttons (sidebar compact + expanded); always use .first().
23
23
  loggedInIndicator: '[data-testid="accounts-profile-button"]',
@@ -181,14 +181,9 @@ export class HostPage {
181
181
  * Start a new chat conversation.
182
182
  */
183
183
  async startNewChat() {
184
- const newChatLink = this.page.locator(this.selectors.newChatLink).first();
185
- const isVisible = await newChatLink.isVisible().catch(() => false);
186
- if (isVisible) {
187
- await newChatLink.click();
188
- } else {
189
- await this.page.goto(this.urls.base, { waitUntil: 'domcontentloaded' });
190
- }
191
-
184
+ // Navigate directly rather than clicking — ChatGPT's sidebar compact
185
+ // icon can overlay the "New chat" link and intercept pointer events.
186
+ await this.page.goto(this.urls.base, { waitUntil: 'domcontentloaded' });
192
187
  await this.page.locator(this.selectors.chatInput).waitFor({ timeout: 10_000 });
193
188
  }
194
189
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Separate-origin sandbox server for the simulator's double-iframe architecture.
2
+ * Separate-origin sandbox server for the inspector's double-iframe architecture.
3
3
  *
4
4
  * Real hosts (ChatGPT, Claude) run the sandbox proxy iframe on a separate origin
5
5
  * (e.g., web-sandbox.oaiusercontent.com). This server replicates that by serving
@@ -10,7 +10,7 @@
10
10
  * - document.referrer is empty (cross-origin navigation)
11
11
  * - The iframe sandbox attribute behaves identically to production
12
12
  *
13
- * The server is started by `sunpeak dev` and its URL is injected into the Simulator
13
+ * The server is started by `sunpeak dev` and its URL is injected into the Inspector
14
14
  * via `__SUNPEAK_SANDBOX_URL__`.
15
15
  *
16
16
  * NOTE: The proxy HTML and mock openai script are duplicated from sandbox-proxy.ts
@@ -287,18 +287,18 @@ iframe { border: none; width: 100%; height: 100%; display: block; }
287
287
  */
288
288
  const MOCK_OPENAI_SCRIPT = [
289
289
  'window.openai={',
290
- 'uploadFile:function(f){console.log("[Simulator] uploadFile:",f.name);',
290
+ 'uploadFile:function(f){console.log("[Inspector] uploadFile:",f.name);',
291
291
  'return Promise.resolve({fileId:"sim_file_"+Date.now()})},',
292
- 'getFileDownloadUrl:function(p){console.log("[Simulator] getFileDownloadUrl:",p.fileId);',
293
- 'return Promise.resolve({downloadUrl:"https://simulator.local/files/"+p.fileId})},',
294
- 'requestModal:function(p){console.log("[Simulator] requestModal:",JSON.stringify(p));',
292
+ 'getFileDownloadUrl:function(p){console.log("[Inspector] getFileDownloadUrl:",p.fileId);',
293
+ 'return Promise.resolve({downloadUrl:"https://inspector.local/files/"+p.fileId})},',
294
+ 'requestModal:function(p){console.log("[Inspector] requestModal:",JSON.stringify(p));',
295
295
  'return Promise.resolve()},',
296
- 'requestCheckout:function(s){console.log("[Simulator] requestCheckout:",JSON.stringify(s));',
296
+ 'requestCheckout:function(s){console.log("[Inspector] requestCheckout:",JSON.stringify(s));',
297
297
  'return Promise.resolve({id:"sim_order_"+Date.now(),checkout_session_id:s.id||"sim_session",status:"completed"})},',
298
- 'requestClose:function(){console.log("[Simulator] requestClose")},',
299
- 'requestDisplayMode:function(p){console.log("[Simulator] requestDisplayMode:",p.mode);',
298
+ 'requestClose:function(){console.log("[Inspector] requestClose")},',
299
+ 'requestDisplayMode:function(p){console.log("[Inspector] requestDisplayMode:",p.mode);',
300
300
  'return Promise.resolve()},',
301
- 'sendFollowUpMessage:function(p){console.log("[Simulator] sendFollowUpMessage:",p.prompt)},',
302
- 'openExternal:function(p){console.log("[Simulator] openExternal:",p.href);window.open(p.href,"_blank")}',
301
+ 'sendFollowUpMessage:function(p){console.log("[Inspector] sendFollowUpMessage:",p.prompt)},',
302
+ 'openExternal:function(p){console.log("[Inspector] openExternal:",p.href);window.open(p.href,"_blank")}',
303
303
  '};',
304
304
  ].join('');
package/bin/sunpeak.js CHANGED
@@ -95,19 +95,19 @@ function getVersion() {
95
95
  {
96
96
  const resources = discoverResources();
97
97
  console.log(`
98
- ☀️ 🏔️ sunpeak - The ChatGPT App framework
98
+ ☀️ 🏔️ sunpeak - Inspector, testing framework, and app framework for MCP Apps
99
99
 
100
100
  Install:
101
101
  pnpm add -g sunpeak
102
102
 
103
103
  Usage:
104
104
  sunpeak new [name] [resources] Create a new project
105
- sunpeak dev Start dev server + MCP endpoint
105
+ sunpeak dev Start dev server + inspector + MCP endpoint
106
106
  --no-begging Suppress GitHub star message
107
107
  sunpeak build Build resources + tools for production
108
108
  sunpeak start Start production MCP server
109
109
  --port, -p Server port (default: 8000, or PORT env)
110
- sunpeak inspect Test an external MCP server in the simulator
110
+ sunpeak inspect Inspect any MCP server in the inspector
111
111
  --server, -s <url|cmd> MCP server URL or stdio command (required)
112
112
  --simulations <dir> Simulation JSON directory
113
113
  sunpeak upgrade Upgrade sunpeak to latest version
@@ -1,4 +1,4 @@
1
- import { ScreenWidth } from '../simulator/simulator-types';
1
+ import { ScreenWidth } from '../inspector/inspector-types';
2
2
  import { McpUiDisplayMode, McpUiHostContext } from '@modelcontextprotocol/ext-apps';
3
3
  import * as React from 'react';
4
4
  type Platform = NonNullable<McpUiHostContext['platform']>;
@@ -1,48 +1,48 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../chunk-9hOWP6kD.cjs");
3
3
  require("../protocol-jbxhzcnS.cjs");
4
- const require_simulator = require("../simulator-eU6sQTje.cjs");
5
- const require_simulator_url = require("../simulator-url-3ATCsPOT.cjs");
4
+ const require_inspector = require("../inspector-CByJjmPD.cjs");
5
+ const require_inspector_url = require("../inspector-url-7qhtJwY6.cjs");
6
6
  const require_discovery = require("../discovery-Clu4uHp1.cjs");
7
7
  //#region src/chatgpt/index.ts
8
8
  var chatgpt_exports = /* @__PURE__ */ require_chunk.__exportAll({
9
- IframeResource: () => require_simulator.IframeResource,
10
- McpAppHost: () => require_simulator.McpAppHost,
11
- SCREEN_WIDTHS: () => require_simulator.SCREEN_WIDTHS,
12
- Simulator: () => require_simulator.Simulator,
13
- ThemeProvider: () => require_simulator.ThemeProvider,
14
- createSimulatorUrl: () => require_simulator_url.createSimulatorUrl,
15
- extractResourceCSP: () => require_simulator.extractResourceCSP,
9
+ IframeResource: () => require_inspector.IframeResource,
10
+ Inspector: () => require_inspector.Inspector,
11
+ McpAppHost: () => require_inspector.McpAppHost,
12
+ SCREEN_WIDTHS: () => require_inspector.SCREEN_WIDTHS,
13
+ ThemeProvider: () => require_inspector.ThemeProvider,
14
+ createInspectorUrl: () => require_inspector_url.createInspectorUrl,
15
+ extractResourceCSP: () => require_inspector.extractResourceCSP,
16
16
  extractResourceKey: () => require_discovery.extractResourceKey,
17
17
  extractSimulationKey: () => require_discovery.extractSimulationKey,
18
18
  findResourceDirs: () => require_discovery.findResourceDirs,
19
19
  findResourceKey: () => require_discovery.findResourceKey,
20
20
  getComponentName: () => require_discovery.getComponentName,
21
- resolveServerToolResult: () => require_simulator.resolveServerToolResult,
21
+ resolveServerToolResult: () => require_inspector.resolveServerToolResult,
22
22
  toPascalCase: () => require_discovery.toPascalCase,
23
- useThemeContext: () => require_simulator.useThemeContext
23
+ useThemeContext: () => require_inspector.useThemeContext
24
24
  });
25
25
  //#endregion
26
- exports.IframeResource = require_simulator.IframeResource;
27
- exports.McpAppHost = require_simulator.McpAppHost;
28
- exports.SCREEN_WIDTHS = require_simulator.SCREEN_WIDTHS;
29
- exports.Simulator = require_simulator.Simulator;
30
- exports.ThemeProvider = require_simulator.ThemeProvider;
26
+ exports.IframeResource = require_inspector.IframeResource;
27
+ exports.Inspector = require_inspector.Inspector;
28
+ exports.McpAppHost = require_inspector.McpAppHost;
29
+ exports.SCREEN_WIDTHS = require_inspector.SCREEN_WIDTHS;
30
+ exports.ThemeProvider = require_inspector.ThemeProvider;
31
31
  Object.defineProperty(exports, "chatgpt_exports", {
32
32
  enumerable: true,
33
33
  get: function() {
34
34
  return chatgpt_exports;
35
35
  }
36
36
  });
37
- exports.createSimulatorUrl = require_simulator_url.createSimulatorUrl;
38
- exports.extractResourceCSP = require_simulator.extractResourceCSP;
37
+ exports.createInspectorUrl = require_inspector_url.createInspectorUrl;
38
+ exports.extractResourceCSP = require_inspector.extractResourceCSP;
39
39
  exports.extractResourceKey = require_discovery.extractResourceKey;
40
40
  exports.extractSimulationKey = require_discovery.extractSimulationKey;
41
41
  exports.findResourceDirs = require_discovery.findResourceDirs;
42
42
  exports.findResourceKey = require_discovery.findResourceKey;
43
43
  exports.getComponentName = require_discovery.getComponentName;
44
- exports.resolveServerToolResult = require_simulator.resolveServerToolResult;
44
+ exports.resolveServerToolResult = require_inspector.resolveServerToolResult;
45
45
  exports.toPascalCase = require_discovery.toPascalCase;
46
- exports.useThemeContext = require_simulator.useThemeContext;
46
+ exports.useThemeContext = require_inspector.useThemeContext;
47
47
 
48
48
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak simulator.\n *\n * @module sunpeak/chatgpt\n */\n\n// Register ChatGPT host shell (side effect)\nimport './chatgpt-host';\n\n// Simulator\nexport { Simulator } from '../simulator/simulator';\n\n// Simulator types\nexport type { Simulation, ServerToolMock } from '../types/simulation';\nexport { resolveServerToolResult } from '../types/simulation';\nexport type { ScreenWidth, SimulatorConfig } from '../simulator/simulator-types';\nexport { SCREEN_WIDTHS } from '../simulator/simulator-types';\n\n// Host bridge (for building custom simulators or test harnesses)\nexport { McpAppHost } from '../simulator/mcp-app-host';\nexport type { McpAppHostOptions } from '../simulator/mcp-app-host';\n\n// Iframe rendering (used internally by simulator)\nexport { IframeResource, extractResourceCSP } from '../simulator/iframe-resource';\nexport type { ResourceCSP } from '../simulator/iframe-resource';\n\n// Theme provider\nexport * from '../simulator/theme-provider';\n\n// URL helpers\nexport { createSimulatorUrl } from '../simulator/simulator-url';\nexport type { SimulatorUrlParams } from '../simulator/simulator-url';\n\n// Discovery utilities\nexport {\n toPascalCase,\n extractResourceKey,\n extractSimulationKey,\n findResourceKey,\n getComponentName,\n findResourceDirs,\n} from '../lib/discovery';\nexport type { ResourceDirInfo, FsOps } from '../lib/discovery';\n"],"mappings":""}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak inspector.\n *\n * @module sunpeak/chatgpt\n */\n\n// Register ChatGPT host shell (side effect)\nimport './chatgpt-host';\n\n// Inspector\nexport { Inspector } from '../inspector/inspector';\n\n// Inspector types\nexport type { Simulation, ServerToolMock } from '../types/simulation';\nexport { resolveServerToolResult } from '../types/simulation';\nexport type { ScreenWidth, InspectorConfig } from '../inspector/inspector-types';\nexport { SCREEN_WIDTHS } from '../inspector/inspector-types';\n\n// Host bridge (for building custom inspectors or test harnesses)\nexport { McpAppHost } from '../inspector/mcp-app-host';\nexport type { McpAppHostOptions } from '../inspector/mcp-app-host';\n\n// Iframe rendering (used internally by inspector)\nexport { IframeResource, extractResourceCSP } from '../inspector/iframe-resource';\nexport type { ResourceCSP } from '../inspector/iframe-resource';\n\n// Theme provider\nexport * from '../inspector/theme-provider';\n\n// URL helpers\nexport { createInspectorUrl } from '../inspector/inspector-url';\nexport type { InspectorUrlParams } from '../inspector/inspector-url';\n\n// Discovery utilities\nexport {\n toPascalCase,\n extractResourceKey,\n extractSimulationKey,\n findResourceKey,\n getComponentName,\n findResourceDirs,\n} from '../lib/discovery';\nexport type { ResourceDirInfo, FsOps } from '../lib/discovery';\n"],"mappings":""}
@@ -1,14 +1,14 @@
1
- export { Simulator } from '../simulator/simulator';
1
+ export { Inspector } from '../inspector/inspector';
2
2
  export type { Simulation, ServerToolMock } from '../types/simulation';
3
3
  export { resolveServerToolResult } from '../types/simulation';
4
- export type { ScreenWidth, SimulatorConfig } from '../simulator/simulator-types';
5
- export { SCREEN_WIDTHS } from '../simulator/simulator-types';
6
- export { McpAppHost } from '../simulator/mcp-app-host';
7
- export type { McpAppHostOptions } from '../simulator/mcp-app-host';
8
- export { IframeResource, extractResourceCSP } from '../simulator/iframe-resource';
9
- export type { ResourceCSP } from '../simulator/iframe-resource';
10
- export * from '../simulator/theme-provider';
11
- export { createSimulatorUrl } from '../simulator/simulator-url';
12
- export type { SimulatorUrlParams } from '../simulator/simulator-url';
4
+ export type { ScreenWidth, InspectorConfig } from '../inspector/inspector-types';
5
+ export { SCREEN_WIDTHS } from '../inspector/inspector-types';
6
+ export { McpAppHost } from '../inspector/mcp-app-host';
7
+ export type { McpAppHostOptions } from '../inspector/mcp-app-host';
8
+ export { IframeResource, extractResourceCSP } from '../inspector/iframe-resource';
9
+ export type { ResourceCSP } from '../inspector/iframe-resource';
10
+ export * from '../inspector/theme-provider';
11
+ export { createInspectorUrl } from '../inspector/inspector-url';
12
+ export type { InspectorUrlParams } from '../inspector/inspector-url';
13
13
  export { toPascalCase, extractResourceKey, extractSimulationKey, findResourceKey, getComponentName, findResourceDirs, } from '../lib/discovery';
14
14
  export type { ResourceDirInfo, FsOps } from '../lib/discovery';
@@ -1,16 +1,16 @@
1
1
  import { r as __exportAll } from "../chunk-D6g4UhsZ.js";
2
2
  import "../protocol-DJmRaBzO.js";
3
- import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Simulator, v as SCREEN_WIDTHS } from "../simulator-0dAb16Qt.js";
4
- import { t as createSimulatorUrl } from "../simulator-url-BbuuWa7S.js";
3
+ import { _ as McpAppHost, d as ThemeProvider, f as useThemeContext, g as extractResourceCSP, h as IframeResource, n as resolveServerToolResult, t as Inspector, v as SCREEN_WIDTHS } from "../inspector-ClhpqKLi.js";
4
+ import { t as createInspectorUrl } from "../inspector-url-DuEFmxLP.js";
5
5
  import { c as toPascalCase, i as findResourceKey, n as extractSimulationKey, r as findResourceDirs, s as getComponentName, t as extractResourceKey } from "../discovery-Cgoegt62.js";
6
6
  //#region src/chatgpt/index.ts
7
7
  var chatgpt_exports = /* @__PURE__ */ __exportAll({
8
8
  IframeResource: () => IframeResource,
9
+ Inspector: () => Inspector,
9
10
  McpAppHost: () => McpAppHost,
10
11
  SCREEN_WIDTHS: () => SCREEN_WIDTHS,
11
- Simulator: () => Simulator,
12
12
  ThemeProvider: () => ThemeProvider,
13
- createSimulatorUrl: () => createSimulatorUrl,
13
+ createInspectorUrl: () => createInspectorUrl,
14
14
  extractResourceCSP: () => extractResourceCSP,
15
15
  extractResourceKey: () => extractResourceKey,
16
16
  extractSimulationKey: () => extractSimulationKey,
@@ -22,6 +22,6 @@ var chatgpt_exports = /* @__PURE__ */ __exportAll({
22
22
  useThemeContext: () => useThemeContext
23
23
  });
24
24
  //#endregion
25
- export { IframeResource, McpAppHost, SCREEN_WIDTHS, Simulator, ThemeProvider, createSimulatorUrl, extractResourceCSP, extractResourceKey, extractSimulationKey, findResourceDirs, findResourceKey, getComponentName, resolveServerToolResult, chatgpt_exports as t, toPascalCase, useThemeContext };
25
+ export { IframeResource, Inspector, McpAppHost, SCREEN_WIDTHS, ThemeProvider, createInspectorUrl, extractResourceCSP, extractResourceKey, extractSimulationKey, findResourceDirs, findResourceKey, getComponentName, resolveServerToolResult, chatgpt_exports as t, toPascalCase, useThemeContext };
26
26
 
27
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak simulator.\n *\n * @module sunpeak/chatgpt\n */\n\n// Register ChatGPT host shell (side effect)\nimport './chatgpt-host';\n\n// Simulator\nexport { Simulator } from '../simulator/simulator';\n\n// Simulator types\nexport type { Simulation, ServerToolMock } from '../types/simulation';\nexport { resolveServerToolResult } from '../types/simulation';\nexport type { ScreenWidth, SimulatorConfig } from '../simulator/simulator-types';\nexport { SCREEN_WIDTHS } from '../simulator/simulator-types';\n\n// Host bridge (for building custom simulators or test harnesses)\nexport { McpAppHost } from '../simulator/mcp-app-host';\nexport type { McpAppHostOptions } from '../simulator/mcp-app-host';\n\n// Iframe rendering (used internally by simulator)\nexport { IframeResource, extractResourceCSP } from '../simulator/iframe-resource';\nexport type { ResourceCSP } from '../simulator/iframe-resource';\n\n// Theme provider\nexport * from '../simulator/theme-provider';\n\n// URL helpers\nexport { createSimulatorUrl } from '../simulator/simulator-url';\nexport type { SimulatorUrlParams } from '../simulator/simulator-url';\n\n// Discovery utilities\nexport {\n toPascalCase,\n extractResourceKey,\n extractSimulationKey,\n findResourceKey,\n getComponentName,\n findResourceDirs,\n} from '../lib/discovery';\nexport type { ResourceDirInfo, FsOps } from '../lib/discovery';\n"],"mappings":""}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/chatgpt/index.ts"],"sourcesContent":["/**\n * ChatGPT-specific exports for the Sunpeak inspector.\n *\n * @module sunpeak/chatgpt\n */\n\n// Register ChatGPT host shell (side effect)\nimport './chatgpt-host';\n\n// Inspector\nexport { Inspector } from '../inspector/inspector';\n\n// Inspector types\nexport type { Simulation, ServerToolMock } from '../types/simulation';\nexport { resolveServerToolResult } from '../types/simulation';\nexport type { ScreenWidth, InspectorConfig } from '../inspector/inspector-types';\nexport { SCREEN_WIDTHS } from '../inspector/inspector-types';\n\n// Host bridge (for building custom inspectors or test harnesses)\nexport { McpAppHost } from '../inspector/mcp-app-host';\nexport type { McpAppHostOptions } from '../inspector/mcp-app-host';\n\n// Iframe rendering (used internally by inspector)\nexport { IframeResource, extractResourceCSP } from '../inspector/iframe-resource';\nexport type { ResourceCSP } from '../inspector/iframe-resource';\n\n// Theme provider\nexport * from '../inspector/theme-provider';\n\n// URL helpers\nexport { createInspectorUrl } from '../inspector/inspector-url';\nexport type { InspectorUrlParams } from '../inspector/inspector-url';\n\n// Discovery utilities\nexport {\n toPascalCase,\n extractResourceKey,\n extractSimulationKey,\n findResourceKey,\n getComponentName,\n findResourceDirs,\n} from '../lib/discovery';\nexport type { ResourceDirInfo, FsOps } from '../lib/discovery';\n"],"mappings":""}