sunpeak 0.18.6 → 0.18.7
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/dev.mjs +6 -2
- package/bin/commands/inspect.mjs +13 -1
- package/bin/commands/new.mjs +5 -0
- package/bin/lib/dev-overlay.mjs +50 -0
- package/bin/lib/live/live-config.d.mts +3 -0
- package/bin/lib/live/live-config.mjs +3 -1
- package/dist/chatgpt/index.cjs +2 -2
- package/dist/chatgpt/index.js +2 -2
- package/dist/claude/index.cjs +1 -1
- package/dist/claude/index.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/inspector/index.cjs +2 -2
- package/dist/inspector/index.js +2 -2
- package/dist/inspector/inspector-url.d.ts +13 -0
- package/dist/inspector/use-inspector-state.d.ts +2 -0
- package/dist/{inspector-DRD_Q66E.cjs → inspector-CKc58UuI.cjs} +60 -19
- package/dist/inspector-CKc58UuI.cjs.map +1 -0
- package/dist/{inspector-CjSoXm6N.js → inspector-DZrN0kej.js} +60 -19
- package/dist/inspector-DZrN0kej.js.map +1 -0
- package/dist/{inspector-url-7qhtJwY6.cjs → inspector-url-C3LTKgXt.cjs} +3 -1
- package/dist/inspector-url-C3LTKgXt.cjs.map +1 -0
- package/dist/{inspector-url-DuEFmxLP.js → inspector-url-CyQcuBI9.js} +3 -1
- package/dist/inspector-url-CyQcuBI9.js.map +1 -0
- package/dist/mcp/index.cjs +81 -7
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +81 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/style.css +4 -0
- package/package.json +1 -1
- package/template/dist/albums/albums.html +1 -1
- package/template/dist/albums/albums.json +1 -1
- package/template/dist/carousel/carousel.html +1 -1
- package/template/dist/carousel/carousel.json +1 -1
- package/template/dist/map/map.html +1 -1
- package/template/dist/map/map.json +1 -1
- package/template/dist/review/review.html +1 -1
- package/template/dist/review/review.json +1 -1
- package/template/tests/e2e/albums.spec.ts +1 -1
- package/template/tests/e2e/carousel.spec.ts +1 -1
- package/template/tests/e2e/dev-overlay.spec.ts +118 -0
- package/template/tests/e2e/helpers.ts +13 -0
- package/template/tests/e2e/map.spec.ts +1 -1
- package/template/tests/e2e/review.spec.ts +1 -1
- package/template/tests/live/playwright.config.ts +1 -1
- package/dist/inspector-CjSoXm6N.js.map +0 -1
- package/dist/inspector-DRD_Q66E.cjs.map +0 -1
- package/dist/inspector-url-7qhtJwY6.cjs.map +0 -1
- package/dist/inspector-url-DuEFmxLP.js.map +0 -1
|
@@ -38,6 +38,8 @@ function createInspectorUrl(params, basePath = "/") {
|
|
|
38
38
|
if (params.safeAreaLeft !== void 0) searchParams.set("safeAreaLeft", String(params.safeAreaLeft));
|
|
39
39
|
if (params.safeAreaRight !== void 0) searchParams.set("safeAreaRight", String(params.safeAreaRight));
|
|
40
40
|
if (params.prodResources !== void 0) searchParams.set("prodResources", String(params.prodResources));
|
|
41
|
+
if (params.sidebar !== void 0) searchParams.set("sidebar", String(params.sidebar));
|
|
42
|
+
if (params.devOverlay !== void 0) searchParams.set("devOverlay", String(params.devOverlay));
|
|
41
43
|
const queryString = searchParams.toString();
|
|
42
44
|
return queryString ? `${basePath}?${queryString}` : basePath;
|
|
43
45
|
}
|
|
@@ -49,4 +51,4 @@ Object.defineProperty(exports, "createInspectorUrl", {
|
|
|
49
51
|
}
|
|
50
52
|
});
|
|
51
53
|
|
|
52
|
-
//# sourceMappingURL=inspector-url-
|
|
54
|
+
//# sourceMappingURL=inspector-url-C3LTKgXt.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspector-url-C3LTKgXt.cjs","names":[],"sources":["../src/inspector/inspector-url.ts"],"sourcesContent":["import type { Theme, DisplayMode, DeviceType } from '../types/runtime';\n\n/**\n * Strongly-typed URL parameters for the Inspector.\n *\n * Use with `createInspectorUrl()` to generate type-safe URL paths for e2e tests.\n *\n * The two primary selectors mirror the sidebar dropdowns:\n * - `tool` — which tool to inspect (Tool dropdown)\n * - `simulation` — which simulation fixture to load (Simulation dropdown)\n *\n * When only `tool` is specified, no mock data is loaded (\"Press Run\" state).\n * When `simulation` is specified, mock data from that fixture renders immediately.\n * When both are specified, the tool is selected and the simulation provides mock data.\n *\n * @example\n * ```ts\n * import { createInspectorUrl } from 'sunpeak/inspector';\n *\n * // Select a tool with no mock data (user must click Run):\n * await page.goto(createInspectorUrl({ tool: 'show-albums' }));\n *\n * // Select a simulation (mock data renders immediately):\n * await page.goto(createInspectorUrl({ simulation: 'show-albums' }));\n *\n * // Full options:\n * await page.goto(createInspectorUrl({\n * simulation: 'show-albums',\n * theme: 'dark',\n * host: 'claude',\n * }));\n * ```\n */\nexport interface InspectorUrlParams {\n /**\n * The simulation name to load (e.g., 'show-albums', 'review-diff').\n * Corresponds to the simulation JSON filename without the `.json` extension.\n * When specified, mock data from the simulation fixture renders immediately.\n */\n simulation?: string;\n\n /**\n * The tool name to select (e.g., 'show-albums', 'show-map').\n * When specified without `simulation`, no mock data is loaded — the user\n * must click Run to call the real handler.\n */\n tool?: string;\n\n /**\n * The host shell to use (e.g., 'chatgpt', 'claude').\n * Switches conversation chrome, theming, and reported host info/capabilities.\n * @default 'chatgpt'\n */\n host?: string;\n\n /**\n * The color theme for the inspector.\n * @default 'dark'\n */\n theme?: Theme;\n\n /**\n * The display mode for the widget.\n * - 'inline': Embedded in the conversation\n * - 'pip': Picture-in-picture mode with max height\n * - 'fullscreen': Full screen overlay\n * @default 'inline'\n */\n displayMode?: DisplayMode;\n\n /**\n * The locale for the inspector (e.g., 'en-US', 'ja-JP').\n * @default 'en-US'\n */\n locale?: string;\n\n /**\n * Maximum height in pixels for PiP mode.\n * Only applicable when displayMode is 'pip'.\n */\n maxHeight?: number;\n\n /**\n * The device type to simulate.\n * Affects default hover/touch capabilities.\n */\n deviceType?: DeviceType;\n\n /**\n * Whether the device supports hover interactions.\n * @default true for desktop, false for mobile/tablet\n */\n hover?: boolean;\n\n /**\n * Whether the device supports touch interactions.\n * @default false for desktop, true for mobile/tablet\n */\n touch?: boolean;\n\n /**\n * Safe area inset from the top of the screen (in pixels).\n * Used for devices with notches or status bars.\n */\n safeAreaTop?: number;\n\n /**\n * Safe area inset from the bottom of the screen (in pixels).\n * Used for devices with home indicators.\n */\n safeAreaBottom?: number;\n\n /**\n * Safe area inset from the left of the screen (in pixels).\n */\n safeAreaLeft?: number;\n\n /**\n * Safe area inset from the right of the screen (in pixels).\n */\n safeAreaRight?: number;\n\n /**\n * Enable Prod Resources mode (production dist/ bundles instead of HMR).\n */\n prodResources?: boolean;\n\n /**\n * Show the inspector sidebar. Useful for headless testing or embedding\n * the inspector as a pure resource viewer.\n * @default true\n */\n sidebar?: boolean;\n\n /**\n * Show the dev overlay (resource timestamp + tool timing) inside resources.\n * Set to false to hide it during e2e tests so it doesn't interfere with\n * element assertions.\n * @default true\n */\n devOverlay?: boolean;\n}\n\n/**\n * Creates a URL path with query parameters for the Inspector.\n *\n * @param params - The inspector parameters to encode\n * @param basePath - The base path for the URL (default: '/')\n * @returns A URL path string with encoded query parameters\n *\n * @example\n * ```ts\n * // Tool only (no mock data, \"Press Run\" state):\n * createInspectorUrl({ tool: 'show-albums' })\n * // Returns: '/?tool=show-albums'\n *\n * // Simulation (mock data renders immediately):\n * createInspectorUrl({ simulation: 'show-albums', theme: 'light' })\n * // Returns: '/?simulation=show-albums&theme=light'\n *\n * // Both tool and simulation:\n * createInspectorUrl({ tool: 'show-albums', simulation: 'show-albums' })\n * // Returns: '/?tool=show-albums&simulation=show-albums'\n * ```\n */\nexport function createInspectorUrl(params: InspectorUrlParams, basePath = '/'): string {\n const searchParams = new URLSearchParams();\n\n if (params.tool !== undefined) {\n searchParams.set('tool', params.tool);\n }\n if (params.simulation !== undefined) {\n searchParams.set('simulation', params.simulation);\n }\n if (params.host !== undefined) {\n searchParams.set('host', params.host);\n }\n if (params.theme !== undefined) {\n searchParams.set('theme', params.theme);\n }\n if (params.displayMode !== undefined) {\n searchParams.set('displayMode', params.displayMode);\n }\n if (params.locale !== undefined) {\n searchParams.set('locale', params.locale);\n }\n if (params.maxHeight !== undefined) {\n searchParams.set('maxHeight', String(params.maxHeight));\n }\n if (params.deviceType !== undefined) {\n searchParams.set('deviceType', params.deviceType);\n }\n if (params.hover !== undefined) {\n searchParams.set('hover', String(params.hover));\n }\n if (params.touch !== undefined) {\n searchParams.set('touch', String(params.touch));\n }\n if (params.safeAreaTop !== undefined) {\n searchParams.set('safeAreaTop', String(params.safeAreaTop));\n }\n if (params.safeAreaBottom !== undefined) {\n searchParams.set('safeAreaBottom', String(params.safeAreaBottom));\n }\n if (params.safeAreaLeft !== undefined) {\n searchParams.set('safeAreaLeft', String(params.safeAreaLeft));\n }\n if (params.safeAreaRight !== undefined) {\n searchParams.set('safeAreaRight', String(params.safeAreaRight));\n }\n if (params.prodResources !== undefined) {\n searchParams.set('prodResources', String(params.prodResources));\n }\n if (params.sidebar !== undefined) {\n searchParams.set('sidebar', String(params.sidebar));\n }\n if (params.devOverlay !== undefined) {\n searchParams.set('devOverlay', String(params.devOverlay));\n }\n\n const queryString = searchParams.toString();\n return queryString ? `${basePath}?${queryString}` : basePath;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqKA,SAAgB,mBAAmB,QAA4B,WAAW,KAAa;CACrF,MAAM,eAAe,IAAI,iBAAiB;AAE1C,KAAI,OAAO,SAAS,KAAA,EAClB,cAAa,IAAI,QAAQ,OAAO,KAAK;AAEvC,KAAI,OAAO,eAAe,KAAA,EACxB,cAAa,IAAI,cAAc,OAAO,WAAW;AAEnD,KAAI,OAAO,SAAS,KAAA,EAClB,cAAa,IAAI,QAAQ,OAAO,KAAK;AAEvC,KAAI,OAAO,UAAU,KAAA,EACnB,cAAa,IAAI,SAAS,OAAO,MAAM;AAEzC,KAAI,OAAO,gBAAgB,KAAA,EACzB,cAAa,IAAI,eAAe,OAAO,YAAY;AAErD,KAAI,OAAO,WAAW,KAAA,EACpB,cAAa,IAAI,UAAU,OAAO,OAAO;AAE3C,KAAI,OAAO,cAAc,KAAA,EACvB,cAAa,IAAI,aAAa,OAAO,OAAO,UAAU,CAAC;AAEzD,KAAI,OAAO,eAAe,KAAA,EACxB,cAAa,IAAI,cAAc,OAAO,WAAW;AAEnD,KAAI,OAAO,UAAU,KAAA,EACnB,cAAa,IAAI,SAAS,OAAO,OAAO,MAAM,CAAC;AAEjD,KAAI,OAAO,UAAU,KAAA,EACnB,cAAa,IAAI,SAAS,OAAO,OAAO,MAAM,CAAC;AAEjD,KAAI,OAAO,gBAAgB,KAAA,EACzB,cAAa,IAAI,eAAe,OAAO,OAAO,YAAY,CAAC;AAE7D,KAAI,OAAO,mBAAmB,KAAA,EAC5B,cAAa,IAAI,kBAAkB,OAAO,OAAO,eAAe,CAAC;AAEnE,KAAI,OAAO,iBAAiB,KAAA,EAC1B,cAAa,IAAI,gBAAgB,OAAO,OAAO,aAAa,CAAC;AAE/D,KAAI,OAAO,kBAAkB,KAAA,EAC3B,cAAa,IAAI,iBAAiB,OAAO,OAAO,cAAc,CAAC;AAEjE,KAAI,OAAO,kBAAkB,KAAA,EAC3B,cAAa,IAAI,iBAAiB,OAAO,OAAO,cAAc,CAAC;AAEjE,KAAI,OAAO,YAAY,KAAA,EACrB,cAAa,IAAI,WAAW,OAAO,OAAO,QAAQ,CAAC;AAErD,KAAI,OAAO,eAAe,KAAA,EACxB,cAAa,IAAI,cAAc,OAAO,OAAO,WAAW,CAAC;CAG3D,MAAM,cAAc,aAAa,UAAU;AAC3C,QAAO,cAAc,GAAG,SAAS,GAAG,gBAAgB"}
|
|
@@ -38,10 +38,12 @@ function createInspectorUrl(params, basePath = "/") {
|
|
|
38
38
|
if (params.safeAreaLeft !== void 0) searchParams.set("safeAreaLeft", String(params.safeAreaLeft));
|
|
39
39
|
if (params.safeAreaRight !== void 0) searchParams.set("safeAreaRight", String(params.safeAreaRight));
|
|
40
40
|
if (params.prodResources !== void 0) searchParams.set("prodResources", String(params.prodResources));
|
|
41
|
+
if (params.sidebar !== void 0) searchParams.set("sidebar", String(params.sidebar));
|
|
42
|
+
if (params.devOverlay !== void 0) searchParams.set("devOverlay", String(params.devOverlay));
|
|
41
43
|
const queryString = searchParams.toString();
|
|
42
44
|
return queryString ? `${basePath}?${queryString}` : basePath;
|
|
43
45
|
}
|
|
44
46
|
//#endregion
|
|
45
47
|
export { createInspectorUrl as t };
|
|
46
48
|
|
|
47
|
-
//# sourceMappingURL=inspector-url-
|
|
49
|
+
//# sourceMappingURL=inspector-url-CyQcuBI9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspector-url-CyQcuBI9.js","names":[],"sources":["../src/inspector/inspector-url.ts"],"sourcesContent":["import type { Theme, DisplayMode, DeviceType } from '../types/runtime';\n\n/**\n * Strongly-typed URL parameters for the Inspector.\n *\n * Use with `createInspectorUrl()` to generate type-safe URL paths for e2e tests.\n *\n * The two primary selectors mirror the sidebar dropdowns:\n * - `tool` — which tool to inspect (Tool dropdown)\n * - `simulation` — which simulation fixture to load (Simulation dropdown)\n *\n * When only `tool` is specified, no mock data is loaded (\"Press Run\" state).\n * When `simulation` is specified, mock data from that fixture renders immediately.\n * When both are specified, the tool is selected and the simulation provides mock data.\n *\n * @example\n * ```ts\n * import { createInspectorUrl } from 'sunpeak/inspector';\n *\n * // Select a tool with no mock data (user must click Run):\n * await page.goto(createInspectorUrl({ tool: 'show-albums' }));\n *\n * // Select a simulation (mock data renders immediately):\n * await page.goto(createInspectorUrl({ simulation: 'show-albums' }));\n *\n * // Full options:\n * await page.goto(createInspectorUrl({\n * simulation: 'show-albums',\n * theme: 'dark',\n * host: 'claude',\n * }));\n * ```\n */\nexport interface InspectorUrlParams {\n /**\n * The simulation name to load (e.g., 'show-albums', 'review-diff').\n * Corresponds to the simulation JSON filename without the `.json` extension.\n * When specified, mock data from the simulation fixture renders immediately.\n */\n simulation?: string;\n\n /**\n * The tool name to select (e.g., 'show-albums', 'show-map').\n * When specified without `simulation`, no mock data is loaded — the user\n * must click Run to call the real handler.\n */\n tool?: string;\n\n /**\n * The host shell to use (e.g., 'chatgpt', 'claude').\n * Switches conversation chrome, theming, and reported host info/capabilities.\n * @default 'chatgpt'\n */\n host?: string;\n\n /**\n * The color theme for the inspector.\n * @default 'dark'\n */\n theme?: Theme;\n\n /**\n * The display mode for the widget.\n * - 'inline': Embedded in the conversation\n * - 'pip': Picture-in-picture mode with max height\n * - 'fullscreen': Full screen overlay\n * @default 'inline'\n */\n displayMode?: DisplayMode;\n\n /**\n * The locale for the inspector (e.g., 'en-US', 'ja-JP').\n * @default 'en-US'\n */\n locale?: string;\n\n /**\n * Maximum height in pixels for PiP mode.\n * Only applicable when displayMode is 'pip'.\n */\n maxHeight?: number;\n\n /**\n * The device type to simulate.\n * Affects default hover/touch capabilities.\n */\n deviceType?: DeviceType;\n\n /**\n * Whether the device supports hover interactions.\n * @default true for desktop, false for mobile/tablet\n */\n hover?: boolean;\n\n /**\n * Whether the device supports touch interactions.\n * @default false for desktop, true for mobile/tablet\n */\n touch?: boolean;\n\n /**\n * Safe area inset from the top of the screen (in pixels).\n * Used for devices with notches or status bars.\n */\n safeAreaTop?: number;\n\n /**\n * Safe area inset from the bottom of the screen (in pixels).\n * Used for devices with home indicators.\n */\n safeAreaBottom?: number;\n\n /**\n * Safe area inset from the left of the screen (in pixels).\n */\n safeAreaLeft?: number;\n\n /**\n * Safe area inset from the right of the screen (in pixels).\n */\n safeAreaRight?: number;\n\n /**\n * Enable Prod Resources mode (production dist/ bundles instead of HMR).\n */\n prodResources?: boolean;\n\n /**\n * Show the inspector sidebar. Useful for headless testing or embedding\n * the inspector as a pure resource viewer.\n * @default true\n */\n sidebar?: boolean;\n\n /**\n * Show the dev overlay (resource timestamp + tool timing) inside resources.\n * Set to false to hide it during e2e tests so it doesn't interfere with\n * element assertions.\n * @default true\n */\n devOverlay?: boolean;\n}\n\n/**\n * Creates a URL path with query parameters for the Inspector.\n *\n * @param params - The inspector parameters to encode\n * @param basePath - The base path for the URL (default: '/')\n * @returns A URL path string with encoded query parameters\n *\n * @example\n * ```ts\n * // Tool only (no mock data, \"Press Run\" state):\n * createInspectorUrl({ tool: 'show-albums' })\n * // Returns: '/?tool=show-albums'\n *\n * // Simulation (mock data renders immediately):\n * createInspectorUrl({ simulation: 'show-albums', theme: 'light' })\n * // Returns: '/?simulation=show-albums&theme=light'\n *\n * // Both tool and simulation:\n * createInspectorUrl({ tool: 'show-albums', simulation: 'show-albums' })\n * // Returns: '/?tool=show-albums&simulation=show-albums'\n * ```\n */\nexport function createInspectorUrl(params: InspectorUrlParams, basePath = '/'): string {\n const searchParams = new URLSearchParams();\n\n if (params.tool !== undefined) {\n searchParams.set('tool', params.tool);\n }\n if (params.simulation !== undefined) {\n searchParams.set('simulation', params.simulation);\n }\n if (params.host !== undefined) {\n searchParams.set('host', params.host);\n }\n if (params.theme !== undefined) {\n searchParams.set('theme', params.theme);\n }\n if (params.displayMode !== undefined) {\n searchParams.set('displayMode', params.displayMode);\n }\n if (params.locale !== undefined) {\n searchParams.set('locale', params.locale);\n }\n if (params.maxHeight !== undefined) {\n searchParams.set('maxHeight', String(params.maxHeight));\n }\n if (params.deviceType !== undefined) {\n searchParams.set('deviceType', params.deviceType);\n }\n if (params.hover !== undefined) {\n searchParams.set('hover', String(params.hover));\n }\n if (params.touch !== undefined) {\n searchParams.set('touch', String(params.touch));\n }\n if (params.safeAreaTop !== undefined) {\n searchParams.set('safeAreaTop', String(params.safeAreaTop));\n }\n if (params.safeAreaBottom !== undefined) {\n searchParams.set('safeAreaBottom', String(params.safeAreaBottom));\n }\n if (params.safeAreaLeft !== undefined) {\n searchParams.set('safeAreaLeft', String(params.safeAreaLeft));\n }\n if (params.safeAreaRight !== undefined) {\n searchParams.set('safeAreaRight', String(params.safeAreaRight));\n }\n if (params.prodResources !== undefined) {\n searchParams.set('prodResources', String(params.prodResources));\n }\n if (params.sidebar !== undefined) {\n searchParams.set('sidebar', String(params.sidebar));\n }\n if (params.devOverlay !== undefined) {\n searchParams.set('devOverlay', String(params.devOverlay));\n }\n\n const queryString = searchParams.toString();\n return queryString ? `${basePath}?${queryString}` : basePath;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqKA,SAAgB,mBAAmB,QAA4B,WAAW,KAAa;CACrF,MAAM,eAAe,IAAI,iBAAiB;AAE1C,KAAI,OAAO,SAAS,KAAA,EAClB,cAAa,IAAI,QAAQ,OAAO,KAAK;AAEvC,KAAI,OAAO,eAAe,KAAA,EACxB,cAAa,IAAI,cAAc,OAAO,WAAW;AAEnD,KAAI,OAAO,SAAS,KAAA,EAClB,cAAa,IAAI,QAAQ,OAAO,KAAK;AAEvC,KAAI,OAAO,UAAU,KAAA,EACnB,cAAa,IAAI,SAAS,OAAO,MAAM;AAEzC,KAAI,OAAO,gBAAgB,KAAA,EACzB,cAAa,IAAI,eAAe,OAAO,YAAY;AAErD,KAAI,OAAO,WAAW,KAAA,EACpB,cAAa,IAAI,UAAU,OAAO,OAAO;AAE3C,KAAI,OAAO,cAAc,KAAA,EACvB,cAAa,IAAI,aAAa,OAAO,OAAO,UAAU,CAAC;AAEzD,KAAI,OAAO,eAAe,KAAA,EACxB,cAAa,IAAI,cAAc,OAAO,WAAW;AAEnD,KAAI,OAAO,UAAU,KAAA,EACnB,cAAa,IAAI,SAAS,OAAO,OAAO,MAAM,CAAC;AAEjD,KAAI,OAAO,UAAU,KAAA,EACnB,cAAa,IAAI,SAAS,OAAO,OAAO,MAAM,CAAC;AAEjD,KAAI,OAAO,gBAAgB,KAAA,EACzB,cAAa,IAAI,eAAe,OAAO,OAAO,YAAY,CAAC;AAE7D,KAAI,OAAO,mBAAmB,KAAA,EAC5B,cAAa,IAAI,kBAAkB,OAAO,OAAO,eAAe,CAAC;AAEnE,KAAI,OAAO,iBAAiB,KAAA,EAC1B,cAAa,IAAI,gBAAgB,OAAO,OAAO,aAAa,CAAC;AAE/D,KAAI,OAAO,kBAAkB,KAAA,EAC3B,cAAa,IAAI,iBAAiB,OAAO,OAAO,cAAc,CAAC;AAEjE,KAAI,OAAO,kBAAkB,KAAA,EAC3B,cAAa,IAAI,iBAAiB,OAAO,OAAO,cAAc,CAAC;AAEjE,KAAI,OAAO,YAAY,KAAA,EACrB,cAAa,IAAI,WAAW,OAAO,OAAO,QAAQ,CAAC;AAErD,KAAI,OAAO,eAAe,KAAA,EACxB,cAAa,IAAI,cAAc,OAAO,OAAO,WAAW,CAAC;CAG3D,MAAM,cAAc,aAAa,UAAU;AAC3C,QAAO,cAAc,GAAG,SAAS,GAAG,gBAAgB"}
|
package/dist/mcp/index.cjs
CHANGED
|
@@ -9109,6 +9109,10 @@ function injectDefaultDomain(meta, clientName, serverUrl) {
|
|
|
9109
9109
|
//#region src/mcp/server.ts
|
|
9110
9110
|
var localDevServerUrl = "http://localhost:8000";
|
|
9111
9111
|
var localHmrWsUrl = "ws://localhost:24678";
|
|
9112
|
+
var lastToolTimingMs = null;
|
|
9113
|
+
function isDevOverlayEnabled() {
|
|
9114
|
+
return process.env.SUNPEAK_DEV_OVERLAY !== "false";
|
|
9115
|
+
}
|
|
9112
9116
|
/**
|
|
9113
9117
|
* Detect whether this request needs pre-built HTML (no Vite HMR).
|
|
9114
9118
|
*
|
|
@@ -9134,6 +9138,57 @@ function readResourceHtmlProd(distPath) {
|
|
|
9134
9138
|
return node_fs.default.readFileSync(htmlPath, "utf8");
|
|
9135
9139
|
}
|
|
9136
9140
|
/**
|
|
9141
|
+
* Generate an inline script that shows a dev overlay with resource served timestamp
|
|
9142
|
+
* and tool call request timing.
|
|
9143
|
+
*
|
|
9144
|
+
* The resource timestamp is baked into the HTML at readResource time. Tool timing
|
|
9145
|
+
* arrives two ways:
|
|
9146
|
+
* 1. Baked-in `toolMs` from readResource time (works when the tool call precedes the
|
|
9147
|
+
* resource read, which is the case for Claude and the inspector's initial render).
|
|
9148
|
+
* 2. `_meta._sunpeak.requestTimeMs` on the tool result PostMessage (handles inspector
|
|
9149
|
+
* Re-run and hosts that pass `_meta` through to the resource iframe).
|
|
9150
|
+
*
|
|
9151
|
+
* NOTE: Keep in sync with bin/lib/dev-overlay.mjs (used by the standalone inspector).
|
|
9152
|
+
*
|
|
9153
|
+
* @param servedAt - Unix timestamp (ms) when the resource HTML was generated/served.
|
|
9154
|
+
* @param toolMs - Most recent tool call duration (ms), or null if no call yet.
|
|
9155
|
+
*/
|
|
9156
|
+
function getDevOverlayScript(servedAt, toolMs) {
|
|
9157
|
+
return `<script>
|
|
9158
|
+
(function(){
|
|
9159
|
+
var servedAt=${servedAt};
|
|
9160
|
+
var el=null,hidden=false,lastMs=${toolMs ?? "null"};
|
|
9161
|
+
function fmt(ts){var d=new Date(ts);var h=d.getHours(),m=d.getMinutes(),s=d.getSeconds();return (h<10?'0':'')+h+':'+(m<10?'0':'')+m+':'+(s<10?'0':'')+s}
|
|
9162
|
+
function make(){
|
|
9163
|
+
var existing=document.getElementById('__sunpeak-dev-timing');
|
|
9164
|
+
if(existing)return existing;
|
|
9165
|
+
var b=document.createElement('button');b.id='__sunpeak-dev-timing';
|
|
9166
|
+
b.style.cssText='position:fixed;bottom:8px;right:8px;z-index:2147483647;display:grid;grid-template-columns:auto auto;gap:0 6px;align-items:baseline;padding:5px 8px;border-radius:6px;border:1px solid rgba(128,128,128,0.25);background:rgba(0,0,0,0.75);backdrop-filter:blur(8px);color:#e5e5e5;font-size:11px;font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;line-height:1.4;cursor:pointer;user-select:none;opacity:0.85;transition:opacity 150ms;';
|
|
9167
|
+
b.onmouseenter=function(){b.style.opacity='1'};
|
|
9168
|
+
b.onmouseleave=function(){b.style.opacity='0.85'};
|
|
9169
|
+
b.onclick=function(){hidden=!hidden;upd()};
|
|
9170
|
+
document.body.appendChild(b);return b;
|
|
9171
|
+
}
|
|
9172
|
+
function upd(){
|
|
9173
|
+
if(!el)el=make();
|
|
9174
|
+
if(hidden){el.title='Show dev info';el.innerHTML='<span style="grid-column:1/-1;font-size:9px;text-align:center">DEV</span>';return}
|
|
9175
|
+
var h='';
|
|
9176
|
+
h+='<span style="text-align:right;color:rgba(255,255,255,0.5);white-space:nowrap">Resource:</span><span style="white-space:nowrap">'+fmt(servedAt)+'</span>';
|
|
9177
|
+
if(lastMs!=null)h+='<span style="text-align:right;color:rgba(255,255,255,0.5);white-space:nowrap">Tool:</span><span style="white-space:nowrap">'+(lastMs%1===0?lastMs:lastMs.toFixed(1))+'ms</span>';
|
|
9178
|
+
el.title='Hide dev info';el.innerHTML=h;
|
|
9179
|
+
}
|
|
9180
|
+
upd();
|
|
9181
|
+
window.addEventListener('message',function(e){
|
|
9182
|
+
var d=e.data;if(!d||typeof d!=='object')return;
|
|
9183
|
+
if(d.method!=='ui/notifications/tool-result')return;
|
|
9184
|
+
var p=d.params;if(!p)return;
|
|
9185
|
+
var ms=p._meta&&p._meta._sunpeak&&p._meta._sunpeak.requestTimeMs;
|
|
9186
|
+
if(typeof ms==='number'){lastMs=ms;upd()}
|
|
9187
|
+
});
|
|
9188
|
+
})();
|
|
9189
|
+
<\/script>`;
|
|
9190
|
+
}
|
|
9191
|
+
/**
|
|
9137
9192
|
* Generate HTML that loads from Vite dev server with HMR.
|
|
9138
9193
|
* Used for direct connections (e.g. ChatGPT connecting to localhost).
|
|
9139
9194
|
*/
|
|
@@ -9176,6 +9231,7 @@ function getViteResourceHtml(srcPath) {
|
|
|
9176
9231
|
src: srcPath,
|
|
9177
9232
|
component: componentName
|
|
9178
9233
|
}).toString()}`}"><\/script>
|
|
9234
|
+
${isDevOverlayEnabled() ? getDevOverlayScript(Date.now(), lastToolTimingMs) : ""}
|
|
9179
9235
|
</body>
|
|
9180
9236
|
</html>`;
|
|
9181
9237
|
}
|
|
@@ -9187,7 +9243,9 @@ function getViteResourceHtml(srcPath) {
|
|
|
9187
9243
|
*/
|
|
9188
9244
|
function getResourceHtml(simulation, viteMode, prodBuild) {
|
|
9189
9245
|
if (viteMode && simulation.srcPath && !prodBuild) return getViteResourceHtml(simulation.srcPath);
|
|
9190
|
-
|
|
9246
|
+
let html = readResourceHtmlProd(simulation.distPath);
|
|
9247
|
+
if (isDevOverlayEnabled()) html = html.replace("</body>", `${getDevOverlayScript(Date.now(), lastToolTimingMs)}\n</body>`);
|
|
9248
|
+
return html;
|
|
9191
9249
|
}
|
|
9192
9250
|
/**
|
|
9193
9251
|
* Inject localhost Vite dev server URLs into CSP metadata.
|
|
@@ -9308,14 +9366,29 @@ function createAppServer(config, simulations, viteMode) {
|
|
|
9308
9366
|
const realHandler = simulation.handler;
|
|
9309
9367
|
if (realHandler && (config.prodTools || !hasMockResult)) {
|
|
9310
9368
|
console.log(`[MCP] CallTool: ${tool.name}${argsStr} → live handler`);
|
|
9369
|
+
const startTime = performance.now();
|
|
9311
9370
|
try {
|
|
9312
9371
|
const result = await realHandler(args, extra);
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9372
|
+
const durationMs = Math.round((performance.now() - startTime) * 10) / 10;
|
|
9373
|
+
lastToolTimingMs = durationMs;
|
|
9374
|
+
if (typeof result === "string") return {
|
|
9375
|
+
content: [{
|
|
9376
|
+
type: "text",
|
|
9377
|
+
text: result
|
|
9378
|
+
}],
|
|
9379
|
+
_meta: { _sunpeak: { requestTimeMs: durationMs } }
|
|
9380
|
+
};
|
|
9381
|
+
const typed = result;
|
|
9382
|
+
return {
|
|
9383
|
+
...typed,
|
|
9384
|
+
_meta: {
|
|
9385
|
+
...typed._meta,
|
|
9386
|
+
_sunpeak: { requestTimeMs: durationMs }
|
|
9387
|
+
}
|
|
9388
|
+
};
|
|
9318
9389
|
} catch (error) {
|
|
9390
|
+
const durationMs = Math.round((performance.now() - startTime) * 10) / 10;
|
|
9391
|
+
lastToolTimingMs = durationMs;
|
|
9319
9392
|
const msg = error instanceof Error ? error.message : String(error);
|
|
9320
9393
|
console.error(`[MCP] CallTool error (${tool.name}): ${msg}`);
|
|
9321
9394
|
return {
|
|
@@ -9323,7 +9396,8 @@ function createAppServer(config, simulations, viteMode) {
|
|
|
9323
9396
|
type: "text",
|
|
9324
9397
|
text: `Error: ${msg}`
|
|
9325
9398
|
}],
|
|
9326
|
-
isError: true
|
|
9399
|
+
isError: true,
|
|
9400
|
+
_meta: { _sunpeak: { requestTimeMs: durationMs } }
|
|
9327
9401
|
};
|
|
9328
9402
|
}
|
|
9329
9403
|
}
|