@vibevibes/mcp 0.8.1 → 0.9.1

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/dist/index.d.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /**
2
- * vibevibes-mcp MCP server for agent participation in vibevibes experiences.
2
+ * vibevibes MCP server connects Claude to a running vibevibes experience.
3
3
  *
4
- * The `connect` tool is the single entry point: it joins the server, writes
5
- * the state file (for the stop hook to poll), and returns room info.
6
- *
7
- * 4 tools: connect, act, look, disconnect
4
+ * The dev server (vibevibes-dev from @vibevibes/sdk) must be running first.
5
+ * 5 tools: connect, act, look, screenshot, disconnect
8
6
  */
9
7
  export {};
package/dist/index.js CHANGED
@@ -1,10 +1,8 @@
1
1
  /**
2
- * vibevibes-mcp MCP server for agent participation in vibevibes experiences.
2
+ * vibevibes MCP server connects Claude to a running vibevibes experience.
3
3
  *
4
- * The `connect` tool is the single entry point: it joins the server, writes
5
- * the state file (for the stop hook to poll), and returns room info.
6
- *
7
- * 4 tools: connect, act, look, disconnect
4
+ * The dev server (vibevibes-dev from @vibevibes/sdk) must be running first.
5
+ * 5 tools: connect, act, look, screenshot, disconnect
8
6
  */
9
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -12,101 +10,35 @@ import { z } from "zod";
12
10
  import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from "node:fs";
13
11
  import { resolve, dirname } from "node:path";
14
12
  import { fileURLToPath } from "node:url";
15
- import { spawn, spawnSync } from "node:child_process";
13
+ import { spawnSync } from "node:child_process";
16
14
  /** Extract error message from unknown catch value. */
17
15
  function toErrorMessage(err) {
18
16
  return err instanceof Error ? err.message : String(err);
19
17
  }
20
- // ── Server auto-start ──────────────────────────────────────
21
- let serverStarted = false;
18
+ // ── Server check ──────────────────────────────────────
19
+ let serverReachable = false;
22
20
  /**
23
- * Check if the server is reachable. If not, start it in a child process.
24
- * The server loads the experience from the given project root.
21
+ * Check if the dev server is reachable.
22
+ * If not, throw an error telling the agent to run `npm run dev`.
25
23
  */
26
- async function ensureServerRunning(projectRoot) {
27
- if (serverStarted)
24
+ async function ensureServerRunning() {
25
+ if (serverReachable)
28
26
  return;
29
- // Check if server is already running
30
27
  try {
31
28
  const controller = new AbortController();
32
29
  const timer = setTimeout(() => controller.abort(), 2000);
33
30
  const res = await fetch(`${SERVER_URL}/state`, { signal: controller.signal });
34
31
  clearTimeout(timer);
35
32
  if (res.ok) {
36
- serverStarted = true;
33
+ serverReachable = true;
37
34
  return;
38
35
  }
39
36
  }
40
37
  catch {
41
- // Server not running — start it
42
- }
43
- // Find the server entry point (in mcp/dist/ or mcp/src/)
44
- const serverScript = resolve(MCP_ROOT, "dist/server.js");
45
- const serverTs = resolve(MCP_ROOT, "src/server.ts");
46
- // Start server as a child process using a small bootstrap script
47
- const bootstrapCode = `
48
- import("${serverScript.replace(/\\/g, "/")}").then(m => {
49
- m.startServer({ projectRoot: "${projectRoot.replace(/\\/g, "/")}" });
50
- }).catch(e => {
51
- // Fallback: try tsx for .ts source
52
- import("${serverTs.replace(/\\/g, "/")}").then(m => {
53
- m.startServer({ projectRoot: "${projectRoot.replace(/\\/g, "/")}" });
54
- }).catch(e2 => {
55
- console.error("Failed to start server:", e2.message);
56
- process.exit(1);
57
- });
58
- });
59
- `;
60
- const child = spawn(process.execPath, ["--input-type=module", "-e", bootstrapCode], {
61
- stdio: ["pipe", "pipe", "pipe"],
62
- detached: true,
63
- env: { ...process.env, PORT: new URL(SERVER_URL).port || "4321" },
64
- });
65
- child.unref();
66
- // Store child for cleanup
67
- serverChild = child;
68
- child.stderr?.on("data", (chunk) => {
69
- const msg = chunk.toString().trim();
70
- if (msg)
71
- console.error(`[server] ${msg}`);
72
- });
73
- // Wait for server to become available (up to 15 seconds)
74
- const deadline = Date.now() + 15000;
75
- while (Date.now() < deadline) {
76
- await new Promise((r) => setTimeout(r, 500));
77
- try {
78
- const controller = new AbortController();
79
- const timer = setTimeout(() => controller.abort(), 1500);
80
- const res = await fetch(`${SERVER_URL}/state`, { signal: controller.signal });
81
- clearTimeout(timer);
82
- if (res.ok) {
83
- serverStarted = true;
84
- return;
85
- }
86
- }
87
- catch {
88
- // Keep waiting
89
- }
38
+ // Not reachable
90
39
  }
91
- throw new Error(`Server failed to start within 15 seconds at ${SERVER_URL}`);
40
+ throw new Error(`Dev server not running at ${SERVER_URL}. Run \`npm run dev\` first (in a background shell), then try again.`);
92
41
  }
93
- let serverChild = null;
94
- // Cleanup server on exit
95
- process.on("exit", () => { if (serverChild)
96
- try {
97
- serverChild.kill();
98
- }
99
- catch { } });
100
- process.on("SIGINT", () => { if (serverChild)
101
- try {
102
- serverChild.kill();
103
- }
104
- catch { } process.exit(0); });
105
- process.on("SIGTERM", () => { if (serverChild)
106
- try {
107
- serverChild.kill();
108
- }
109
- catch { } process.exit(0); });
110
42
  // Resolve server URL: CLI arg > env var > localhost default
111
43
  const RAW_SERVER_URL = process.argv[2] ||
112
44
  process.env.VIBEVIBES_SERVER_URL ||
@@ -323,8 +255,8 @@ Call this first, then use act to interact. The stop hook keeps you present.`, {
323
255
  if (url) {
324
256
  SERVER_URL = url.replace(/\/$/, "");
325
257
  }
326
- // Auto-start server if not running
327
- await ensureServerRunning(PROJECT_ROOT);
258
+ // Check dev server is running
259
+ await ensureServerRunning();
328
260
  // Check if already connected (same process re-calling connect)
329
261
  let identity = null;
330
262
  if (currentOwner && existsSync(AGENTS_DIR)) {
package/hooks/logic.js CHANGED
@@ -136,9 +136,14 @@ export function makeDecision(ctx, iteration) {
136
136
  // Experience signaled completion — allow exit (agent file already deleted by stop-hook)
137
137
  if (ctx.observation?.done)
138
138
  return null;
139
- // Nothing to react toallow exit silently (zero wasted tokens)
140
- if (!hasEvents && !hasError && !hasBrowserErrors && !hasObserveError)
141
- return null;
139
+ // Always block exit while connected the agent should stay alive.
140
+ // If there are events/errors, include them. Otherwise, minimal keepalive.
141
+ if (!hasEvents && !hasError && !hasBrowserErrors && !hasObserveError) {
142
+ return {
143
+ decision: "block",
144
+ reason: "Still connected. Waiting for activity.",
145
+ };
146
+ }
142
147
  const reason = formatPrompt(ctx);
143
148
  return {
144
149
  decision: "block",
package/package.json CHANGED
@@ -1,33 +1,25 @@
1
1
  {
2
2
  "name": "@vibevibes/mcp",
3
- "version": "0.8.1",
4
- "description": "MCP server + runtime engine for vibevibes experiences",
3
+ "version": "0.9.1",
4
+ "description": "MCP server connects Claude to vibevibes experiences",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
9
- "vibevibes": "./bin/cli.js",
10
- "vibevibes-serve": "./bin/serve.js"
9
+ "vibevibes": "./bin/cli.js"
11
10
  },
12
11
  "scripts": {
13
- "build": "tsc && tsc -p tsconfig.hooks.json && node -e \"const{cpSync}=require('fs');cpSync('src/viewer','dist/viewer',{recursive:true})\"",
12
+ "build": "tsc && tsc -p tsconfig.hooks.json",
14
13
  "postinstall": "node ./bin/postinstall.js",
15
14
  "prepublishOnly": "npm run build",
16
15
  "dev": "tsx src/index.ts"
17
16
  },
18
17
  "dependencies": {
19
18
  "@modelcontextprotocol/sdk": "^1.9.0",
20
- "@vibevibes/sdk": "^0.3.0",
21
- "esbuild": "^0.27.2",
22
- "express": "^4.18.2",
23
- "ws": "^8.19.0",
24
- "zod": "^3.22.4",
25
- "zod-to-json-schema": "^3.22.4"
19
+ "zod": "^3.22.4"
26
20
  },
27
21
  "devDependencies": {
28
- "@types/express": "^4.17.21",
29
22
  "@types/node": "^20.11.5",
30
- "@types/ws": "^8.18.1",
31
23
  "tsx": "^4.7.0",
32
24
  "typescript": "^5.3.3"
33
25
  },
@@ -50,10 +42,6 @@
50
42
  "vibevibes",
51
43
  "mcp",
52
44
  "model-context-protocol",
53
- "multiplayer",
54
- "ai-native",
55
- "shared-experience",
56
- "real-time",
57
- "websocket"
45
+ "ai-native"
58
46
  ]
59
47
  }
package/bin/serve.js DELETED
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Start the vibevibes server for an experience.
5
- *
6
- * Usage:
7
- * npx vibevibes-serve # serves from current directory
8
- * npx vibevibes-serve ./my-exp # serves from a specific path
9
- */
10
-
11
- import { resolve } from "node:path";
12
- import { writeFileSync, existsSync } from "node:fs";
13
- import { execSync } from "node:child_process";
14
- import { startServer } from "../dist/server.js";
15
-
16
- const projectRoot = resolve(process.argv[2] || ".");
17
- const port = parseInt(process.env.PORT || "4321", 10);
18
-
19
- // Find git root (where Claude Code reads .mcp.json from)
20
- let mcpJsonDir = projectRoot;
21
- try {
22
- mcpJsonDir = execSync("git rev-parse --show-toplevel", { cwd: projectRoot, encoding: "utf-8" }).trim();
23
- } catch {}
24
-
25
- // Auto-generate .mcp.json so Claude Code can connect via /mcp
26
- const mcpJsonPath = resolve(mcpJsonDir, ".mcp.json");
27
- if (!existsSync(mcpJsonPath)) {
28
- const config = {
29
- mcpServers: {
30
- vibevibes: {
31
- command: "npx",
32
- args: ["vibevibes-mcp"],
33
- env: { VIBEVIBES_SERVER_URL: `http://localhost:${port}` },
34
- },
35
- },
36
- };
37
- writeFileSync(mcpJsonPath, JSON.stringify(config, null, 2) + "\n");
38
- console.log(` .mcp.json: wrote ${mcpJsonPath}`);
39
- }
40
-
41
- startServer({ projectRoot, port });
package/dist/bundler.d.ts DELETED
@@ -1,36 +0,0 @@
1
- /**
2
- * Experience bundler — produces server and client bundles from src/index.tsx.
3
- *
4
- * Server bundle: CJS, eval'd via new Function() to extract tools + manifest.
5
- * Client bundle: ESM, loaded in browser via blob URL + dynamic import().
6
- *
7
- * Extracted from create-experience/runtime/bundler.ts into @vibevibes/runtime.
8
- */
9
- /**
10
- * Bundle for server-side tool execution (Node.js eval).
11
- * Returns the raw ExperienceModule extracted via new Function().
12
- */
13
- export declare function bundleForServer(entryPath: string): Promise<string>;
14
- /**
15
- * Evaluate a server bundle and extract the ExperienceModule.
16
- */
17
- export declare function evalServerBundle(serverCode: string): Promise<unknown>;
18
- /**
19
- * Bundle for client-side Canvas rendering (browser).
20
- * Returns pure ESM. External imports (react, zod, etc.) are left as-is —
21
- * the viewer's import map resolves them in the browser.
22
- */
23
- export declare function bundleForClient(entryPath: string): Promise<string>;
24
- /**
25
- * Build both bundles from an entry file.
26
- */
27
- export declare function buildExperience(entryPath: string): Promise<{
28
- serverCode: string;
29
- clientCode: string;
30
- }>;
31
- /**
32
- * Validate a client bundle for common issues.
33
- * Lightweight — esbuild already validates syntax. This just checks the output exists.
34
- * Returns null if OK, or an error message string.
35
- */
36
- export declare function validateClientBundle(code: string): string | null;
package/dist/bundler.js DELETED
@@ -1,254 +0,0 @@
1
- /**
2
- * Experience bundler — produces server and client bundles from src/index.tsx.
3
- *
4
- * Server bundle: CJS, eval'd via new Function() to extract tools + manifest.
5
- * Client bundle: ESM, loaded in browser via blob URL + dynamic import().
6
- *
7
- * Extracted from create-experience/runtime/bundler.ts into @vibevibes/runtime.
8
- */
9
- import * as esbuild from "esbuild";
10
- const EXTERNALS = ["react", "react/jsx-runtime", "react-dom", "react-dom/client", "yjs", "zod", "@vibevibes/sdk", "@vibevibes/runtime"];
11
- // Additional externals for server-only bundles — heavy rendering libraries that
12
- // aren't needed for tool/test execution. Canvas components are never called server-side.
13
- const SERVER_ONLY_EXTERNALS = [
14
- ...EXTERNALS,
15
- "three", "three/*",
16
- "@react-three/fiber", "@react-three/fiber/*",
17
- "@react-three/drei", "@react-three/drei/*",
18
- ];
19
- /**
20
- * Strip esbuild's CJS annotation: `0 && (module.exports = {...})`.
21
- * Uses brace-depth counting to handle nested objects/functions in the annotation,
22
- * unlike a simple `[^}]*` regex which breaks on nested braces.
23
- */
24
- function stripCjsAnnotation(code) {
25
- const marker = /0\s*&&\s*\(module\.exports\s*=\s*\{/g;
26
- let match;
27
- let result = code;
28
- while ((match = marker.exec(code)) !== null) {
29
- const start = match.index;
30
- let depth = 1; // we matched the opening `{`
31
- let i = match.index + match[0].length;
32
- while (i < code.length && depth > 0) {
33
- if (code[i] === "{")
34
- depth++;
35
- else if (code[i] === "}")
36
- depth--;
37
- i++;
38
- }
39
- // Skip the closing `)` and optional `;`
40
- if (i < code.length && code[i] === ")")
41
- i++;
42
- if (i < code.length && code[i] === ";")
43
- i++;
44
- result = result.slice(0, start) + "/* [vibevibes] stripped CJS annotation */" + result.slice(i);
45
- break; // Only one annotation per bundle
46
- }
47
- return result;
48
- }
49
- /**
50
- * Strip import/export statements for external packages.
51
- * The runtime provides these via globalThis (browser) or function args (server).
52
- */
53
- /**
54
- * Strip external imports from a CJS server bundle so it can be eval'd with new Function().
55
- * Only used for server bundles — client bundles keep imports (resolved by browser import map).
56
- */
57
- function stripExternalImports(code, externals = EXTERNALS) {
58
- let result = code;
59
- for (const ext of externals) {
60
- let escaped;
61
- if (ext.endsWith("/*")) {
62
- const base = ext.slice(0, -2).replace(/[.*+?^${}()|[\]\\\/]/g, "\\$&");
63
- escaped = `${base}\\/[^"']+`;
64
- }
65
- else {
66
- escaped = ext.replace(/[.*+?^${}()|[\]\\\/]/g, "\\$&");
67
- }
68
- // CJS: var import_X = __toESM(require("pkg"), N); or var import_X = require("pkg");
69
- result = result.replace(new RegExp(`var\\s+\\w+\\s*=\\s*(?:__toESM\\()?require\\(["']${escaped}["']\\)[^;]{0,500};`, "g"), "");
70
- }
71
- return result;
72
- }
73
- /**
74
- * CJS shim definitions for server-side eval (new Function()).
75
- * Maps esbuild-generated variable names to runtime-provided globals.
76
- */
77
- const SDK_CORE_SHIM = "{ defineExperience: defineExperience, defineTool: defineTool, defineTest: defineTest, defineStream: defineStream, default: { defineExperience: defineExperience, defineTool: defineTool, defineTest: defineTest, defineStream: defineStream } }";
78
- const CJS_BASE_SHIMS = {
79
- import_react: "{ default: React, __esModule: true, createElement: React.createElement, Fragment: React.Fragment, useState: React.useState, useEffect: React.useEffect, useCallback: React.useCallback, useMemo: React.useMemo, useRef: React.useRef, useContext: React.useContext, useReducer: React.useReducer, createContext: React.createContext, forwardRef: React.forwardRef, memo: React.memo }",
80
- import_zod: "{ z: z, default: z }",
81
- import_yjs: "{ default: Y }",
82
- import_sdk: SDK_CORE_SHIM,
83
- import_vibevibes_sdk: SDK_CORE_SHIM,
84
- import_runtime: SDK_CORE_SHIM,
85
- import_vibevibes_runtime: SDK_CORE_SHIM,
86
- import_react_dom: "{ default: {}, __esModule: true }",
87
- import_client: "{ default: {}, __esModule: true }",
88
- // Proxy stubs for rendering libraries (server-side only — Canvas is never called)
89
- import_three: "(new Proxy({}, { get: (_, p) => typeof p === 'string' ? function(){} : undefined }))",
90
- import_fiber: "(new Proxy({}, { get: (_, p) => typeof p === 'string' ? function(){} : undefined }))",
91
- import_drei: "(new Proxy({}, { get: (_, p) => typeof p === 'string' ? function(){} : undefined }))",
92
- };
93
- /**
94
- * Inject CJS shim variables for server-side eval.
95
- */
96
- function injectCjsShims(code) {
97
- const lines = [];
98
- // Emit base shims
99
- for (const [name, value] of Object.entries(CJS_BASE_SHIMS)) {
100
- lines.push(`var ${name} = ${value};`);
101
- }
102
- // Scan for numbered variants (e.g. import_react2, import_zod3) and alias them
103
- for (const baseName of Object.keys(CJS_BASE_SHIMS)) {
104
- const pattern = new RegExp(`\\b(${baseName}(\\d+))\\b`, "g");
105
- const seen = new Set();
106
- let match;
107
- while ((match = pattern.exec(code)) !== null) {
108
- const numberedName = match[1];
109
- if (!seen.has(numberedName)) {
110
- seen.add(numberedName);
111
- lines.push(`var ${numberedName} = ${baseName};`);
112
- }
113
- }
114
- }
115
- return lines.join("\n");
116
- }
117
- /**
118
- * Format esbuild errors into actionable messages with file:line and suggestions.
119
- */
120
- function formatEsbuildError(err, target) {
121
- const buildErr = err;
122
- if (buildErr.errors && Array.isArray(buildErr.errors)) {
123
- const formatted = buildErr.errors.map((e) => {
124
- const loc = e.location
125
- ? `${e.location.file}:${e.location.line}:${e.location.column}`
126
- : "unknown location";
127
- return ` ${loc}: ${e.text}`;
128
- }).join("\n");
129
- return new Error(`Build failed (${target} bundle):\n${formatted}\n\n` +
130
- `Common fixes:\n` +
131
- `- Check for syntax errors at the indicated location\n` +
132
- `- Ensure all imports resolve to existing files in src/\n` +
133
- `- Verify @vibevibes/sdk imports match the available exports`);
134
- }
135
- return err instanceof Error ? err : new Error(String(err));
136
- }
137
- /**
138
- * Bundle for server-side tool execution (Node.js eval).
139
- * Returns the raw ExperienceModule extracted via new Function().
140
- */
141
- export async function bundleForServer(entryPath) {
142
- let result;
143
- try {
144
- result = await esbuild.build({
145
- entryPoints: [entryPath],
146
- bundle: true,
147
- format: "cjs",
148
- platform: "node",
149
- target: "es2022",
150
- write: false,
151
- external: SERVER_ONLY_EXTERNALS,
152
- jsx: "transform",
153
- jsxFactory: "React.createElement",
154
- jsxFragment: "React.Fragment",
155
- logLevel: "silent",
156
- });
157
- }
158
- catch (err) {
159
- throw formatEsbuildError(err, "server");
160
- }
161
- const outputFile = result.outputFiles?.[0];
162
- if (!outputFile)
163
- throw new Error("esbuild produced no output files for server bundle");
164
- let code = outputFile.text;
165
- code = stripExternalImports(code, SERVER_ONLY_EXTERNALS);
166
- // Strip user-code React hook destructuring (already provided by CJS shims)
167
- code = code.replace(/(?:const|let|var)\s+\{[^}]*?\b(?:useState|useEffect|useCallback|useMemo|useRef|useContext|useReducer)\b[^}]*?\}\s*=\s*(?:React|import_react\w*)\s*;/g, "/* [vibevibes] stripped duplicate React destructuring */");
168
- // Inject CJS shims for esbuild-generated variable references
169
- // Pass code so we can detect numbered variants (import_react2, etc.)
170
- code = injectCjsShims(code) + "\n" + code;
171
- // Strip esbuild's CJS annotation `0 && (module.exports = {...})` — dead code that
172
- // causes syntax errors when module.exports is replaced with var assignment.
173
- // Uses brace-depth counting to handle nested objects/functions in the annotation.
174
- code = stripCjsAnnotation(code);
175
- // Replace module.exports/export default with variable assignment
176
- code = code.replace(/module\.exports\s*=\s*/g, "var __experience_export__ = ");
177
- code = code.replace(/exports\.default(?!\w)\s*=\s*/g, "var __experience_export__ = ");
178
- return code;
179
- }
180
- /**
181
- * Evaluate a server bundle and extract the ExperienceModule.
182
- */
183
- export async function evalServerBundle(serverCode) {
184
- const sdk = await import("@vibevibes/sdk");
185
- const { defineExperience, defineTool, defineTest, defineStream } = sdk;
186
- const noop = () => null;
187
- const stubReact = {
188
- createElement: noop, Fragment: "Fragment",
189
- useState: (init) => [typeof init === "function" ? init() : init, noop],
190
- useEffect: noop, useCallback: (fn) => fn,
191
- useMemo: (fn) => fn(), useRef: (init) => ({ current: init ?? null }),
192
- useContext: noop, useReducer: noop,
193
- createContext: noop, forwardRef: noop, memo: (x) => x,
194
- };
195
- const zodModule = await import("zod");
196
- const z = zodModule.z ?? zodModule.default ?? zodModule;
197
- const fn = new Function("globalThis", "process", "global", "React", "Y", "z", "defineExperience", "defineTool", "defineTest", "defineStream", "require", "exports", "module", "console", `"use strict";\n${serverCode}\nreturn typeof __experience_export__ !== 'undefined' ? __experience_export__ : (typeof module !== 'undefined' ? module.exports : undefined);`);
198
- const fakeModule = { exports: {} };
199
- const sandboxGlobal = Object.create(null);
200
- const sandboxProcess = { env: { NODE_ENV: "production" } };
201
- const result = fn(sandboxGlobal, sandboxProcess, sandboxGlobal, stubReact, {}, z, defineExperience, defineTool, defineTest, defineStream, (id) => { throw new Error(`require('${id}') is not supported in the vibevibes server sandbox. Add '${id}' to EXTERNALS in bundler.ts.`); }, fakeModule.exports, fakeModule, console);
202
- const exports = fakeModule.exports;
203
- return result?.default ?? result ?? exports?.default ?? exports;
204
- }
205
- /**
206
- * Bundle for client-side Canvas rendering (browser).
207
- * Returns pure ESM. External imports (react, zod, etc.) are left as-is —
208
- * the viewer's import map resolves them in the browser.
209
- */
210
- export async function bundleForClient(entryPath) {
211
- let result;
212
- try {
213
- result = await esbuild.build({
214
- entryPoints: [entryPath],
215
- bundle: true,
216
- format: "esm",
217
- platform: "browser",
218
- target: "es2020",
219
- write: false,
220
- external: EXTERNALS,
221
- jsx: "transform",
222
- jsxFactory: "React.createElement",
223
- jsxFragment: "React.Fragment",
224
- logLevel: "silent",
225
- });
226
- }
227
- catch (err) {
228
- throw formatEsbuildError(err, "client");
229
- }
230
- const clientOutputFile = result.outputFiles?.[0];
231
- if (!clientOutputFile)
232
- throw new Error("esbuild produced no output files for client bundle");
233
- return clientOutputFile.text;
234
- }
235
- /**
236
- * Build both bundles from an entry file.
237
- */
238
- export async function buildExperience(entryPath) {
239
- const [serverCode, clientCode] = await Promise.all([
240
- bundleForServer(entryPath),
241
- bundleForClient(entryPath),
242
- ]);
243
- return { serverCode, clientCode };
244
- }
245
- /**
246
- * Validate a client bundle for common issues.
247
- * Lightweight — esbuild already validates syntax. This just checks the output exists.
248
- * Returns null if OK, or an error message string.
249
- */
250
- export function validateClientBundle(code) {
251
- if (!code || !code.trim())
252
- return "Client bundle is empty";
253
- return null;
254
- }
package/dist/server.d.ts DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * @vibevibes/runtime — the server engine for vibevibes experiences.
3
- *
4
- * Single-room, single-experience architecture.
5
- * AI agents join via MCP or HTTP. Humans join via browser.
6
- * Tools are the only mutation path. State is server-authoritative.
7
- */
8
- export interface ServerConfig {
9
- /** Absolute path to the experience project root (where manifest.json or src/index.tsx lives). */
10
- projectRoot: string;
11
- /** Port to listen on. Defaults to 4321 or PORT env var. */
12
- port?: number;
13
- }
14
- export declare function setPublicUrl(url: string): void;
15
- export declare function getBaseUrl(): string;
16
- export declare function startServer(config?: ServerConfig): Promise<import("http").Server>;
17
- export declare function setProjectRoot(root: string): void;