sunpeak 0.20.2 → 0.20.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +59 -89
  2. package/bin/commands/dev.mjs +23 -4
  3. package/bin/commands/inspect.mjs +111 -4
  4. package/bin/commands/new.mjs +33 -9
  5. package/bin/commands/test-init.mjs +25 -23
  6. package/bin/commands/test.mjs +4 -3
  7. package/bin/lib/eval/eval-runner.mjs +27 -1
  8. package/bin/lib/eval/model-registry.mjs +6 -1
  9. package/bin/lib/test/base-config.mjs +11 -4
  10. package/bin/sunpeak.js +16 -15
  11. package/dist/chatgpt/index.cjs +1 -1
  12. package/dist/chatgpt/index.js +1 -1
  13. package/dist/claude/index.cjs +1 -1
  14. package/dist/claude/index.js +1 -1
  15. package/dist/host/chatgpt/index.cjs +1 -1
  16. package/dist/host/chatgpt/index.js +1 -1
  17. package/dist/index.cjs +3 -3
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.js +3 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/inspector/index.cjs +1 -1
  22. package/dist/inspector/index.js +1 -1
  23. package/dist/{inspector-BBDa5yCm.js → inspector-60Na_Zc4.js} +2 -2
  24. package/dist/inspector-60Na_Zc4.js.map +1 -0
  25. package/dist/{inspector-DAA1Wiyh.cjs → inspector-D0qOqYX2.cjs} +2 -2
  26. package/dist/{inspector-BBDa5yCm.js.map → inspector-D0qOqYX2.cjs.map} +1 -1
  27. package/dist/mcp/index.cjs +24 -3
  28. package/dist/mcp/index.cjs.map +1 -1
  29. package/dist/mcp/index.js +24 -3
  30. package/dist/mcp/index.js.map +1 -1
  31. package/dist/mcp/types.d.ts +1 -0
  32. package/dist/{use-app-DPkj5Jp_.cjs → use-app-B33mckz4.cjs} +7 -3
  33. package/dist/use-app-B33mckz4.cjs.map +1 -0
  34. package/dist/{use-app-Cr0auUa1.js → use-app-kv5GQr0G.js} +7 -3
  35. package/dist/use-app-kv5GQr0G.js.map +1 -0
  36. package/package.json +3 -3
  37. package/template/README.md +21 -23
  38. package/template/dist/albums/albums.html +1 -1
  39. package/template/dist/albums/albums.json +1 -1
  40. package/template/dist/carousel/carousel.html +1 -1
  41. package/template/dist/carousel/carousel.json +1 -1
  42. package/template/dist/map/map.html +1 -1
  43. package/template/dist/map/map.json +1 -1
  44. package/template/dist/review/review.html +1 -1
  45. package/template/dist/review/review.json +1 -1
  46. package/template/node_modules/.vite/deps/_metadata.json +3 -3
  47. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js +6 -2
  48. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps.js.map +1 -1
  49. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js +1 -1
  50. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_app-bridge.js.map +1 -1
  51. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js +6 -2
  52. package/template/node_modules/.vite-mcp/deps/@modelcontextprotocol_ext-apps_react.js.map +1 -1
  53. package/template/node_modules/.vite-mcp/deps/_metadata.json +22 -22
  54. package/template/package.json +2 -1
  55. package/template/tests/e2e/visual.spec.ts +2 -2
  56. package/template/tests/evals/albums.eval.ts +1 -1
  57. package/template/tests/evals/map.eval.ts +1 -1
  58. package/template/tests/evals/review.eval.ts +4 -2
  59. package/dist/inspector-DAA1Wiyh.cjs.map +0 -1
  60. package/dist/use-app-Cr0auUa1.js.map +0 -1
  61. package/dist/use-app-DPkj5Jp_.cjs.map +0 -1
@@ -112,9 +112,35 @@ export async function discoverAndConvertTools(client) {
112
112
  const tools = {};
113
113
 
114
114
  for (const t of mcpTools) {
115
+ // Clean up the MCP inputSchema for AI provider compatibility.
116
+ // OpenAI rejects $schema, additionalProperties: {} (empty schema has no type),
117
+ // and other JSON Schema features that MCP servers may include.
118
+ const rawSchema = t.inputSchema || { type: 'object', properties: {} };
119
+ const cleanSchema = { ...rawSchema };
120
+ delete cleanSchema.$schema;
121
+ if (
122
+ cleanSchema.additionalProperties != null &&
123
+ typeof cleanSchema.additionalProperties === 'object' &&
124
+ Object.keys(cleanSchema.additionalProperties).length === 0
125
+ ) {
126
+ // Empty additionalProperties ({}) causes OpenAI to report type: "None".
127
+ // Remove it so the schema is a plain { type: "object", properties: {...} }.
128
+ delete cleanSchema.additionalProperties;
129
+ }
130
+ if (!cleanSchema.type) cleanSchema.type = 'object';
131
+ if (!cleanSchema.properties) cleanSchema.properties = {};
132
+ // Remove `required` so the model isn't forced to ask the user for every
133
+ // parameter before calling a tool. Eval prompts are intentionally vague
134
+ // ("show me photo albums") and the model should call the tool with
135
+ // reasonable defaults, not refuse because required fields are missing.
136
+ delete cleanSchema.required;
137
+
115
138
  tools[t.name] = aiTool({
116
139
  description: t.description || '',
117
- parameters: jsonSchema(t.inputSchema || { type: 'object', properties: {} }),
140
+ // Set both so the tool works with ai v4/v5 (reads `parameters`)
141
+ // and ai v6 (reads `inputSchema`). tool() passes through both.
142
+ inputSchema: jsonSchema(cleanSchema),
143
+ parameters: jsonSchema(cleanSchema),
118
144
  execute: async (args) => {
119
145
  const result = await client.callTool({ name: t.name, arguments: args });
120
146
  // Return a simplified version for the model to consume
@@ -44,7 +44,12 @@ export async function resolveModel(modelId) {
44
44
  // that creates model instances: openai('gpt-4o'), anthropic('claude-...'), google('gemini-...')
45
45
  if (pkg === '@ai-sdk/openai') {
46
46
  const { openai } = provider;
47
- return openai(modelId);
47
+ // @ai-sdk/openai v3 defaults to the Responses API, which requires strict
48
+ // JSON Schema (additionalProperties: false at every level, all properties
49
+ // required) — incompatible with arbitrary MCP server schemas. Use .chat()
50
+ // (Chat Completions API) when available. v1/v2 default to Chat Completions
51
+ // already and may not have .chat(), so fall back to the default.
52
+ return typeof openai.chat === 'function' ? openai.chat(modelId) : openai(modelId);
48
53
  }
49
54
  if (pkg === '@ai-sdk/anthropic') {
50
55
  const { anthropic } = provider;
@@ -5,8 +5,6 @@
5
5
  * Produces a config with per-host Playwright projects, sensible defaults for
6
6
  * MCP App testing, and a webServer entry to launch the inspector backend.
7
7
  */
8
- import { getPortSync } from '../get-port.mjs';
9
-
10
8
  /**
11
9
  * @param {Object} options
12
10
  * @param {string[]} options.hosts - Host shells to create projects for
@@ -63,10 +61,19 @@ export function createBaseConfig({ hosts, testDir, webServer, port, use, globalS
63
61
  /**
64
62
  * Resolve ports for the inspector and sandbox proxy.
65
63
  * Respects env vars for CI where validate.mjs assigns unique ports.
64
+ *
65
+ * Uses FIXED default ports (no dynamic probing) so all Playwright workers
66
+ * resolve the same baseURL. Dynamic port probing (getPortSync) caused flaky
67
+ * tests: the main process would pick port X, start the webServer on it, then
68
+ * worker processes re-evaluating the config would find X occupied and resolve
69
+ * to random ports Y/Z — causing ERR_CONNECTION_REFUSED.
70
+ *
71
+ * If the default port is busy, Playwright's reuseExistingServer (local) reuses
72
+ * it, or strictPort (CI) fails fast with a clear error.
66
73
  */
67
74
  export function resolvePorts() {
68
- const port = parsePort(process.env.SUNPEAK_TEST_PORT) ?? getPortSync(6776);
69
- const sandboxPort = parsePort(process.env.SUNPEAK_SANDBOX_PORT) ?? getPortSync(24680);
75
+ const port = parsePort(process.env.SUNPEAK_TEST_PORT) ?? 6776;
76
+ const sandboxPort = parsePort(process.env.SUNPEAK_SANDBOX_PORT) ?? 24680;
70
77
  return { port, sandboxPort };
71
78
  }
72
79
 
package/bin/sunpeak.js CHANGED
@@ -102,22 +102,11 @@ function getVersion() {
102
102
  {
103
103
  const resources = discoverResources();
104
104
  console.log(`
105
- ☀️ 🏔️ sunpeak - Inspector, testing framework, and app framework for MCP Apps
105
+ ☀️ 🏔️ sunpeak - App framework, testing framework, and inspector for MCP Apps
106
106
 
107
- Install:
108
- pnpm add -g sunpeak
107
+ Usage: npx sunpeak <command>
109
108
 
110
- Testing (works with any MCP server):
111
- sunpeak inspect Inspect any MCP server in the inspector
112
- --server, -s <url|cmd> MCP server URL or stdio command (required)
113
- --simulations <dir> Simulation JSON directory
114
- sunpeak test Run e2e tests against the inspector
115
- init Scaffold test infrastructure into a project
116
- --unit Run unit tests (vitest)
117
- --live Run live tests against real hosts
118
- --eval Run evals against LLM models
119
-
120
- App framework (for sunpeak projects):
109
+ App framework:
121
110
  sunpeak new [name] [resources] Create a new project
122
111
  sunpeak dev Start dev server + inspector + MCP endpoint
123
112
  --no-begging Suppress GitHub star message
@@ -125,8 +114,20 @@ App framework (for sunpeak projects):
125
114
  sunpeak start Start production MCP server
126
115
  --port, -p Server port (default: 8000, or PORT env)
127
116
  sunpeak upgrade Upgrade sunpeak to latest version
128
- sunpeak --version Show version number
129
117
 
118
+ Testing (works with any MCP server):
119
+ sunpeak test Run e2e tests against the inspector
120
+ init Scaffold test infrastructure into a project
121
+ --unit Run unit tests (vitest)
122
+ --live Run live tests against real hosts
123
+ --eval Run evals against LLM models
124
+
125
+ Inspector (works with any MCP server):
126
+ sunpeak inspect Inspect any MCP server in the inspector
127
+ --server, -s <url|cmd> MCP server URL or stdio command (required)
128
+ --simulations <dir> Simulation JSON directory
129
+
130
+ sunpeak --version Show version number
130
131
  Resources: ${resources.join(', ')} (comma/space separated)
131
132
  Example: sunpeak new sunpeak-app "${resources.slice(0, 2).join(',')}"
132
133
  `);
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("../chunk-9hOWP6kD.cjs");
3
- const require_inspector = require("../inspector-DAA1Wiyh.cjs");
3
+ const require_inspector = require("../inspector-D0qOqYX2.cjs");
4
4
  const require_inspector_url = require("../inspector-url-C3LTKgXt.cjs");
5
5
  const require_discovery = require("../discovery-Clu4uHp1.cjs");
6
6
  //#region src/chatgpt/index.ts
@@ -1,5 +1,5 @@
1
1
  import { r as __exportAll } from "../chunk-D6g4UhsZ.js";
2
- 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-BBDa5yCm.js";
2
+ 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-60Na_Zc4.js";
3
3
  import { t as createInspectorUrl } from "../inspector-url-CyQcuBI9.js";
4
4
  import { c as toPascalCase, i as findResourceKey, n as extractSimulationKey, r as findResourceDirs, s as getComponentName, t as extractResourceKey } from "../discovery-Cgoegt62.js";
5
5
  //#region src/chatgpt/index.ts
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../chunk-9hOWP6kD.cjs");
3
- const require_inspector = require("../inspector-DAA1Wiyh.cjs");
3
+ const require_inspector = require("../inspector-D0qOqYX2.cjs");
4
4
  exports.Inspector = require_inspector.Inspector;
@@ -1,2 +1,2 @@
1
- import { t as Inspector } from "../inspector-BBDa5yCm.js";
1
+ import { t as Inspector } from "../inspector-60Na_Zc4.js";
2
2
  export { Inspector };
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-9hOWP6kD.cjs");
3
- const require_use_app = require("../../use-app-DPkj5Jp_.cjs");
3
+ const require_use_app = require("../../use-app-B33mckz4.cjs");
4
4
  let react = require("react");
5
5
  //#region src/host/chatgpt/openai-types.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { t as useApp } from "../../use-app-Cr0auUa1.js";
1
+ import { t as useApp } from "../../use-app-kv5GQr0G.js";
2
2
  import { useCallback } from "react";
3
3
  //#region src/host/chatgpt/openai-types.ts
4
4
  /**
package/dist/index.cjs CHANGED
@@ -1,15 +1,15 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-9hOWP6kD.cjs");
3
3
  const require_protocol = require("./protocol-C8pFDmcy.cjs");
4
- const require_use_app = require("./use-app-DPkj5Jp_.cjs");
5
- const require_inspector = require("./inspector-DAA1Wiyh.cjs");
4
+ const require_use_app = require("./use-app-B33mckz4.cjs");
5
+ const require_inspector = require("./inspector-D0qOqYX2.cjs");
6
6
  const require_host_index = require("./host/index.cjs");
7
7
  const require_inspector_index = require("./inspector/index.cjs");
8
8
  const require_chatgpt_index = require("./chatgpt/index.cjs");
9
9
  let react = require("react");
10
10
  react = require_chunk.__toESM(react, 1);
11
11
  let react_jsx_runtime = require("react/jsx-runtime");
12
- //#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.5.0_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__react-_a8a8e071c354e7dd6f62871eadf46f99/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js
12
+ //#region ../../node_modules/.pnpm/@modelcontextprotocol+ext-apps@1.6.0_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__react-_1fd7d0151a0915598274278e5ddb69e9/node_modules/@modelcontextprotocol/ext-apps/dist/src/react/index.js
13
13
  var m = require_protocol.union([require_protocol.literal("light"), require_protocol.literal("dark")]).describe("Color theme preference for the host environment."), N$1 = require_protocol.union([
14
14
  require_protocol.literal("inline"),
15
15
  require_protocol.literal("fullscreen"),