sunpeak 0.16.29 → 0.17.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.
- package/bin/commands/dev.mjs +169 -342
- package/bin/commands/inspect.mjs +763 -0
- package/bin/commands/new.mjs +2 -2
- package/bin/lib/inspect/inspect-config.d.mts +20 -0
- package/bin/lib/inspect/inspect-config.mjs +76 -0
- package/bin/lib/live/global-setup.mjs +6 -1
- package/bin/sunpeak.js +11 -1
- package/dist/chatgpt/globals.css +8 -0
- package/dist/chatgpt/index.cjs +3 -11
- package/dist/chatgpt/index.cjs.map +1 -1
- package/dist/chatgpt/index.d.ts +2 -2
- package/dist/chatgpt/index.js +4 -8
- package/dist/chatgpt/index.js.map +1 -1
- package/dist/claude/index.cjs +1 -1
- package/dist/claude/index.js +1 -1
- package/dist/discovery-Cgoegt62.js +114 -0
- package/dist/discovery-Cgoegt62.js.map +1 -0
- package/dist/discovery-Clu4uHp1.cjs +161 -0
- package/dist/discovery-Clu4uHp1.cjs.map +1 -0
- package/dist/index.cjs +1 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/discovery-cli.cjs +1 -1
- package/dist/lib/discovery-cli.js +1 -1
- package/dist/lib/discovery.d.ts +7 -67
- package/dist/lib/index.d.ts +0 -1
- package/dist/mcp/index.cjs +34 -23
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +34 -23
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/types.d.ts +5 -0
- package/dist/simulator/index.cjs +5 -11
- package/dist/simulator/index.cjs.map +1 -1
- package/dist/simulator/index.d.ts +4 -2
- package/dist/simulator/index.js +5 -8
- package/dist/simulator/index.js.map +1 -1
- package/dist/simulator/simple-sidebar.d.ts +7 -4
- package/dist/simulator/simulator-url.d.ts +8 -0
- package/dist/simulator/simulator.d.ts +15 -2
- package/dist/simulator/use-mcp-connection.d.ts +19 -0
- package/dist/{simulator-DIVvI69i.cjs → simulator-CH9hs0N6.cjs} +129 -21
- package/dist/simulator-CH9hs0N6.cjs.map +1 -0
- package/dist/{simulator-C7mkK7Sz.js → simulator-Dl8B-Ljb.js} +124 -22
- package/dist/simulator-Dl8B-Ljb.js.map +1 -0
- package/dist/{simulator-url-BDGD4vZD.cjs → simulator-url-CozKF1jf.cjs} +3 -1
- package/dist/simulator-url-CozKF1jf.cjs.map +1 -0
- package/dist/{simulator-url-Bkxj43yT.js → simulator-url-KoS_ToP6.js} +3 -1
- package/dist/simulator-url-KoS_ToP6.js.map +1 -0
- package/dist/style.css +8 -0
- package/package.json +11 -3
- package/template/dist/albums/albums.html +105 -0
- package/template/dist/albums/albums.json +16 -0
- package/template/dist/carousel/carousel.html +105 -0
- package/template/dist/carousel/carousel.json +16 -0
- package/template/dist/map/map.html +3060 -0
- package/template/dist/map/map.json +22 -0
- package/template/dist/review/review.html +105 -0
- package/template/dist/review/review.json +16 -0
- package/template/dist/server.js +15 -0
- package/template/dist/tools/review-diff.js +50 -0
- package/template/dist/tools/review-post.js +50 -0
- package/template/dist/tools/review-purchase.js +61 -0
- package/template/dist/tools/review.js +31 -0
- package/template/dist/tools/show-albums.js +56 -0
- package/template/dist/tools/show-carousel.js +41 -0
- package/template/dist/tools/show-map.js +47 -0
- package/template/node_modules/.vite/deps/_metadata.json +8 -0
- package/template/node_modules/.vite/deps/package.json +3 -0
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +500 -0
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +563 -0
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +575 -0
- package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/@testing-library_react.js +11363 -0
- package/template/node_modules/.vite-mcp/deps/@testing-library_react.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/_metadata.json +130 -0
- package/template/node_modules/.vite-mcp/deps/chunk-BoAXSpZd.js +33 -0
- package/template/node_modules/.vite-mcp/deps/client-CU1wWud4.js +14385 -0
- package/template/node_modules/.vite-mcp/deps/client-CU1wWud4.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/clsx.js +18 -0
- package/template/node_modules/.vite-mcp/deps/clsx.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/dist-uWX8WbjY.js +505 -0
- package/template/node_modules/.vite-mcp/deps/dist-uWX8WbjY.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/embla-carousel-react.js +1461 -0
- package/template/node_modules/.vite-mcp/deps/embla-carousel-react.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/embla-carousel-wheel-gestures.js +536 -0
- package/template/node_modules/.vite-mcp/deps/embla-carousel-wheel-gestures.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/magic-string.es-Cklsmr-5.js +1013 -0
- package/template/node_modules/.vite-mcp/deps/magic-string.es-Cklsmr-5.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/mapbox-gl.js +46311 -0
- package/template/node_modules/.vite-mcp/deps/mapbox-gl.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/package.json +3 -0
- package/template/node_modules/.vite-mcp/deps/protocol-CTflwIfG.js +2090 -0
- package/template/node_modules/.vite-mcp/deps/protocol-CTflwIfG.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/react-dom.js +186 -0
- package/template/node_modules/.vite-mcp/deps/react-dom.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/react-dom_client.js +2 -0
- package/template/node_modules/.vite-mcp/deps/react.js +769 -0
- package/template/node_modules/.vite-mcp/deps/react.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/react_jsx-dev-runtime.js +205 -0
- package/template/node_modules/.vite-mcp/deps/react_jsx-dev-runtime.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/react_jsx-runtime.js +209 -0
- package/template/node_modules/.vite-mcp/deps/react_jsx-runtime.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/schemas-NsgmY9QV.js +12157 -0
- package/template/node_modules/.vite-mcp/deps/schemas-NsgmY9QV.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/tailwind-merge.js +2025 -0
- package/template/node_modules/.vite-mcp/deps/tailwind-merge.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/vitest.js +14021 -0
- package/template/node_modules/.vite-mcp/deps/vitest.js.map +1 -0
- package/template/node_modules/.vite-mcp/deps/zod.js +624 -0
- package/template/node_modules/.vite-mcp/deps/zod.js.map +1 -0
- package/template/src/tools/review-diff.test.ts +5 -1
- package/template/src/tools/review-diff.ts +1 -1
- package/template/src/tools/review-post.test.ts +5 -1
- package/template/src/tools/review-post.ts +1 -1
- package/template/src/tools/review-purchase.test.ts +5 -1
- package/template/src/tools/review-purchase.ts +1 -1
- package/template/src/tools/review.test.ts +5 -1
- package/template/src/tools/review.ts +1 -1
- package/template/src/tools/show-albums.test.ts +5 -1
- package/template/src/tools/show-albums.ts +1 -1
- package/template/src/tools/show-carousel.test.ts +5 -1
- package/template/src/tools/show-carousel.ts +1 -1
- package/template/src/tools/show-map.test.ts +5 -1
- package/template/src/tools/show-map.ts +1 -1
- package/dist/discovery-BxKCIgG5.cjs +0 -332
- package/dist/discovery-BxKCIgG5.cjs.map +0 -1
- package/dist/discovery-Du4LHrih.js +0 -261
- package/dist/discovery-Du4LHrih.js.map +0 -1
- package/dist/simulator-C7mkK7Sz.js.map +0 -1
- package/dist/simulator-DIVvI69i.cjs.map +0 -1
- package/dist/simulator-url-BDGD4vZD.cjs.map +0 -1
- package/dist/simulator-url-Bkxj43yT.js.map +0 -1
- package/template/.sunpeak/dev.tsx +0 -79
- package/template/.sunpeak/resource-loader.html +0 -20
- package/template/.sunpeak/resource-loader.tsx +0 -57
- package/template/index.html +0 -14
- package/template/src/resources/index.ts +0 -17
package/bin/commands/new.mjs
CHANGED
|
@@ -170,8 +170,8 @@ export async function init(projectName, resourcesArg, deps = defaultDeps) {
|
|
|
170
170
|
filter: (src) => {
|
|
171
171
|
const name = basename(src);
|
|
172
172
|
|
|
173
|
-
// Skip node_modules and
|
|
174
|
-
if (name === 'node_modules' || name === 'pnpm-lock.yaml') {
|
|
173
|
+
// Skip node_modules, lock file, and legacy dev bootstrap files
|
|
174
|
+
if (name === 'node_modules' || name === 'pnpm-lock.yaml' || name === '.sunpeak' || name === 'index.html') {
|
|
175
175
|
return false;
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface InspectConfigOptions {
|
|
2
|
+
/** MCP server URL or stdio command string (required) */
|
|
3
|
+
server: string;
|
|
4
|
+
/** Test directory (default: 'tests/e2e') */
|
|
5
|
+
testDir?: string;
|
|
6
|
+
/** Simulation JSON directory (opt-in, fixtures loaded only when specified) */
|
|
7
|
+
simulationsDir?: string;
|
|
8
|
+
/** Host shells to test (default: ['chatgpt', 'claude']) */
|
|
9
|
+
hosts?: ('chatgpt' | 'claude')[];
|
|
10
|
+
/** App name in simulator chrome */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** Additional Playwright `use` options */
|
|
13
|
+
use?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a complete Playwright config for testing an external MCP server
|
|
18
|
+
* using the sunpeak simulator.
|
|
19
|
+
*/
|
|
20
|
+
export function defineInspectConfig(options: InspectConfigOptions): Record<string, unknown>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright config factory for inspect mode (BYOS — Bring Your Own Server).
|
|
3
|
+
*
|
|
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
|
|
6
|
+
* as `defineLiveConfig` for live tests.
|
|
7
|
+
*
|
|
8
|
+
* Usage in playwright.config.ts:
|
|
9
|
+
* import { defineInspectConfig } from 'sunpeak/test/inspect/config';
|
|
10
|
+
* export default defineInspectConfig({
|
|
11
|
+
* server: 'http://localhost:8000/mcp',
|
|
12
|
+
* });
|
|
13
|
+
*/
|
|
14
|
+
import { getPortSync } from '../get-port.mjs';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a complete Playwright config for testing an external MCP server.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} options
|
|
20
|
+
* @param {string} options.server - MCP server URL or stdio command (required)
|
|
21
|
+
* @param {string} [options.testDir='tests/e2e'] - Test directory
|
|
22
|
+
* @param {string} [options.simulationsDir='tests/simulations'] - Simulation JSON directory
|
|
23
|
+
* @param {string[]} [options.hosts=['chatgpt', 'claude']] - Host shells to test
|
|
24
|
+
* @param {string} [options.name] - App name in simulator chrome
|
|
25
|
+
* @param {Object} [options.use] - Additional Playwright `use` options
|
|
26
|
+
* @returns {import('@playwright/test').PlaywrightTestConfig}
|
|
27
|
+
*/
|
|
28
|
+
export function defineInspectConfig(options) {
|
|
29
|
+
const {
|
|
30
|
+
server,
|
|
31
|
+
testDir = 'tests/e2e',
|
|
32
|
+
simulationsDir,
|
|
33
|
+
hosts = ['chatgpt', 'claude'],
|
|
34
|
+
name,
|
|
35
|
+
use: userUse,
|
|
36
|
+
} = options;
|
|
37
|
+
|
|
38
|
+
if (!server) {
|
|
39
|
+
throw new Error('defineInspectConfig: `server` option is required');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const port = Number(process.env.SUNPEAK_TEST_PORT) || getPortSync(6776);
|
|
43
|
+
const sandboxPort = Number(process.env.SUNPEAK_SANDBOX_PORT) || getPortSync(24680);
|
|
44
|
+
|
|
45
|
+
// Build the sunpeak inspect command
|
|
46
|
+
const serverArg = server.includes(' ') ? `"${server}"` : server;
|
|
47
|
+
const command = [
|
|
48
|
+
'npx sunpeak inspect',
|
|
49
|
+
`--server ${serverArg}`,
|
|
50
|
+
...(simulationsDir ? [`--simulations ${simulationsDir}`] : []),
|
|
51
|
+
`--port ${port}`,
|
|
52
|
+
...(name ? [`--name "${name}"`] : []),
|
|
53
|
+
].join(' ');
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
testDir,
|
|
57
|
+
fullyParallel: true,
|
|
58
|
+
forbidOnly: !!process.env.CI,
|
|
59
|
+
retries: process.env.CI ? 2 : 1,
|
|
60
|
+
// Limit workers to avoid overwhelming the double-iframe sandbox proxy.
|
|
61
|
+
workers: process.env.CI ? 1 : 2,
|
|
62
|
+
reporter: 'list',
|
|
63
|
+
use: {
|
|
64
|
+
baseURL: `http://localhost:${port}`,
|
|
65
|
+
trace: 'on-first-retry',
|
|
66
|
+
...userUse,
|
|
67
|
+
},
|
|
68
|
+
projects: hosts.map((host) => ({ name: host })),
|
|
69
|
+
webServer: {
|
|
70
|
+
command: `SUNPEAK_SANDBOX_PORT=${sandboxPort} ${command}`,
|
|
71
|
+
url: `http://localhost:${port}/health`,
|
|
72
|
+
reuseExistingServer: !process.env.CI,
|
|
73
|
+
timeout: 60_000,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -23,7 +23,12 @@ import { dirname } from 'path';
|
|
|
23
23
|
import { ANTI_BOT_ARGS, CHROME_USER_AGENT, resolvePlaywright, getAppName } from './utils.mjs';
|
|
24
24
|
import { ChatGPTPage, CHATGPT_SELECTORS, CHATGPT_URLS } from './chatgpt-page.mjs';
|
|
25
25
|
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Auth file retention window. The file is kept for 24 hours, but sessions
|
|
28
|
+
* typically expire much sooner (a few hours) because Cloudflare's HttpOnly
|
|
29
|
+
* `cf_clearance` cookie cannot be captured by storageState(). When it
|
|
30
|
+
* expires, the next run will need re-authentication even if the file is fresh.
|
|
31
|
+
*/
|
|
27
32
|
const MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
28
33
|
|
|
29
34
|
const CHATGPT_URL = CHATGPT_URLS.base;
|
package/bin/sunpeak.js
CHANGED
|
@@ -37,7 +37,7 @@ function getVersion() {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Commands that don't require a package.json
|
|
40
|
-
const standaloneCommands = ['new', 'upgrade', 'help', undefined];
|
|
40
|
+
const standaloneCommands = ['new', 'upgrade', 'inspect', 'help', undefined];
|
|
41
41
|
|
|
42
42
|
if (command && !standaloneCommands.includes(command)) {
|
|
43
43
|
checkPackageJson();
|
|
@@ -72,6 +72,13 @@ function getVersion() {
|
|
|
72
72
|
}
|
|
73
73
|
break;
|
|
74
74
|
|
|
75
|
+
case 'inspect':
|
|
76
|
+
{
|
|
77
|
+
const { inspect } = await import(join(COMMANDS_DIR, 'inspect.mjs'));
|
|
78
|
+
await inspect(args);
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
|
|
75
82
|
case 'upgrade':
|
|
76
83
|
{
|
|
77
84
|
const { upgrade } = await import(join(COMMANDS_DIR, 'upgrade.mjs'));
|
|
@@ -100,6 +107,9 @@ Usage:
|
|
|
100
107
|
sunpeak build Build resources + tools for production
|
|
101
108
|
sunpeak start Start production MCP server
|
|
102
109
|
--port, -p Server port (default: 8000, or PORT env)
|
|
110
|
+
sunpeak inspect Test an external MCP server in the simulator
|
|
111
|
+
--server, -s <url|cmd> MCP server URL or stdio command (required)
|
|
112
|
+
--simulations <dir> Simulation JSON directory
|
|
103
113
|
sunpeak upgrade Upgrade sunpeak to latest version
|
|
104
114
|
sunpeak --version Show version number
|
|
105
115
|
|
package/dist/chatgpt/globals.css
CHANGED
|
@@ -806,6 +806,10 @@
|
|
|
806
806
|
height: calc(var(--spacing) * 6);
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
+
.h-2 {
|
|
810
|
+
height: calc(var(--spacing) * 2);
|
|
811
|
+
}
|
|
812
|
+
|
|
809
813
|
.h-3 {
|
|
810
814
|
height: calc(var(--spacing) * 3);
|
|
811
815
|
}
|
|
@@ -898,6 +902,10 @@
|
|
|
898
902
|
width: calc(var(--spacing) * 1);
|
|
899
903
|
}
|
|
900
904
|
|
|
905
|
+
.w-2 {
|
|
906
|
+
width: calc(var(--spacing) * 2);
|
|
907
|
+
}
|
|
908
|
+
|
|
901
909
|
.w-3 {
|
|
902
910
|
width: calc(var(--spacing) * 3);
|
|
903
911
|
}
|
package/dist/chatgpt/index.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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-
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const require_simulator = require("../simulator-CH9hs0N6.cjs");
|
|
5
|
+
const require_simulator_url = require("../simulator-url-CozKF1jf.cjs");
|
|
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
9
|
IframeResource: () => require_simulator.IframeResource,
|
|
@@ -11,10 +11,6 @@ var chatgpt_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
|
11
11
|
SCREEN_WIDTHS: () => require_simulator.SCREEN_WIDTHS,
|
|
12
12
|
Simulator: () => require_simulator.Simulator,
|
|
13
13
|
ThemeProvider: () => require_simulator.ThemeProvider,
|
|
14
|
-
buildDevSimulations: () => require_discovery.buildDevSimulations,
|
|
15
|
-
buildResourceMap: () => require_discovery.buildResourceMap,
|
|
16
|
-
buildSimulations: () => require_discovery.buildSimulations,
|
|
17
|
-
createResourceExports: () => require_discovery.createResourceExports,
|
|
18
14
|
createSimulatorUrl: () => require_simulator_url.createSimulatorUrl,
|
|
19
15
|
extractResourceCSP: () => require_simulator.extractResourceCSP,
|
|
20
16
|
extractResourceKey: () => require_discovery.extractResourceKey,
|
|
@@ -32,16 +28,12 @@ exports.McpAppHost = require_simulator.McpAppHost;
|
|
|
32
28
|
exports.SCREEN_WIDTHS = require_simulator.SCREEN_WIDTHS;
|
|
33
29
|
exports.Simulator = require_simulator.Simulator;
|
|
34
30
|
exports.ThemeProvider = require_simulator.ThemeProvider;
|
|
35
|
-
exports.buildDevSimulations = require_discovery.buildDevSimulations;
|
|
36
|
-
exports.buildResourceMap = require_discovery.buildResourceMap;
|
|
37
|
-
exports.buildSimulations = require_discovery.buildSimulations;
|
|
38
31
|
Object.defineProperty(exports, "chatgpt_exports", {
|
|
39
32
|
enumerable: true,
|
|
40
33
|
get: function() {
|
|
41
34
|
return chatgpt_exports;
|
|
42
35
|
}
|
|
43
36
|
});
|
|
44
|
-
exports.createResourceExports = require_discovery.createResourceExports;
|
|
45
37
|
exports.createSimulatorUrl = require_simulator_url.createSimulatorUrl;
|
|
46
38
|
exports.extractResourceCSP = require_simulator.extractResourceCSP;
|
|
47
39
|
exports.extractResourceKey = require_discovery.extractResourceKey;
|
|
@@ -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
|
|
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":""}
|
package/dist/chatgpt/index.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export type { ResourceCSP } from '../simulator/iframe-resource';
|
|
|
10
10
|
export * from '../simulator/theme-provider';
|
|
11
11
|
export { createSimulatorUrl } from '../simulator/simulator-url';
|
|
12
12
|
export type { SimulatorUrlParams } from '../simulator/simulator-url';
|
|
13
|
-
export {
|
|
14
|
-
export type {
|
|
13
|
+
export { toPascalCase, extractResourceKey, extractSimulationKey, findResourceKey, getComponentName, findResourceDirs, } from '../lib/discovery';
|
|
14
|
+
export type { ResourceDirInfo, FsOps } from '../lib/discovery';
|
package/dist/chatgpt/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { r as __exportAll } from "../chunk-D6g4UhsZ.js";
|
|
2
2
|
import "../protocol-DJmRaBzO.js";
|
|
3
|
-
import { _ as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
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-Dl8B-Ljb.js";
|
|
4
|
+
import { t as createSimulatorUrl } from "../simulator-url-KoS_ToP6.js";
|
|
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,
|
|
@@ -10,10 +10,6 @@ var chatgpt_exports = /* @__PURE__ */ __exportAll({
|
|
|
10
10
|
SCREEN_WIDTHS: () => SCREEN_WIDTHS,
|
|
11
11
|
Simulator: () => Simulator,
|
|
12
12
|
ThemeProvider: () => ThemeProvider,
|
|
13
|
-
buildDevSimulations: () => buildDevSimulations,
|
|
14
|
-
buildResourceMap: () => buildResourceMap,
|
|
15
|
-
buildSimulations: () => buildSimulations,
|
|
16
|
-
createResourceExports: () => createResourceExports,
|
|
17
13
|
createSimulatorUrl: () => createSimulatorUrl,
|
|
18
14
|
extractResourceCSP: () => extractResourceCSP,
|
|
19
15
|
extractResourceKey: () => extractResourceKey,
|
|
@@ -26,6 +22,6 @@ var chatgpt_exports = /* @__PURE__ */ __exportAll({
|
|
|
26
22
|
useThemeContext: () => useThemeContext
|
|
27
23
|
});
|
|
28
24
|
//#endregion
|
|
29
|
-
export { IframeResource, McpAppHost, SCREEN_WIDTHS, Simulator, ThemeProvider,
|
|
25
|
+
export { IframeResource, McpAppHost, SCREEN_WIDTHS, Simulator, ThemeProvider, createSimulatorUrl, extractResourceCSP, extractResourceKey, extractSimulationKey, findResourceDirs, findResourceKey, getComponentName, resolveServerToolResult, chatgpt_exports as t, toPascalCase, useThemeContext };
|
|
30
26
|
|
|
31
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
|
|
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":""}
|
package/dist/claude/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
require("../chunk-9hOWP6kD.cjs");
|
|
3
3
|
require("../protocol-jbxhzcnS.cjs");
|
|
4
|
-
const require_simulator = require("../simulator-
|
|
4
|
+
const require_simulator = require("../simulator-CH9hs0N6.cjs");
|
|
5
5
|
exports.Simulator = require_simulator.Simulator;
|
package/dist/claude/index.js
CHANGED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
//#region src/lib/discovery.ts
|
|
2
|
+
/**
|
|
3
|
+
* Discovery utilities for resources, tools, and simulations.
|
|
4
|
+
*
|
|
5
|
+
* String helpers (toPascalCase, extractResourceKey, etc.) are used by both
|
|
6
|
+
* browser and Node.js code. Node.js utilities (findResourceDirs, findToolFiles,
|
|
7
|
+
* etc.) are used by CLI commands for build-time and runtime discovery.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Convert a kebab-case string to PascalCase
|
|
11
|
+
* @example toPascalCase('review') // 'Review'
|
|
12
|
+
* @example toPascalCase('album-art') // 'AlbumArt'
|
|
13
|
+
*/
|
|
14
|
+
function toPascalCase(str) {
|
|
15
|
+
return str.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract the resource key from a resource file path.
|
|
19
|
+
* Matches {name}.tsx (e.g., './albums/albums.tsx' → 'albums')
|
|
20
|
+
*/
|
|
21
|
+
function extractResourceKey(path) {
|
|
22
|
+
const match = path.match(/([^/]+)\.tsx$/);
|
|
23
|
+
return match ? match[1] : void 0;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract the simulation key from a simulation file path.
|
|
27
|
+
* Matches any *.json file (e.g., './show-albums.json' → 'show-albums')
|
|
28
|
+
*/
|
|
29
|
+
function extractSimulationKey(path) {
|
|
30
|
+
const match = path.match(/([^/]+)\.json$/);
|
|
31
|
+
return match ? match[1] : void 0;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Find the best matching resource key for a simulation key.
|
|
35
|
+
* Matches the longest resource name that is a prefix of the simulation key.
|
|
36
|
+
* @example findResourceKey('review-diff', ['review', 'carousel']) // 'review'
|
|
37
|
+
* @example findResourceKey('albums', ['albums', 'review']) // 'albums'
|
|
38
|
+
*/
|
|
39
|
+
function findResourceKey(simulationKey, resourceKeys) {
|
|
40
|
+
const sorted = [...resourceKeys].sort((a, b) => b.length - a.length);
|
|
41
|
+
for (const resourceKey of sorted) if (simulationKey === resourceKey || simulationKey.startsWith(resourceKey + "-")) return resourceKey;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the expected component export name for a resource
|
|
45
|
+
* @example getComponentName('review') // 'ReviewResource'
|
|
46
|
+
* @example getComponentName('album-art') // 'AlbumArtResource'
|
|
47
|
+
*/
|
|
48
|
+
function getComponentName(resourceKey) {
|
|
49
|
+
return `${toPascalCase(resourceKey)}Resource`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find all resource directories in a base directory.
|
|
53
|
+
* Each valid resource directory contains a file matching the expected pattern.
|
|
54
|
+
*
|
|
55
|
+
* @param baseDir - Base directory to scan (e.g., 'src/resources' or 'dist')
|
|
56
|
+
* @param filePattern - Function to generate expected filename from resource key
|
|
57
|
+
* @param fs - File system operations (for testing)
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // Find source resources (tsx files)
|
|
61
|
+
* const resources = findResourceDirs('src/resources', key => `${key}.tsx`);
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // Find built resources (js files)
|
|
65
|
+
* const resources = findResourceDirs('dist', key => `${key}.js`);
|
|
66
|
+
*/
|
|
67
|
+
function findResourceDirs(baseDir, filePattern, fs) {
|
|
68
|
+
if (!fs.existsSync(baseDir)) return [];
|
|
69
|
+
return fs.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
70
|
+
const key = entry.name;
|
|
71
|
+
const dir = `${baseDir}/${key}`;
|
|
72
|
+
const resourcePath = `${dir}/${filePattern(key)}`;
|
|
73
|
+
if (!fs.existsSync(resourcePath)) return null;
|
|
74
|
+
return {
|
|
75
|
+
key,
|
|
76
|
+
dir,
|
|
77
|
+
resourcePath
|
|
78
|
+
};
|
|
79
|
+
}).filter((info) => info !== null);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Find all tool files in a tools directory.
|
|
83
|
+
* Matches *.ts files directly in the directory (not recursive).
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* findToolFiles('src/tools', fs)
|
|
87
|
+
* // [{ name: 'show-albums', path: 'src/tools/show-albums.ts' }]
|
|
88
|
+
*/
|
|
89
|
+
function findToolFiles(toolsDir, fs) {
|
|
90
|
+
if (!fs.existsSync(toolsDir)) return [];
|
|
91
|
+
return fs.readdirSync(toolsDir, { withFileTypes: true }).filter((entry) => !entry.isDirectory() && entry.name.endsWith(".ts") && !entry.name.endsWith(".test.ts")).map((entry) => ({
|
|
92
|
+
name: entry.name.replace(/\.ts$/, ""),
|
|
93
|
+
path: `${toolsDir}/${entry.name}`
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Find all simulation JSON files in a flat simulations directory.
|
|
98
|
+
* Matches any *.json file directly in the directory.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* findSimulationFilesFlat('tests/simulations', fs)
|
|
102
|
+
* // [{ name: 'show-albums', path: 'tests/simulations/show-albums.json' }]
|
|
103
|
+
*/
|
|
104
|
+
function findSimulationFilesFlat(simulationsDir, fs) {
|
|
105
|
+
if (!fs.existsSync(simulationsDir)) return [];
|
|
106
|
+
return fs.readdirSync(simulationsDir, { withFileTypes: true }).filter((entry) => !entry.isDirectory() && entry.name.endsWith(".json")).map((entry) => ({
|
|
107
|
+
name: entry.name.replace(/\.json$/, ""),
|
|
108
|
+
path: `${simulationsDir}/${entry.name}`
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { findSimulationFilesFlat as a, toPascalCase as c, findResourceKey as i, extractSimulationKey as n, findToolFiles as o, findResourceDirs as r, getComponentName as s, extractResourceKey as t };
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=discovery-Cgoegt62.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery-Cgoegt62.js","names":[],"sources":["../src/lib/discovery.ts"],"sourcesContent":["/**\n * Discovery utilities for resources, tools, and simulations.\n *\n * String helpers (toPascalCase, extractResourceKey, etc.) are used by both\n * browser and Node.js code. Node.js utilities (findResourceDirs, findToolFiles,\n * etc.) are used by CLI commands for build-time and runtime discovery.\n */\n\n/**\n * Convert a kebab-case string to PascalCase\n * @example toPascalCase('review') // 'Review'\n * @example toPascalCase('album-art') // 'AlbumArt'\n */\nexport function toPascalCase(str: string): string {\n return str\n .split('-')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\n/**\n * Extract the resource key from a resource file path.\n * Matches {name}.tsx (e.g., './albums/albums.tsx' → 'albums')\n */\nexport function extractResourceKey(path: string): string | undefined {\n const match = path.match(/([^/]+)\\.tsx$/);\n return match ? match[1] : undefined;\n}\n\n/**\n * Extract the simulation key from a simulation file path.\n * Matches any *.json file (e.g., './show-albums.json' → 'show-albums')\n */\nexport function extractSimulationKey(path: string): string | undefined {\n const match = path.match(/([^/]+)\\.json$/);\n return match ? match[1] : undefined;\n}\n\n/**\n * Find the best matching resource key for a simulation key.\n * Matches the longest resource name that is a prefix of the simulation key.\n * @example findResourceKey('review-diff', ['review', 'carousel']) // 'review'\n * @example findResourceKey('albums', ['albums', 'review']) // 'albums'\n */\nexport function findResourceKey(simulationKey: string, resourceKeys: string[]): string | undefined {\n // Sort by length descending to find longest match first\n const sorted = [...resourceKeys].sort((a, b) => b.length - a.length);\n for (const resourceKey of sorted) {\n if (simulationKey === resourceKey || simulationKey.startsWith(resourceKey + '-')) {\n return resourceKey;\n }\n }\n return undefined;\n}\n\n/**\n * Get the expected component export name for a resource\n * @example getComponentName('review') // 'ReviewResource'\n * @example getComponentName('album-art') // 'AlbumArtResource'\n */\nexport function getComponentName(resourceKey: string): string {\n return `${toPascalCase(resourceKey)}Resource`;\n}\n\n// --- Node.js utilities for CLI commands ---\n// These utilities use standard Node.js APIs and can be imported by build/push/mcp commands.\n\n/**\n * Information about a discovered resource directory\n */\nexport interface ResourceDirInfo {\n /** Resource key (directory name), e.g., 'albums', 'carousel' */\n key: string;\n /** Full path to the resource directory */\n dir: string;\n /** Full path to the main resource file (tsx or json depending on context) */\n resourcePath: string;\n}\n\n/**\n * File system operations interface for dependency injection in tests\n */\nexport interface FsOps {\n readdirSync: (\n path: string,\n options: { withFileTypes: true }\n ) => Array<{ name: string; isDirectory: () => boolean }>;\n existsSync: (path: string) => boolean;\n}\n\n/**\n * Find all resource directories in a base directory.\n * Each valid resource directory contains a file matching the expected pattern.\n *\n * @param baseDir - Base directory to scan (e.g., 'src/resources' or 'dist')\n * @param filePattern - Function to generate expected filename from resource key\n * @param fs - File system operations (for testing)\n *\n * @example\n * // Find source resources (tsx files)\n * const resources = findResourceDirs('src/resources', key => `${key}.tsx`);\n *\n * @example\n * // Find built resources (js files)\n * const resources = findResourceDirs('dist', key => `${key}.js`);\n */\nexport function findResourceDirs(\n baseDir: string,\n filePattern: (key: string) => string,\n fs: FsOps\n): ResourceDirInfo[] {\n if (!fs.existsSync(baseDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(baseDir, { withFileTypes: true });\n\n return entries\n .filter((entry) => entry.isDirectory())\n .map((entry) => {\n const key = entry.name;\n const dir = `${baseDir}/${key}`;\n const resourcePath = `${dir}/${filePattern(key)}`;\n\n if (!fs.existsSync(resourcePath)) {\n return null;\n }\n\n return { key, dir, resourcePath };\n })\n .filter((info): info is ResourceDirInfo => info !== null);\n}\n\n// --- Tool files + flat simulations discovery ---\n\n/**\n * Information about a discovered tool file\n */\nexport interface ToolFileInfo {\n /** Tool name derived from filename (e.g., 'show-albums') */\n name: string;\n /** Full path to the tool file */\n path: string;\n}\n\n/**\n * Find all tool files in a tools directory.\n * Matches *.ts files directly in the directory (not recursive).\n *\n * @example\n * findToolFiles('src/tools', fs)\n * // [{ name: 'show-albums', path: 'src/tools/show-albums.ts' }]\n */\nexport function findToolFiles(\n toolsDir: string,\n fs: Pick<FsOps, 'readdirSync' | 'existsSync'>\n): ToolFileInfo[] {\n if (!fs.existsSync(toolsDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(toolsDir, { withFileTypes: true });\n\n return entries\n .filter(\n (entry) =>\n !entry.isDirectory() && entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')\n )\n .map((entry) => ({\n name: entry.name.replace(/\\.ts$/, ''),\n path: `${toolsDir}/${entry.name}`,\n }));\n}\n\n/**\n * Information about a discovered simulation file (flat convention)\n */\nexport interface SimulationFileInfo {\n /** Filename without extension (e.g., 'show-albums') */\n name: string;\n /** Full path to the simulation file */\n path: string;\n}\n\n/**\n * Find all simulation JSON files in a flat simulations directory.\n * Matches any *.json file directly in the directory.\n *\n * @example\n * findSimulationFilesFlat('tests/simulations', fs)\n * // [{ name: 'show-albums', path: 'tests/simulations/show-albums.json' }]\n */\nexport function findSimulationFilesFlat(\n simulationsDir: string,\n fs: Pick<FsOps, 'readdirSync' | 'existsSync'>\n): SimulationFileInfo[] {\n if (!fs.existsSync(simulationsDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(simulationsDir, { withFileTypes: true });\n\n return entries\n .filter((entry) => !entry.isDirectory() && entry.name.endsWith('.json'))\n .map((entry) => ({\n name: entry.name.replace(/\\.json$/, ''),\n path: `${simulationsDir}/${entry.name}`,\n }));\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,aAAa,KAAqB;AAChD,QAAO,IACJ,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;;;;;AAOb,SAAgB,mBAAmB,MAAkC;CACnE,MAAM,QAAQ,KAAK,MAAM,gBAAgB;AACzC,QAAO,QAAQ,MAAM,KAAK,KAAA;;;;;;AAO5B,SAAgB,qBAAqB,MAAkC;CACrE,MAAM,QAAQ,KAAK,MAAM,iBAAiB;AAC1C,QAAO,QAAQ,MAAM,KAAK,KAAA;;;;;;;;AAS5B,SAAgB,gBAAgB,eAAuB,cAA4C;CAEjG,MAAM,SAAS,CAAC,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO;AACpE,MAAK,MAAM,eAAe,OACxB,KAAI,kBAAkB,eAAe,cAAc,WAAW,cAAc,IAAI,CAC9E,QAAO;;;;;;;AAWb,SAAgB,iBAAiB,aAA6B;AAC5D,QAAO,GAAG,aAAa,YAAY,CAAC;;;;;;;;;;;;;;;;;;AA6CtC,SAAgB,iBACd,SACA,aACA,IACmB;AACnB,KAAI,CAAC,GAAG,WAAW,QAAQ,CACzB,QAAO,EAAE;AAKX,QAFgB,GAAG,YAAY,SAAS,EAAE,eAAe,MAAM,CAAC,CAG7D,QAAQ,UAAU,MAAM,aAAa,CAAC,CACtC,KAAK,UAAU;EACd,MAAM,MAAM,MAAM;EAClB,MAAM,MAAM,GAAG,QAAQ,GAAG;EAC1B,MAAM,eAAe,GAAG,IAAI,GAAG,YAAY,IAAI;AAE/C,MAAI,CAAC,GAAG,WAAW,aAAa,CAC9B,QAAO;AAGT,SAAO;GAAE;GAAK;GAAK;GAAc;GACjC,CACD,QAAQ,SAAkC,SAAS,KAAK;;;;;;;;;;AAuB7D,SAAgB,cACd,UACA,IACgB;AAChB,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,QAAO,EAAE;AAKX,QAFgB,GAAG,YAAY,UAAU,EAAE,eAAe,MAAM,CAAC,CAG9D,QACE,UACC,CAAC,MAAM,aAAa,IAAI,MAAM,KAAK,SAAS,MAAM,IAAI,CAAC,MAAM,KAAK,SAAS,WAAW,CACzF,CACA,KAAK,WAAW;EACf,MAAM,MAAM,KAAK,QAAQ,SAAS,GAAG;EACrC,MAAM,GAAG,SAAS,GAAG,MAAM;EAC5B,EAAE;;;;;;;;;;AAqBP,SAAgB,wBACd,gBACA,IACsB;AACtB,KAAI,CAAC,GAAG,WAAW,eAAe,CAChC,QAAO,EAAE;AAKX,QAFgB,GAAG,YAAY,gBAAgB,EAAE,eAAe,MAAM,CAAC,CAGpE,QAAQ,UAAU,CAAC,MAAM,aAAa,IAAI,MAAM,KAAK,SAAS,QAAQ,CAAC,CACvE,KAAK,WAAW;EACf,MAAM,MAAM,KAAK,QAAQ,WAAW,GAAG;EACvC,MAAM,GAAG,eAAe,GAAG,MAAM;EAClC,EAAE"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
//#region src/lib/discovery.ts
|
|
2
|
+
/**
|
|
3
|
+
* Discovery utilities for resources, tools, and simulations.
|
|
4
|
+
*
|
|
5
|
+
* String helpers (toPascalCase, extractResourceKey, etc.) are used by both
|
|
6
|
+
* browser and Node.js code. Node.js utilities (findResourceDirs, findToolFiles,
|
|
7
|
+
* etc.) are used by CLI commands for build-time and runtime discovery.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Convert a kebab-case string to PascalCase
|
|
11
|
+
* @example toPascalCase('review') // 'Review'
|
|
12
|
+
* @example toPascalCase('album-art') // 'AlbumArt'
|
|
13
|
+
*/
|
|
14
|
+
function toPascalCase(str) {
|
|
15
|
+
return str.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract the resource key from a resource file path.
|
|
19
|
+
* Matches {name}.tsx (e.g., './albums/albums.tsx' → 'albums')
|
|
20
|
+
*/
|
|
21
|
+
function extractResourceKey(path) {
|
|
22
|
+
const match = path.match(/([^/]+)\.tsx$/);
|
|
23
|
+
return match ? match[1] : void 0;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract the simulation key from a simulation file path.
|
|
27
|
+
* Matches any *.json file (e.g., './show-albums.json' → 'show-albums')
|
|
28
|
+
*/
|
|
29
|
+
function extractSimulationKey(path) {
|
|
30
|
+
const match = path.match(/([^/]+)\.json$/);
|
|
31
|
+
return match ? match[1] : void 0;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Find the best matching resource key for a simulation key.
|
|
35
|
+
* Matches the longest resource name that is a prefix of the simulation key.
|
|
36
|
+
* @example findResourceKey('review-diff', ['review', 'carousel']) // 'review'
|
|
37
|
+
* @example findResourceKey('albums', ['albums', 'review']) // 'albums'
|
|
38
|
+
*/
|
|
39
|
+
function findResourceKey(simulationKey, resourceKeys) {
|
|
40
|
+
const sorted = [...resourceKeys].sort((a, b) => b.length - a.length);
|
|
41
|
+
for (const resourceKey of sorted) if (simulationKey === resourceKey || simulationKey.startsWith(resourceKey + "-")) return resourceKey;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the expected component export name for a resource
|
|
45
|
+
* @example getComponentName('review') // 'ReviewResource'
|
|
46
|
+
* @example getComponentName('album-art') // 'AlbumArtResource'
|
|
47
|
+
*/
|
|
48
|
+
function getComponentName(resourceKey) {
|
|
49
|
+
return `${toPascalCase(resourceKey)}Resource`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find all resource directories in a base directory.
|
|
53
|
+
* Each valid resource directory contains a file matching the expected pattern.
|
|
54
|
+
*
|
|
55
|
+
* @param baseDir - Base directory to scan (e.g., 'src/resources' or 'dist')
|
|
56
|
+
* @param filePattern - Function to generate expected filename from resource key
|
|
57
|
+
* @param fs - File system operations (for testing)
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // Find source resources (tsx files)
|
|
61
|
+
* const resources = findResourceDirs('src/resources', key => `${key}.tsx`);
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // Find built resources (js files)
|
|
65
|
+
* const resources = findResourceDirs('dist', key => `${key}.js`);
|
|
66
|
+
*/
|
|
67
|
+
function findResourceDirs(baseDir, filePattern, fs) {
|
|
68
|
+
if (!fs.existsSync(baseDir)) return [];
|
|
69
|
+
return fs.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
70
|
+
const key = entry.name;
|
|
71
|
+
const dir = `${baseDir}/${key}`;
|
|
72
|
+
const resourcePath = `${dir}/${filePattern(key)}`;
|
|
73
|
+
if (!fs.existsSync(resourcePath)) return null;
|
|
74
|
+
return {
|
|
75
|
+
key,
|
|
76
|
+
dir,
|
|
77
|
+
resourcePath
|
|
78
|
+
};
|
|
79
|
+
}).filter((info) => info !== null);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Find all tool files in a tools directory.
|
|
83
|
+
* Matches *.ts files directly in the directory (not recursive).
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* findToolFiles('src/tools', fs)
|
|
87
|
+
* // [{ name: 'show-albums', path: 'src/tools/show-albums.ts' }]
|
|
88
|
+
*/
|
|
89
|
+
function findToolFiles(toolsDir, fs) {
|
|
90
|
+
if (!fs.existsSync(toolsDir)) return [];
|
|
91
|
+
return fs.readdirSync(toolsDir, { withFileTypes: true }).filter((entry) => !entry.isDirectory() && entry.name.endsWith(".ts") && !entry.name.endsWith(".test.ts")).map((entry) => ({
|
|
92
|
+
name: entry.name.replace(/\.ts$/, ""),
|
|
93
|
+
path: `${toolsDir}/${entry.name}`
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Find all simulation JSON files in a flat simulations directory.
|
|
98
|
+
* Matches any *.json file directly in the directory.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* findSimulationFilesFlat('tests/simulations', fs)
|
|
102
|
+
* // [{ name: 'show-albums', path: 'tests/simulations/show-albums.json' }]
|
|
103
|
+
*/
|
|
104
|
+
function findSimulationFilesFlat(simulationsDir, fs) {
|
|
105
|
+
if (!fs.existsSync(simulationsDir)) return [];
|
|
106
|
+
return fs.readdirSync(simulationsDir, { withFileTypes: true }).filter((entry) => !entry.isDirectory() && entry.name.endsWith(".json")).map((entry) => ({
|
|
107
|
+
name: entry.name.replace(/\.json$/, ""),
|
|
108
|
+
path: `${simulationsDir}/${entry.name}`
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
Object.defineProperty(exports, "extractResourceKey", {
|
|
113
|
+
enumerable: true,
|
|
114
|
+
get: function() {
|
|
115
|
+
return extractResourceKey;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
Object.defineProperty(exports, "extractSimulationKey", {
|
|
119
|
+
enumerable: true,
|
|
120
|
+
get: function() {
|
|
121
|
+
return extractSimulationKey;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
Object.defineProperty(exports, "findResourceDirs", {
|
|
125
|
+
enumerable: true,
|
|
126
|
+
get: function() {
|
|
127
|
+
return findResourceDirs;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
Object.defineProperty(exports, "findResourceKey", {
|
|
131
|
+
enumerable: true,
|
|
132
|
+
get: function() {
|
|
133
|
+
return findResourceKey;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
Object.defineProperty(exports, "findSimulationFilesFlat", {
|
|
137
|
+
enumerable: true,
|
|
138
|
+
get: function() {
|
|
139
|
+
return findSimulationFilesFlat;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
Object.defineProperty(exports, "findToolFiles", {
|
|
143
|
+
enumerable: true,
|
|
144
|
+
get: function() {
|
|
145
|
+
return findToolFiles;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
Object.defineProperty(exports, "getComponentName", {
|
|
149
|
+
enumerable: true,
|
|
150
|
+
get: function() {
|
|
151
|
+
return getComponentName;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
Object.defineProperty(exports, "toPascalCase", {
|
|
155
|
+
enumerable: true,
|
|
156
|
+
get: function() {
|
|
157
|
+
return toPascalCase;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
//# sourceMappingURL=discovery-Clu4uHp1.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery-Clu4uHp1.cjs","names":[],"sources":["../src/lib/discovery.ts"],"sourcesContent":["/**\n * Discovery utilities for resources, tools, and simulations.\n *\n * String helpers (toPascalCase, extractResourceKey, etc.) are used by both\n * browser and Node.js code. Node.js utilities (findResourceDirs, findToolFiles,\n * etc.) are used by CLI commands for build-time and runtime discovery.\n */\n\n/**\n * Convert a kebab-case string to PascalCase\n * @example toPascalCase('review') // 'Review'\n * @example toPascalCase('album-art') // 'AlbumArt'\n */\nexport function toPascalCase(str: string): string {\n return str\n .split('-')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\n/**\n * Extract the resource key from a resource file path.\n * Matches {name}.tsx (e.g., './albums/albums.tsx' → 'albums')\n */\nexport function extractResourceKey(path: string): string | undefined {\n const match = path.match(/([^/]+)\\.tsx$/);\n return match ? match[1] : undefined;\n}\n\n/**\n * Extract the simulation key from a simulation file path.\n * Matches any *.json file (e.g., './show-albums.json' → 'show-albums')\n */\nexport function extractSimulationKey(path: string): string | undefined {\n const match = path.match(/([^/]+)\\.json$/);\n return match ? match[1] : undefined;\n}\n\n/**\n * Find the best matching resource key for a simulation key.\n * Matches the longest resource name that is a prefix of the simulation key.\n * @example findResourceKey('review-diff', ['review', 'carousel']) // 'review'\n * @example findResourceKey('albums', ['albums', 'review']) // 'albums'\n */\nexport function findResourceKey(simulationKey: string, resourceKeys: string[]): string | undefined {\n // Sort by length descending to find longest match first\n const sorted = [...resourceKeys].sort((a, b) => b.length - a.length);\n for (const resourceKey of sorted) {\n if (simulationKey === resourceKey || simulationKey.startsWith(resourceKey + '-')) {\n return resourceKey;\n }\n }\n return undefined;\n}\n\n/**\n * Get the expected component export name for a resource\n * @example getComponentName('review') // 'ReviewResource'\n * @example getComponentName('album-art') // 'AlbumArtResource'\n */\nexport function getComponentName(resourceKey: string): string {\n return `${toPascalCase(resourceKey)}Resource`;\n}\n\n// --- Node.js utilities for CLI commands ---\n// These utilities use standard Node.js APIs and can be imported by build/push/mcp commands.\n\n/**\n * Information about a discovered resource directory\n */\nexport interface ResourceDirInfo {\n /** Resource key (directory name), e.g., 'albums', 'carousel' */\n key: string;\n /** Full path to the resource directory */\n dir: string;\n /** Full path to the main resource file (tsx or json depending on context) */\n resourcePath: string;\n}\n\n/**\n * File system operations interface for dependency injection in tests\n */\nexport interface FsOps {\n readdirSync: (\n path: string,\n options: { withFileTypes: true }\n ) => Array<{ name: string; isDirectory: () => boolean }>;\n existsSync: (path: string) => boolean;\n}\n\n/**\n * Find all resource directories in a base directory.\n * Each valid resource directory contains a file matching the expected pattern.\n *\n * @param baseDir - Base directory to scan (e.g., 'src/resources' or 'dist')\n * @param filePattern - Function to generate expected filename from resource key\n * @param fs - File system operations (for testing)\n *\n * @example\n * // Find source resources (tsx files)\n * const resources = findResourceDirs('src/resources', key => `${key}.tsx`);\n *\n * @example\n * // Find built resources (js files)\n * const resources = findResourceDirs('dist', key => `${key}.js`);\n */\nexport function findResourceDirs(\n baseDir: string,\n filePattern: (key: string) => string,\n fs: FsOps\n): ResourceDirInfo[] {\n if (!fs.existsSync(baseDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(baseDir, { withFileTypes: true });\n\n return entries\n .filter((entry) => entry.isDirectory())\n .map((entry) => {\n const key = entry.name;\n const dir = `${baseDir}/${key}`;\n const resourcePath = `${dir}/${filePattern(key)}`;\n\n if (!fs.existsSync(resourcePath)) {\n return null;\n }\n\n return { key, dir, resourcePath };\n })\n .filter((info): info is ResourceDirInfo => info !== null);\n}\n\n// --- Tool files + flat simulations discovery ---\n\n/**\n * Information about a discovered tool file\n */\nexport interface ToolFileInfo {\n /** Tool name derived from filename (e.g., 'show-albums') */\n name: string;\n /** Full path to the tool file */\n path: string;\n}\n\n/**\n * Find all tool files in a tools directory.\n * Matches *.ts files directly in the directory (not recursive).\n *\n * @example\n * findToolFiles('src/tools', fs)\n * // [{ name: 'show-albums', path: 'src/tools/show-albums.ts' }]\n */\nexport function findToolFiles(\n toolsDir: string,\n fs: Pick<FsOps, 'readdirSync' | 'existsSync'>\n): ToolFileInfo[] {\n if (!fs.existsSync(toolsDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(toolsDir, { withFileTypes: true });\n\n return entries\n .filter(\n (entry) =>\n !entry.isDirectory() && entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')\n )\n .map((entry) => ({\n name: entry.name.replace(/\\.ts$/, ''),\n path: `${toolsDir}/${entry.name}`,\n }));\n}\n\n/**\n * Information about a discovered simulation file (flat convention)\n */\nexport interface SimulationFileInfo {\n /** Filename without extension (e.g., 'show-albums') */\n name: string;\n /** Full path to the simulation file */\n path: string;\n}\n\n/**\n * Find all simulation JSON files in a flat simulations directory.\n * Matches any *.json file directly in the directory.\n *\n * @example\n * findSimulationFilesFlat('tests/simulations', fs)\n * // [{ name: 'show-albums', path: 'tests/simulations/show-albums.json' }]\n */\nexport function findSimulationFilesFlat(\n simulationsDir: string,\n fs: Pick<FsOps, 'readdirSync' | 'existsSync'>\n): SimulationFileInfo[] {\n if (!fs.existsSync(simulationsDir)) {\n return [];\n }\n\n const entries = fs.readdirSync(simulationsDir, { withFileTypes: true });\n\n return entries\n .filter((entry) => !entry.isDirectory() && entry.name.endsWith('.json'))\n .map((entry) => ({\n name: entry.name.replace(/\\.json$/, ''),\n path: `${simulationsDir}/${entry.name}`,\n }));\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,aAAa,KAAqB;AAChD,QAAO,IACJ,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;;;;;AAOb,SAAgB,mBAAmB,MAAkC;CACnE,MAAM,QAAQ,KAAK,MAAM,gBAAgB;AACzC,QAAO,QAAQ,MAAM,KAAK,KAAA;;;;;;AAO5B,SAAgB,qBAAqB,MAAkC;CACrE,MAAM,QAAQ,KAAK,MAAM,iBAAiB;AAC1C,QAAO,QAAQ,MAAM,KAAK,KAAA;;;;;;;;AAS5B,SAAgB,gBAAgB,eAAuB,cAA4C;CAEjG,MAAM,SAAS,CAAC,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,OAAO;AACpE,MAAK,MAAM,eAAe,OACxB,KAAI,kBAAkB,eAAe,cAAc,WAAW,cAAc,IAAI,CAC9E,QAAO;;;;;;;AAWb,SAAgB,iBAAiB,aAA6B;AAC5D,QAAO,GAAG,aAAa,YAAY,CAAC;;;;;;;;;;;;;;;;;;AA6CtC,SAAgB,iBACd,SACA,aACA,IACmB;AACnB,KAAI,CAAC,GAAG,WAAW,QAAQ,CACzB,QAAO,EAAE;AAKX,QAFgB,GAAG,YAAY,SAAS,EAAE,eAAe,MAAM,CAAC,CAG7D,QAAQ,UAAU,MAAM,aAAa,CAAC,CACtC,KAAK,UAAU;EACd,MAAM,MAAM,MAAM;EAClB,MAAM,MAAM,GAAG,QAAQ,GAAG;EAC1B,MAAM,eAAe,GAAG,IAAI,GAAG,YAAY,IAAI;AAE/C,MAAI,CAAC,GAAG,WAAW,aAAa,CAC9B,QAAO;AAGT,SAAO;GAAE;GAAK;GAAK;GAAc;GACjC,CACD,QAAQ,SAAkC,SAAS,KAAK;;;;;;;;;;AAuB7D,SAAgB,cACd,UACA,IACgB;AAChB,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,QAAO,EAAE;AAKX,QAFgB,GAAG,YAAY,UAAU,EAAE,eAAe,MAAM,CAAC,CAG9D,QACE,UACC,CAAC,MAAM,aAAa,IAAI,MAAM,KAAK,SAAS,MAAM,IAAI,CAAC,MAAM,KAAK,SAAS,WAAW,CACzF,CACA,KAAK,WAAW;EACf,MAAM,MAAM,KAAK,QAAQ,SAAS,GAAG;EACrC,MAAM,GAAG,SAAS,GAAG,MAAM;EAC5B,EAAE;;;;;;;;;;AAqBP,SAAgB,wBACd,gBACA,IACsB;AACtB,KAAI,CAAC,GAAG,WAAW,eAAe,CAChC,QAAO,EAAE;AAKX,QAFgB,GAAG,YAAY,gBAAgB,EAAE,eAAe,MAAM,CAAC,CAGpE,QAAQ,UAAU,CAAC,MAAM,aAAa,IAAI,MAAM,KAAK,SAAS,QAAQ,CAAC,CACvE,KAAK,WAAW;EACf,MAAM,MAAM,KAAK,QAAQ,WAAW,GAAG;EACvC,MAAM,GAAG,eAAe,GAAG,MAAM;EAClC,EAAE"}
|
package/dist/index.cjs
CHANGED
|
@@ -2,8 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_chunk = require("./chunk-9hOWP6kD.cjs");
|
|
3
3
|
const require_protocol = require("./protocol-jbxhzcnS.cjs");
|
|
4
4
|
const require_use_app = require("./use-app-D2h-aiyr.cjs");
|
|
5
|
-
const require_simulator = require("./simulator-
|
|
6
|
-
const require_discovery = require("./discovery-BxKCIgG5.cjs");
|
|
5
|
+
const require_simulator = require("./simulator-CH9hs0N6.cjs");
|
|
7
6
|
const require_host_index = require("./host/index.cjs");
|
|
8
7
|
const require_simulator_index = require("./simulator/index.cjs");
|
|
9
8
|
const require_chatgpt_index = require("./chatgpt/index.cjs");
|
|
@@ -3227,7 +3226,6 @@ exports.TOOL_RESULT_METHOD = require_use_app.l;
|
|
|
3227
3226
|
exports.applyDocumentTheme = require_use_app.FQ;
|
|
3228
3227
|
exports.applyHostFonts = require_use_app.TQ;
|
|
3229
3228
|
exports.applyHostStyleVariables = require_use_app.PQ;
|
|
3230
|
-
exports.buildResourceMap = require_discovery.buildResourceMap;
|
|
3231
3229
|
Object.defineProperty(exports, "chatgpt", {
|
|
3232
3230
|
enumerable: true,
|
|
3233
3231
|
get: function() {
|
|
@@ -3235,7 +3233,6 @@ Object.defineProperty(exports, "chatgpt", {
|
|
|
3235
3233
|
}
|
|
3236
3234
|
});
|
|
3237
3235
|
exports.cn = cn;
|
|
3238
|
-
exports.createResourceExports = require_discovery.createResourceExports;
|
|
3239
3236
|
exports.detectHost = require_host_index.detectHost;
|
|
3240
3237
|
exports.detectPlatform = require_host_index.detectPlatform;
|
|
3241
3238
|
exports.getDocumentTheme = require_use_app.AQ;
|