@okostream/mcp 0.12.3 → 0.12.4

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 (2) hide show
  1. package/dist/server.js +54 -8
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -116223,7 +116223,7 @@ function sanitizeScopes(scopes) {
116223
116223
  }
116224
116224
 
116225
116225
  // build/version.js
116226
- var OKO_MCP_VERSION = "0.12.3";
116226
+ var OKO_MCP_VERSION = "0.12.4";
116227
116227
 
116228
116228
  // build/auth.js
116229
116229
  var state = null;
@@ -116518,6 +116518,11 @@ async function readEvent(eventId, uid, mode = "read") {
116518
116518
 
116519
116519
  // build/tools/imagePipeline.js
116520
116520
  var IMAGE_KINDS = ["promoBanner", "videoPlaceholder", "card"];
116521
+ var IMAGE_ADVICE = {
116522
+ promoBanner: "Banner advice: a wide landscape image at least 1600 px wide (3:1 to 5:1 works best, for example 1600\xD7400); keep text inside the middle 80% so it survives mobile scaling; JPEG/PNG/WebP/AVIF up to 15 MB, stored as WebP with 320/800/1600 px variants.",
116523
+ videoPlaceholder: "Placeholder advice: it covers the 16:9 video slot, so use a 16:9 image at least 1600\xD7900 px; avoid small text; JPEG/PNG/WebP/AVIF up to 15 MB, stored as WebP with 320/800/1600 px variants.",
116524
+ card: "Card advice: match the cardImageRatio chosen in oko_configure_cards (1:1 is the safest), at least 800 px on the short side; JPEG/PNG/WebP/AVIF up to 15 MB, stored as WebP with 320/800/1600 px variants."
116525
+ };
116521
116526
  var IMAGE_VARIANT_NAMES = ["thumb_320.webp", "card_800.webp", "hero_1600.webp"];
116522
116527
  var CARD_IMAGE_RATIOS = ["auto", "1:1", "4:3", "3:2", "16:9", "2:3", "3:4"];
116523
116528
  var CARD_ID_PATTERN = /^[A-Za-z0-9_-]{1,80}$/;
@@ -117004,6 +117009,16 @@ async function uploadEventImageForUser(uid, eventId, kind, cardId, source) {
117004
117009
  const previous = readImageRef(event, kind, cardId);
117005
117010
  const sourceBuffer = await readImageSource(source);
117006
117011
  const remoteNotes = takeRemoteFetchNotes();
117012
+ const eventBlocks = event.blocks && typeof event.blocks === "object" ? event.blocks : {};
117013
+ const placeholderCfg = eventBlocks.video?.placeholder && typeof eventBlocks.video.placeholder === "object" ? eventBlocks.video.placeholder : {};
117014
+ const blockEnabled = kind === "promoBanner" ? eventBlocks.promoBanner?.enabled === true : kind === "videoPlaceholder" ? placeholderCfg.enabled === true : readCardsConfig(event).enabled;
117015
+ const enableInstruction = kind === "promoBanner" ? "oko_configure_blocks promoBanner.enabled=true" : kind === "videoPlaceholder" ? "oko_configure_blocks videoPlaceholder.enabled=true" : "oko_configure_cards enabled=true";
117016
+ const uploadHints = [
117017
+ blockEnabled ? `The ${kind} block is enabled: the new image appears on the page as soon as the variants are ready.` : `The ${kind} block is disabled in setup, so viewers will not see this image until it is enabled (${enableInstruction}). Uploading never enables a block by itself.`,
117018
+ ...kind === "videoPlaceholder" && placeholderCfg.mode !== "image" ? ['The placeholder mode is not "image": set oko_configure_blocks videoPlaceholder.mode="image" for this picture to be used.'] : [],
117019
+ ...kind === "videoPlaceholder" ? ['The placeholder is shown to viewers only while its live switch is on: oko_set_block_visibility block "placeholder" visible=true.'] : [],
117020
+ IMAGE_ADVICE[kind]
117021
+ ];
117007
117022
  const previousMasterPath = storagePathFromDownloadUrl(previous.imageMasterUrl);
117008
117023
  const deleteWarnings = [];
117009
117024
  let deletesAttempted = 0;
@@ -117029,7 +117044,7 @@ async function uploadEventImageForUser(uid, eventId, kind, cardId, source) {
117029
117044
  note: "Image master uploaded. CF generateImageVariants should publish thumb/card/hero variants and update imageUrl/imageVariants in about 10-30 seconds.",
117030
117045
  storageDeletesAttempted: deletesAttempted,
117031
117046
  storageDeleteWarnings: deleteWarnings,
117032
- ...remoteNotes.length ? { hints: remoteNotes } : {}
117047
+ hints: [...remoteNotes, ...uploadHints]
117033
117048
  };
117034
117049
  }
117035
117050
 
@@ -118086,6 +118101,8 @@ function validateEventSetup(eventId, event) {
118086
118101
  } else if (safeString(promo.imageMasterUrl).trim() && !readImageVariants(promo.imageVariants)) {
118087
118102
  add(warnings, "promo_variants_pending", "blocks.promoBanner.imageVariants", "Promo banner image variants are not ready yet.");
118088
118103
  }
118104
+ } else if (safeString(promo.imageUrl).trim() || safeString(promo.imageMasterUrl).trim()) {
118105
+ add(suggestions, "promo_disabled_with_image", "blocks.promoBanner.enabled", 'Promo banner has an uploaded image but is disabled in setup, so viewers never see it. Enable it with oko_configure_blocks promoBanner.enabled=true; to hide it only during the live show, keep it enabled and use oko_set_block_visibility block "banner" visible=false.');
118089
118106
  }
118090
118107
  const cta = asRecord(blocks.primaryCta);
118091
118108
  if (cta.enabled === true) {
@@ -118108,6 +118125,9 @@ function validateEventSetup(eventId, event) {
118108
118125
  add(warnings, "placeholder_variants_pending", "blocks.video.placeholder.imageVariants", "Video placeholder image variants are not ready yet.");
118109
118126
  }
118110
118127
  }
118128
+ if (videoPlaceholder.enabled === true) {
118129
+ add(suggestions, "placeholder_needs_live_switch", "blocks.video.placeholder", 'The video placeholder is shown to viewers only while its live switch is on: call oko_set_block_visibility block "placeholder" visible=true before the start and visible=false (or null) once the stream is playing.');
118130
+ }
118111
118131
  const cards = readCardsConfig(event);
118112
118132
  cards.repairedIdPositions.forEach((position) => {
118113
118133
  add(errors, "card_id_missing", `blocks.cards.items[${position}].id`, "Card has no usable id in Firestore; its image cannot be matched and will be dropped on the next update.");
@@ -118410,7 +118430,8 @@ function registerEventTools(server2) {
118410
118430
  notes: [
118411
118431
  "A block toggle and its image are independent: enabling a block here works with an image already uploaded via oko_upload_image, and uploading an image never enables the block by itself.",
118412
118432
  "promoBanner has no text field by design: the banner is image+link. blocks.promoBanner.text seen in event documents is legacy and is never rendered on the event page.",
118413
- 'videoPlaceholder.enabled only allows the placeholder; viewers see it after oko_set_block_visibility with block "placeholder" and visible true (a live override, stored outside the event document). Chat, CTA, banner and cards appear as soon as they are enabled here.'
118433
+ 'videoPlaceholder.enabled only allows the placeholder; viewers see it after oko_set_block_visibility with block "placeholder" and visible true (a live override, stored outside the event document). Chat, CTA, banner and cards appear as soon as they are enabled here.',
118434
+ "Setup toggle vs live override: enabled=false removes a block from the page for everyone and persists (its uploaded image stays); oko_set_block_visibility hides or shows an enabled block temporarily and is the tool for the live show. Uploading an image never enables a block."
118414
118435
  ]
118415
118436
  }),
118416
118437
  inputSchema: {
@@ -118498,6 +118519,17 @@ function registerEventTools(server2) {
118498
118519
  }
118499
118520
  await updateDoc(doc(firestore, "events", args.eventId), patch);
118500
118521
  const hints = [];
118522
+ const currentBlocks = current.blocks && typeof current.blocks === "object" ? current.blocks : {};
118523
+ const bannerHasImage = Boolean(safeString(currentBlocks.promoBanner?.imageUrl) || safeString(currentBlocks.promoBanner?.imageMasterUrl));
118524
+ if (args.promoBanner?.enabled === false && bannerHasImage) {
118525
+ hints.push('The promo banner is now disabled in setup: it disappears from the page for everyone, while its uploaded image stays in place. If the goal was to hide it only during the live show and bring it back with one call, re-enable it here and use oko_set_block_visibility block "banner" visible=false instead.');
118526
+ }
118527
+ if (args.promoBanner?.enabled === true && !bannerHasImage) {
118528
+ hints.push(`The promo banner is enabled but has no image yet: upload one with oko_upload_image kind "promoBanner". ${IMAGE_ADVICE.promoBanner}`);
118529
+ }
118530
+ if (args.chat?.enabled !== void 0 || args.promoBanner?.enabled !== void 0 || args.primaryCta?.enabled !== void 0 || args.videoPlaceholder?.enabled !== void 0) {
118531
+ hints.push("Setup toggles (enabled) decide whether a block exists on the page and persist; live overrides (oko_set_block_visibility) show or hide an enabled block temporarily during the show. Uploading an image never enables a block.");
118532
+ }
118501
118533
  if (args.videoPlaceholder?.enabled === true) {
118502
118534
  hints.push('The video placeholder is enabled but not yet visible to viewers: call oko_set_block_visibility with block "placeholder" and visible true (confirm true) to show it. It is a live override stored outside the event document.');
118503
118535
  }
@@ -118623,7 +118655,11 @@ function registerImageTools(server2) {
118623
118655
  "Uploading an image does not enable its block: toggle the block independently via oko_configure_blocks, in either order.",
118624
118656
  "The MCP server reads local paths on the organizer machine.",
118625
118657
  "Remote URLs must be public HTTPS images, max 15MB; private/local hosts are blocked.",
118626
- "For card images, imageId is the cardId so OKO CF4 can update the correct item."
118658
+ "For card images, imageId is the cardId so OKO CF4 can update the correct item.",
118659
+ IMAGE_ADVICE.promoBanner,
118660
+ IMAGE_ADVICE.videoPlaceholder,
118661
+ IMAGE_ADVICE.card,
118662
+ "The result carries hints: whether the target block is enabled, what still hides the image (placeholder mode/live switch), and the advice above."
118627
118663
  ]
118628
118664
  }),
118629
118665
  inputSchema: {
@@ -119273,7 +119309,8 @@ function registerLiveTools(server2) {
119273
119309
  returns: "eventId, block, and effective override value.",
119274
119310
  examples: ["Use visible=false to hide the CTA live; use visible=null to return to setup defaults."],
119275
119311
  notes: [
119276
- "block=chat with visible=false PAUSES message input: viewers keep seeing the chat history but cannot send. It does not hide the chat panel."
119312
+ "block=chat with visible=false PAUSES message input: viewers keep seeing the chat history but cannot send. It does not hide the chat panel.",
119313
+ "Live overrides sit on top of setup: a block disabled in setup (oko_configure_blocks enabled=false) stays absent whatever the override; visible=null returns an enabled block to its setup default. Use overrides for the live show, setup toggles for permanent changes."
119277
119314
  ]
119278
119315
  }),
119279
119316
  inputSchema: {
@@ -119286,8 +119323,17 @@ function registerLiveTools(server2) {
119286
119323
  annotations: idempotentWriteTool
119287
119324
  }, async ({ eventId, block, visible, confirm }) => {
119288
119325
  const { uid } = await authed(["live:control"]);
119289
- await readEvent(eventId, uid, "live");
119326
+ const event = await readEvent(eventId, uid, "live");
119290
119327
  requireConfirm(confirm, "oko_set_block_visibility", { eventId, block, visible });
119328
+ const setupBlocks = event.blocks && typeof event.blocks === "object" ? event.blocks : {};
119329
+ const setupEnabled = {
119330
+ chat: setupBlocks.chat?.enabled === true,
119331
+ banner: setupBlocks.promoBanner?.enabled === true,
119332
+ cta: setupBlocks.primaryCta?.enabled === true,
119333
+ cards: setupBlocks.cards?.enabled === true,
119334
+ placeholder: setupBlocks.video?.placeholder?.enabled === true
119335
+ };
119336
+ const hints = setupEnabled[block] ? [visible === null ? "Override removed: the block follows its setup visibility again." : `Live override applied on top of setup; visible=null returns the ${block} block to its setup default.`] : [`The ${block} block is disabled in setup, so this live override has no visible effect until it is enabled (${block === "cards" ? "oko_configure_cards enabled=true" : "oko_configure_blocks"}).`];
119291
119337
  const paths = {
119292
119338
  chat: "chatVisible",
119293
119339
  banner: "bannerVisible",
@@ -119309,14 +119355,14 @@ function registerLiveTools(server2) {
119309
119355
  await remove(modeRef);
119310
119356
  await remove(legacyRef);
119311
119357
  }
119312
- return textResult({ eventId, block, visible });
119358
+ return textResult({ eventId, block, visible, hints });
119313
119359
  }
119314
119360
  const target = ref(rtdb, `events/${eventId}/ctrl/${paths[block]}`);
119315
119361
  if (visible === null)
119316
119362
  await remove(target);
119317
119363
  else
119318
119364
  await set(target, visible);
119319
- return textResult({ eventId, block, visible });
119365
+ return textResult({ eventId, block, visible, hints });
119320
119366
  });
119321
119367
  server2.registerTool("oko_refresh_viewers", {
119322
119368
  title: "Refresh viewers",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okostream/mcp",
3
- "version": "0.12.3",
3
+ "version": "0.12.4",
4
4
  "description": "Control OKO Stream webinars from Claude, Codex, and other MCP clients.",
5
5
  "license": "UNLICENSED",
6
6
  "author": {