@amirhosseinnateghi/vibed-mcp 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +111 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10335,13 +10335,19 @@ var turnAttachmentSchema = external_exports.object({
|
|
|
10335
10335
|
// NUL bytes break Postgres jsonb (and mean binary-not-text) — strip defensively.
|
|
10336
10336
|
text: external_exports.string().max(5e4).transform((t) => t.replace(/\u0000/g, "")).optional()
|
|
10337
10337
|
});
|
|
10338
|
+
var voiceInputSchema = external_exports.object({
|
|
10339
|
+
key: external_exports.string().min(1).max(300),
|
|
10340
|
+
mime: external_exports.string().max(100).default("audio/webm")
|
|
10341
|
+
});
|
|
10338
10342
|
var createTurnRequestSchema = external_exports.object({
|
|
10339
10343
|
clientTurnId: external_exports.string().uuid(),
|
|
10340
10344
|
content: external_exports.string().max(4e3).default(""),
|
|
10341
10345
|
attachments: external_exports.array(turnAttachmentSchema).max(6).optional(),
|
|
10346
|
+
// A voice turn carries no text yet — the worker transcribes `voice` first (م۷).
|
|
10347
|
+
voice: voiceInputSchema.optional(),
|
|
10342
10348
|
model: external_exports.string().max(100).optional()
|
|
10343
|
-
}).refine((v) => v.content.trim().length > 0 || (v.attachments?.length ?? 0) > 0, {
|
|
10344
|
-
message: "Send a message or
|
|
10349
|
+
}).refine((v) => v.content.trim().length > 0 || (v.attachments?.length ?? 0) > 0 || !!v.voice, {
|
|
10350
|
+
message: "Send a message, an attachment, or a voice recording."
|
|
10345
10351
|
});
|
|
10346
10352
|
var builderAttachmentSchema = external_exports.object({
|
|
10347
10353
|
kind: external_exports.enum(["image", "file", "audio"]),
|
|
@@ -10475,6 +10481,13 @@ var buildEventSchema = external_exports.discriminatedUnion("type", [
|
|
|
10475
10481
|
}),
|
|
10476
10482
|
/** Friendly status chip ("index.html", "Fixing a couple of things…"). */
|
|
10477
10483
|
external_exports.object({ ...base, type: external_exports.literal("status"), summary: external_exports.string() }),
|
|
10484
|
+
/**
|
|
10485
|
+
* The user's spoken words, transcribed server-side (م۷). A voice turn starts
|
|
10486
|
+
* with empty `userText` and a "🎤 Transcribing…" bubble; this event fills the
|
|
10487
|
+
* user bubble with the transcript the moment the worker finishes transcribing,
|
|
10488
|
+
* before the build's prose begins.
|
|
10489
|
+
*/
|
|
10490
|
+
external_exports.object({ ...base, type: external_exports.literal("transcript"), text: external_exports.string() }),
|
|
10478
10491
|
/** First-message category classification. */
|
|
10479
10492
|
external_exports.object({ ...base, type: external_exports.literal("category"), category: external_exports.string() }),
|
|
10480
10493
|
/** The validated draft landed. Preview loads it from the draft URL. */
|
|
@@ -11178,9 +11191,94 @@ function formatReport(result) {
|
|
|
11178
11191
|
out.push(` \u2022 \u2026and ${result.inlineWarnings.length - 12} more`);
|
|
11179
11192
|
}
|
|
11180
11193
|
}
|
|
11194
|
+
const usesBrowserStorage = [...result.warnings.map((w) => w.message), ...result.inlineWarnings].some(
|
|
11195
|
+
(m) => /BROWSER_STORAGE|localStorage|sessionStorage|indexedDB/i.test(m)
|
|
11196
|
+
);
|
|
11197
|
+
if (usesBrowserStorage) {
|
|
11198
|
+
out.push(
|
|
11199
|
+
"",
|
|
11200
|
+
"\u2139 Uses browser storage (blocked in the sandbox). Port it to `window.vibed.storage` \u2014 run `vibed storage` (or the vibed_storage_guide MCP tool) for the local + shared SDK."
|
|
11201
|
+
);
|
|
11202
|
+
}
|
|
11181
11203
|
return out.join("\n");
|
|
11182
11204
|
}
|
|
11183
11205
|
|
|
11206
|
+
// ../cli/src/storageGuide.ts
|
|
11207
|
+
var STORAGE_GUIDE = `# vibed storage \u2014 add persistence to a vibe (\`window.vibed.storage\`)
|
|
11208
|
+
|
|
11209
|
+
A vibe is ONE static sandboxed HTML file with no backend. \`localStorage\`,
|
|
11210
|
+
\`sessionStorage\`, \`indexedDB\`, and cookies are BLOCKED \u2014 they throw in the
|
|
11211
|
+
sandbox (\`vibed check\` warns \`BROWSER_STORAGE\`). For anything you'd persist,
|
|
11212
|
+
use the injected \`window.vibed.storage\` SDK instead. The platform is the
|
|
11213
|
+
backend; you write zero server code.
|
|
11214
|
+
|
|
11215
|
+
## Two rules that apply to EVERY call
|
|
11216
|
+
1. Every call returns a Promise that can reject \u2014 always guard it. When the vibe
|
|
11217
|
+
runs OUTSIDE vibed (e.g. a local file, your \`vibed draft\`/\`preview\`), calls
|
|
11218
|
+
reject with \`{ code: "no_host" }\`. The vibe must stay playable standalone, so
|
|
11219
|
+
treat missing storage as "no saved data yet", never a crash.
|
|
11220
|
+
2. WRITES require the viewer to be signed in. If not, they reject with
|
|
11221
|
+
\`{ code: "unauthenticated" }\` \u2014 catch it and show a gentle "sign in to save"
|
|
11222
|
+
nudge. READS of shared data work for everyone.
|
|
11223
|
+
|
|
11224
|
+
Publishing auto-detects SDK usage and turns storage on for the post \u2014 no flags.
|
|
11225
|
+
|
|
11226
|
+
## Tier 1 \u2014 \`vibed.storage.local\` (LOCAL: private, per-viewer, per-post)
|
|
11227
|
+
Each viewer gets their own private bucket for THIS post. Nobody else can read it.
|
|
11228
|
+
Use for: this player's high score, their settings, "resume where I left off".
|
|
11229
|
+
\`\`\`js
|
|
11230
|
+
await vibed.storage.local.set("best", 8200);
|
|
11231
|
+
const best = await vibed.storage.local.get("best"); // null if never set
|
|
11232
|
+
await vibed.storage.local.delete("best");
|
|
11233
|
+
\`\`\`
|
|
11234
|
+
|
|
11235
|
+
## Tier 2 \u2014 \`vibed.storage.shared\` (GLOBAL: one collective store for the whole post)
|
|
11236
|
+
Data every viewer of the post shares \u2014 leaderboards, votes, guestbooks, shared
|
|
11237
|
+
state. Organized into named "collections" (like tables) you invent.
|
|
11238
|
+
\`\`\`js
|
|
11239
|
+
// key/value doc with optimistic concurrency
|
|
11240
|
+
await vibed.storage.shared.set("state", "doc", { phase: "open" }); // \u2192 { value, version, ... }
|
|
11241
|
+
await vibed.storage.shared.set("state", "doc", next, { ifVersion: 3 }); // rejects { code: "conflict" }
|
|
11242
|
+
const doc = await vibed.storage.shared.get("state", "doc"); // null if missing
|
|
11243
|
+
await vibed.storage.shared.delete("state", "doc");
|
|
11244
|
+
|
|
11245
|
+
// append-only list + query (guestbook, bets, submissions)
|
|
11246
|
+
await vibed.storage.shared.append("bets", { pick: "Argentina", stake: 50 });
|
|
11247
|
+
const mine = await vibed.storage.shared.query("bets", { mine: true });
|
|
11248
|
+
const feed = await vibed.storage.shared.query("bets", { sort: "-created", limit: 30 });
|
|
11249
|
+
|
|
11250
|
+
// counter (poll / reactions)
|
|
11251
|
+
const { num } = await vibed.storage.shared.increment("votes", "argentina", 1);
|
|
11252
|
+
|
|
11253
|
+
// leaderboard: submit a score (keep the best), read the top, get MY rank
|
|
11254
|
+
await vibed.storage.shared.submit("leaderboard", { score, keep: "max", meta: { emoji: "\u{1F427}" } });
|
|
11255
|
+
const top = await vibed.storage.shared.query("leaderboard", { sort: "-num", limit: 10 });
|
|
11256
|
+
const rank = await vibed.storage.shared.rank("leaderboard"); // { rank, of, score } | null
|
|
11257
|
+
|
|
11258
|
+
// live updates (polling now): re-renders when the collection changes; returns an unsubscribe fn
|
|
11259
|
+
const off = vibed.storage.shared.subscribe("leaderboard", (r) => render(r.rows), { intervalMs: 4000 });
|
|
11260
|
+
\`\`\`
|
|
11261
|
+
|
|
11262
|
+
## Who is watching
|
|
11263
|
+
\`\`\`js
|
|
11264
|
+
const me = await vibed.storage.identity(); // { id, signedIn, name? } \u2014 stable per viewer; identify entries
|
|
11265
|
+
const m = await vibed.storage.meta(); // { postId, ... } \u2014 this post's context
|
|
11266
|
+
\`\`\`
|
|
11267
|
+
|
|
11268
|
+
## Limits (free tier \u2014 design within these)
|
|
11269
|
+
- Each value must be JSON-serializable and under the per-value byte cap
|
|
11270
|
+
(rejects \`{ code: "too_large" }\`); \`invalid\` if it can't be JSON-stringified.
|
|
11271
|
+
- shared collections are for structured game/app state, NOT open chat/DM/messaging.
|
|
11272
|
+
|
|
11273
|
+
## Porting a project that used browser storage (the \`BROWSER_STORAGE\` warning)
|
|
11274
|
+
1. Find every \`localStorage\`/\`sessionStorage\`/\`indexedDB\`/cookie use.
|
|
11275
|
+
2. Per-viewer state (settings, progress, personal best) \u2192 \`vibed.storage.local\`.
|
|
11276
|
+
3. Anything others should see (scores to compare, shared counters, submissions)
|
|
11277
|
+
\u2192 the matching \`vibed.storage.shared\` primitive above.
|
|
11278
|
+
4. Make every call \`await\` + \`try/catch\`, with a standalone fallback (no_host).
|
|
11279
|
+
5. Re-run \`vibed check\` \u2014 the \`BROWSER_STORAGE\` warning should be gone.
|
|
11280
|
+
`;
|
|
11281
|
+
|
|
11184
11282
|
// ../cli/src/login.ts
|
|
11185
11283
|
import { spawn } from "node:child_process";
|
|
11186
11284
|
import { platform } from "node:os";
|
|
@@ -11232,6 +11330,7 @@ import { homedir } from "node:os";
|
|
|
11232
11330
|
import { join as join2 } from "node:path";
|
|
11233
11331
|
import { mkdir, readFile as readFile2, writeFile, chmod } from "node:fs/promises";
|
|
11234
11332
|
var DEFAULT_API = "https://vibed.city";
|
|
11333
|
+
var LEGACY_API_DEFAULTS = /* @__PURE__ */ new Set(["https://web-production-834c9.up.railway.app"]);
|
|
11235
11334
|
var dir = () => join2(homedir(), ".vibed");
|
|
11236
11335
|
var file = () => join2(dir(), "config.json");
|
|
11237
11336
|
async function readFileConfig() {
|
|
@@ -11243,7 +11342,8 @@ async function readFileConfig() {
|
|
|
11243
11342
|
}
|
|
11244
11343
|
async function loadConfig(overrides = {}) {
|
|
11245
11344
|
const fromFile = await readFileConfig();
|
|
11246
|
-
|
|
11345
|
+
let apiBase = (overrides.api || process.env.VIBED_API || fromFile.apiBase || DEFAULT_API).replace(/\/$/, "");
|
|
11346
|
+
if (LEGACY_API_DEFAULTS.has(apiBase)) apiBase = DEFAULT_API;
|
|
11247
11347
|
const token = process.env.VIBED_TOKEN || fromFile.token;
|
|
11248
11348
|
return { apiBase, token };
|
|
11249
11349
|
}
|
|
@@ -11371,16 +11471,22 @@ async function deleteExperience(client, idOrUrl) {
|
|
|
11371
11471
|
}
|
|
11372
11472
|
|
|
11373
11473
|
// src/index.ts
|
|
11374
|
-
var SERVER_INFO = { name: "vibed", version: "0.1.
|
|
11474
|
+
var SERVER_INFO = { name: "vibed", version: "0.1.7" };
|
|
11375
11475
|
var PROTOCOL_VERSION = "2024-11-05";
|
|
11376
11476
|
var CATEGORIES2 = ["Game", "Invitation", "Story", "News", "Quiz", "Tool", "Art", "Other"];
|
|
11377
11477
|
var pendingLogin = null;
|
|
11378
11478
|
var str = (v, d = "") => typeof v === "string" ? v : d;
|
|
11379
11479
|
var bool = (v, d) => typeof v === "boolean" ? v : d;
|
|
11380
11480
|
var TOOLS = [
|
|
11481
|
+
{
|
|
11482
|
+
name: "vibed_storage_guide",
|
|
11483
|
+
description: "How to add PERSISTENCE to a vibe: leaderboards, votes/polls, saved progress/high scores, guestbooks, or any shared state. A vibe is one static sandboxed file \u2014 localStorage/sessionStorage/indexedDB/cookies and backend calls are BLOCKED \u2014 so use the injected window.vibed.storage SDK instead. Returns the full primer for both tiers: `local` (private, per-viewer) and `shared` (collective, per-post). Call this BEFORE writing any save/leaderboard/multiplayer feature, or when vibed_check warns BROWSER_STORAGE.",
|
|
11484
|
+
inputSchema: { type: "object", properties: {} },
|
|
11485
|
+
run: async () => STORAGE_GUIDE
|
|
11486
|
+
},
|
|
11381
11487
|
{
|
|
11382
11488
|
name: "vibed_check",
|
|
11383
|
-
description: "Bundle the project into a single HTML file and validate it against vibed's sandbox rules (no network/auth). Returns whether it's publishable and, if not, the blockers to fix. Run this before vibed_publish.",
|
|
11489
|
+
description: "Bundle the project into a single HTML file and validate it against vibed's sandbox rules (no network/auth). Returns whether it's publishable and, if not, the blockers to fix. Run this before vibed_publish. If it warns BROWSER_STORAGE (localStorage etc. throw in the sandbox), call vibed_storage_guide and port to window.vibed.storage.",
|
|
11384
11490
|
inputSchema: {
|
|
11385
11491
|
type: "object",
|
|
11386
11492
|
properties: {
|
package/package.json
CHANGED