@vibevibes/sdk 0.5.0 → 0.6.0
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/dev.js +18 -0
- package/dist/bundler.d.ts +36 -0
- package/dist/bundler.js +254 -0
- package/dist/define.d.ts +35 -0
- package/dist/define.js +69 -0
- package/dist/index.d.ts +2 -181
- package/dist/index.js +2 -70
- package/dist/server.d.ts +17 -0
- package/dist/server.js +1441 -0
- package/dist/types.d.ts +143 -0
- package/dist/types.js +4 -0
- package/dist/viewer/index.html +689 -0
- package/package.json +16 -5
package/bin/dev.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Start the vibevibes dev server for an experience.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx vibevibes-dev # serves from current directory
|
|
8
|
+
* npx vibevibes-dev ./my-exp # serves from a specific path
|
|
9
|
+
* npm run dev # via package.json script
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { resolve } from "node:path";
|
|
13
|
+
import { startServer } from "../dist/server.js";
|
|
14
|
+
|
|
15
|
+
const projectRoot = resolve(process.argv[2] || ".");
|
|
16
|
+
const port = parseInt(process.env.PORT || "4321", 10);
|
|
17
|
+
|
|
18
|
+
startServer({ projectRoot, port });
|
|
@@ -0,0 +1,36 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
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/define.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { ToolDef, ToolRisk, TestDef, ExperienceModule, StreamDef, ParticipantSlot } from "./types";
|
|
3
|
+
export declare function defineTool<TInput, TOutput>(config: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
input_schema: z.ZodType<TInput>;
|
|
7
|
+
risk?: ToolRisk;
|
|
8
|
+
capabilities_required?: string[];
|
|
9
|
+
handler: ToolDef<TInput, TOutput>["handler"];
|
|
10
|
+
}): ToolDef<TInput, TOutput>;
|
|
11
|
+
export declare function defineTest(config: {
|
|
12
|
+
name: string;
|
|
13
|
+
run: TestDef["run"];
|
|
14
|
+
}): TestDef;
|
|
15
|
+
export declare function defineStream<TInput>(config: {
|
|
16
|
+
name: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
input_schema: z.ZodType<TInput>;
|
|
19
|
+
merge: (state: Record<string, any>, input: TInput, actorId: string) => Record<string, any>;
|
|
20
|
+
rateLimit?: number;
|
|
21
|
+
}): StreamDef<TInput>;
|
|
22
|
+
export declare function defineExperience(module: ExperienceModule & {
|
|
23
|
+
initialState?: Record<string, any>;
|
|
24
|
+
agents?: Array<{
|
|
25
|
+
role: string;
|
|
26
|
+
systemPrompt: string;
|
|
27
|
+
allowedTools?: string[];
|
|
28
|
+
autoSpawn?: boolean;
|
|
29
|
+
maxInstances?: number;
|
|
30
|
+
}>;
|
|
31
|
+
participants?: ParticipantSlot[];
|
|
32
|
+
name?: string;
|
|
33
|
+
}): ExperienceModule & {
|
|
34
|
+
initialState?: Record<string, any>;
|
|
35
|
+
};
|
package/dist/define.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export function defineTool(config) {
|
|
2
|
+
return {
|
|
3
|
+
name: config.name,
|
|
4
|
+
description: config.description,
|
|
5
|
+
input_schema: config.input_schema,
|
|
6
|
+
risk: config.risk ?? "low",
|
|
7
|
+
capabilities_required: config.capabilities_required ?? [],
|
|
8
|
+
handler: config.handler,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function defineTest(config) {
|
|
12
|
+
return { name: config.name, run: config.run };
|
|
13
|
+
}
|
|
14
|
+
export function defineStream(config) {
|
|
15
|
+
return {
|
|
16
|
+
name: config.name,
|
|
17
|
+
description: config.description,
|
|
18
|
+
input_schema: config.input_schema,
|
|
19
|
+
merge: config.merge,
|
|
20
|
+
rateLimit: config.rateLimit,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function defineExperience(module) {
|
|
24
|
+
const m = module.manifest ?? {};
|
|
25
|
+
let initialState = module.initialState;
|
|
26
|
+
if (module.stateSchema && !initialState) {
|
|
27
|
+
try {
|
|
28
|
+
initialState = module.stateSchema.parse(undefined);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
try {
|
|
32
|
+
initialState = module.stateSchema.parse({});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Schema has required fields with no defaults
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (module.stateSchema && initialState) {
|
|
40
|
+
try {
|
|
41
|
+
module.stateSchema.parse(initialState);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.warn(`[vibevibes] initialState does not match stateSchema: ${err instanceof Error ? err.message : err}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const rawParticipantSlots = module.participants ??
|
|
48
|
+
m.participantSlots ??
|
|
49
|
+
(module.agents || m.agentSlots)?.map((a) => ({ ...a, type: "ai" }));
|
|
50
|
+
const hasOrchestrator = rawParticipantSlots?.some((s) => s.role === "orchestrator");
|
|
51
|
+
const participantSlots = rawParticipantSlots
|
|
52
|
+
? hasOrchestrator
|
|
53
|
+
? rawParticipantSlots
|
|
54
|
+
: [...rawParticipantSlots, { role: "orchestrator", type: "ai", maxInstances: 1 }]
|
|
55
|
+
: [{ role: "orchestrator", type: "ai", maxInstances: 1 }];
|
|
56
|
+
const agentSlots = participantSlots?.filter((s) => s.type === "ai" || s.type === undefined || s.type === "any") ?? m.agentSlots ?? module.agents;
|
|
57
|
+
return {
|
|
58
|
+
...module,
|
|
59
|
+
initialState,
|
|
60
|
+
manifest: {
|
|
61
|
+
...m,
|
|
62
|
+
title: m.title || module.name || m.id,
|
|
63
|
+
version: m.version || "0.0.1",
|
|
64
|
+
requested_capabilities: m.requested_capabilities || ["state.write"],
|
|
65
|
+
participantSlots: participantSlots ?? m.participantSlots,
|
|
66
|
+
agentSlots: agentSlots ?? m.agentSlots,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,181 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Experience SDK Types
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
type ToolRisk = "low" | "medium" | "high";
|
|
9
|
-
type CallToolFn = (name: string, input: Record<string, unknown>) => Promise<unknown>;
|
|
10
|
-
type ZodFactory = typeof z;
|
|
11
|
-
type ToolEvent = {
|
|
12
|
-
id: string;
|
|
13
|
-
ts: number;
|
|
14
|
-
actorId: string;
|
|
15
|
-
owner?: string;
|
|
16
|
-
tool: string;
|
|
17
|
-
input: Record<string, unknown>;
|
|
18
|
-
output?: unknown;
|
|
19
|
-
error?: string;
|
|
20
|
-
};
|
|
21
|
-
type AgentSlot = {
|
|
22
|
-
role: string;
|
|
23
|
-
systemPrompt: string;
|
|
24
|
-
allowedTools?: string[];
|
|
25
|
-
autoSpawn?: boolean;
|
|
26
|
-
maxInstances?: number;
|
|
27
|
-
};
|
|
28
|
-
type ParticipantSlot = {
|
|
29
|
-
role: string;
|
|
30
|
-
type?: "human" | "ai" | "any";
|
|
31
|
-
systemPrompt?: string;
|
|
32
|
-
allowedTools?: string[];
|
|
33
|
-
autoSpawn?: boolean;
|
|
34
|
-
maxInstances?: number;
|
|
35
|
-
};
|
|
36
|
-
type ParticipantDetail = {
|
|
37
|
-
actorId: string;
|
|
38
|
-
type: "human" | "ai" | "unknown";
|
|
39
|
-
role?: string;
|
|
40
|
-
metadata?: Record<string, string>;
|
|
41
|
-
};
|
|
42
|
-
type ExperienceManifest = {
|
|
43
|
-
id: string;
|
|
44
|
-
version: string;
|
|
45
|
-
title: string;
|
|
46
|
-
description: string;
|
|
47
|
-
requested_capabilities: string[];
|
|
48
|
-
agentSlots?: AgentSlot[];
|
|
49
|
-
participantSlots?: ParticipantSlot[];
|
|
50
|
-
category?: string;
|
|
51
|
-
tags?: string[];
|
|
52
|
-
};
|
|
53
|
-
type StreamDef<TInput = any> = {
|
|
54
|
-
name: string;
|
|
55
|
-
description?: string;
|
|
56
|
-
input_schema: z.ZodTypeAny;
|
|
57
|
-
merge: (state: Record<string, any>, input: TInput, actorId: string) => Record<string, any>;
|
|
58
|
-
rateLimit?: number;
|
|
59
|
-
};
|
|
60
|
-
type ToolCtx<TState extends Record<string, any> = Record<string, any>> = {
|
|
61
|
-
roomId: string;
|
|
62
|
-
actorId: string;
|
|
63
|
-
owner?: string;
|
|
64
|
-
state: TState;
|
|
65
|
-
setState: (newState: TState) => void;
|
|
66
|
-
timestamp: number;
|
|
67
|
-
memory: Record<string, any>;
|
|
68
|
-
setMemory: (updates: Record<string, any>) => void;
|
|
69
|
-
};
|
|
70
|
-
type ToolDef<TInput = any, TOutput = any> = {
|
|
71
|
-
name: string;
|
|
72
|
-
description: string;
|
|
73
|
-
input_schema: z.ZodTypeAny;
|
|
74
|
-
risk: ToolRisk;
|
|
75
|
-
capabilities_required: string[];
|
|
76
|
-
handler: (ctx: ToolCtx, input: TInput) => Promise<TOutput>;
|
|
77
|
-
emits?: string[];
|
|
78
|
-
on?: Record<string, (ctx: ToolCtx, event: ToolEvent) => Promise<void>>;
|
|
79
|
-
persist?: boolean;
|
|
80
|
-
};
|
|
81
|
-
type CanvasProps<TState extends Record<string, any> = Record<string, any>> = {
|
|
82
|
-
actorId: string;
|
|
83
|
-
sharedState: TState;
|
|
84
|
-
callTool: (name: string, input: Record<string, unknown>, predictFn?: (state: TState) => TState) => Promise<unknown>;
|
|
85
|
-
callTools?: (calls: Array<{
|
|
86
|
-
name: string;
|
|
87
|
-
input: Record<string, unknown>;
|
|
88
|
-
}>) => Promise<unknown[]>;
|
|
89
|
-
ephemeralState: Record<string, Record<string, any>>;
|
|
90
|
-
setEphemeral: (data: Record<string, any>) => void;
|
|
91
|
-
stream?: (name: string, input: Record<string, unknown>) => void;
|
|
92
|
-
participants: string[];
|
|
93
|
-
participantDetails?: ParticipantDetail[];
|
|
94
|
-
role?: "spectator" | "player";
|
|
95
|
-
};
|
|
96
|
-
type ExpectChain<T> = {
|
|
97
|
-
toBe: (expected: T) => void;
|
|
98
|
-
toEqual: (expected: unknown) => void;
|
|
99
|
-
toBeTruthy: () => void;
|
|
100
|
-
toBeFalsy: () => void;
|
|
101
|
-
toContain: (item: unknown) => void;
|
|
102
|
-
toHaveProperty: (key: string, value?: unknown) => void;
|
|
103
|
-
toBeGreaterThan: (expected: number) => void;
|
|
104
|
-
toBeLessThan: (expected: number) => void;
|
|
105
|
-
not: ExpectChain<T>;
|
|
106
|
-
};
|
|
107
|
-
type TestHelpers = {
|
|
108
|
-
tool: (name: string) => ToolDef;
|
|
109
|
-
ctx: (opts?: {
|
|
110
|
-
state?: Record<string, any>;
|
|
111
|
-
actorId?: string;
|
|
112
|
-
roomId?: string;
|
|
113
|
-
owner?: string;
|
|
114
|
-
}) => ToolCtx & {
|
|
115
|
-
getState: () => Record<string, any>;
|
|
116
|
-
};
|
|
117
|
-
expect: <T>(actual: T) => ExpectChain<T>;
|
|
118
|
-
snapshot: (label: string, value: unknown) => void;
|
|
119
|
-
observe: (state: Record<string, any>, actorId?: string) => Record<string, any>;
|
|
120
|
-
agentSlots: () => Array<{
|
|
121
|
-
role: string;
|
|
122
|
-
systemPrompt?: string;
|
|
123
|
-
allowedTools?: string[];
|
|
124
|
-
[k: string]: unknown;
|
|
125
|
-
}>;
|
|
126
|
-
};
|
|
127
|
-
type TestDef = {
|
|
128
|
-
name: string;
|
|
129
|
-
run: (helpers: TestHelpers) => Promise<void>;
|
|
130
|
-
};
|
|
131
|
-
type RegistryEntry = {
|
|
132
|
-
path: string;
|
|
133
|
-
};
|
|
134
|
-
type ExperienceRegistry = {
|
|
135
|
-
experiences: Record<string, RegistryEntry>;
|
|
136
|
-
};
|
|
137
|
-
type ExperienceModule = {
|
|
138
|
-
manifest: ExperienceManifest;
|
|
139
|
-
Canvas: React.FC<CanvasProps>;
|
|
140
|
-
tools: ToolDef[];
|
|
141
|
-
tests?: TestDef[];
|
|
142
|
-
stateSchema?: z.ZodTypeAny;
|
|
143
|
-
streams?: StreamDef[];
|
|
144
|
-
observe?: (state: Record<string, any>, event: ToolEvent | null, actorId: string) => Record<string, any>;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
declare function defineTool<TInput, TOutput>(config: {
|
|
148
|
-
name: string;
|
|
149
|
-
description: string;
|
|
150
|
-
input_schema: z.ZodType<TInput>;
|
|
151
|
-
risk?: ToolRisk;
|
|
152
|
-
capabilities_required?: string[];
|
|
153
|
-
handler: ToolDef<TInput, TOutput>["handler"];
|
|
154
|
-
}): ToolDef<TInput, TOutput>;
|
|
155
|
-
declare function defineTest(config: {
|
|
156
|
-
name: string;
|
|
157
|
-
run: TestDef["run"];
|
|
158
|
-
}): TestDef;
|
|
159
|
-
declare function defineStream<TInput>(config: {
|
|
160
|
-
name: string;
|
|
161
|
-
description?: string;
|
|
162
|
-
input_schema: z.ZodType<TInput>;
|
|
163
|
-
merge: (state: Record<string, any>, input: TInput, actorId: string) => Record<string, any>;
|
|
164
|
-
rateLimit?: number;
|
|
165
|
-
}): StreamDef<TInput>;
|
|
166
|
-
declare function defineExperience(module: ExperienceModule & {
|
|
167
|
-
initialState?: Record<string, any>;
|
|
168
|
-
agents?: Array<{
|
|
169
|
-
role: string;
|
|
170
|
-
systemPrompt: string;
|
|
171
|
-
allowedTools?: string[];
|
|
172
|
-
autoSpawn?: boolean;
|
|
173
|
-
maxInstances?: number;
|
|
174
|
-
}>;
|
|
175
|
-
participants?: ParticipantSlot[];
|
|
176
|
-
name?: string;
|
|
177
|
-
}): ExperienceModule & {
|
|
178
|
-
initialState?: Record<string, any>;
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
export { type AgentSlot, type CallToolFn, type CanvasProps, type ExpectChain, type ExperienceManifest, type ExperienceModule, type ExperienceRegistry, type ParticipantDetail, type ParticipantSlot, type RegistryEntry, type StreamDef, type TestDef, type TestHelpers, type ToolCtx, type ToolDef, type ToolEvent, type ToolRisk, type ZodFactory, defineExperience, defineStream, defineTest, defineTool };
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export * from "./define";
|
package/dist/index.js
CHANGED
|
@@ -1,70 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return {
|
|
4
|
-
name: config.name,
|
|
5
|
-
description: config.description,
|
|
6
|
-
input_schema: config.input_schema,
|
|
7
|
-
risk: config.risk ?? "low",
|
|
8
|
-
capabilities_required: config.capabilities_required ?? [],
|
|
9
|
-
handler: config.handler
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
function defineTest(config) {
|
|
13
|
-
return { name: config.name, run: config.run };
|
|
14
|
-
}
|
|
15
|
-
function defineStream(config) {
|
|
16
|
-
return {
|
|
17
|
-
name: config.name,
|
|
18
|
-
description: config.description,
|
|
19
|
-
input_schema: config.input_schema,
|
|
20
|
-
merge: config.merge,
|
|
21
|
-
rateLimit: config.rateLimit
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function defineExperience(module) {
|
|
25
|
-
const m = module.manifest ?? {};
|
|
26
|
-
let initialState = module.initialState;
|
|
27
|
-
if (module.stateSchema && !initialState) {
|
|
28
|
-
try {
|
|
29
|
-
initialState = module.stateSchema.parse(void 0);
|
|
30
|
-
} catch {
|
|
31
|
-
try {
|
|
32
|
-
initialState = module.stateSchema.parse({});
|
|
33
|
-
} catch {
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (module.stateSchema && initialState) {
|
|
38
|
-
try {
|
|
39
|
-
module.stateSchema.parse(initialState);
|
|
40
|
-
} catch (err) {
|
|
41
|
-
console.warn(
|
|
42
|
-
`[vibevibes] initialState does not match stateSchema: ${err instanceof Error ? err.message : err}`
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const rawParticipantSlots = module.participants ?? m.participantSlots ?? (module.agents || m.agentSlots)?.map((a) => ({ ...a, type: "ai" }));
|
|
47
|
-
const hasOrchestrator = rawParticipantSlots?.some((s) => s.role === "orchestrator");
|
|
48
|
-
const participantSlots = rawParticipantSlots ? hasOrchestrator ? rawParticipantSlots : [...rawParticipantSlots, { role: "orchestrator", type: "ai", maxInstances: 1 }] : [{ role: "orchestrator", type: "ai", maxInstances: 1 }];
|
|
49
|
-
const agentSlots = participantSlots?.filter(
|
|
50
|
-
(s) => s.type === "ai" || s.type === void 0 || s.type === "any"
|
|
51
|
-
) ?? m.agentSlots ?? module.agents;
|
|
52
|
-
return {
|
|
53
|
-
...module,
|
|
54
|
-
initialState,
|
|
55
|
-
manifest: {
|
|
56
|
-
...m,
|
|
57
|
-
title: m.title || module.name || m.id,
|
|
58
|
-
version: m.version || "0.0.1",
|
|
59
|
-
requested_capabilities: m.requested_capabilities || ["state.write"],
|
|
60
|
-
participantSlots: participantSlots ?? m.participantSlots,
|
|
61
|
-
agentSlots: agentSlots ?? m.agentSlots
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
export {
|
|
66
|
-
defineExperience,
|
|
67
|
-
defineStream,
|
|
68
|
-
defineTest,
|
|
69
|
-
defineTool
|
|
70
|
-
};
|
|
1
|
+
export * from "./types";
|
|
2
|
+
export * from "./define";
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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;
|