@okostream/mcp 0.12.3 → 0.12.5

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 +58 -13
  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.5";
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
 
@@ -117348,7 +117363,7 @@ var SCOPE_UNLOCKS = {
117348
117363
  "chat:moderate": "chat mode, moderation, bans and mutes",
117349
117364
  "telegram:write": "claiming channels and publishing Telegram posts",
117350
117365
  "workspace:read": "listing workspaces, members, invites, notifications",
117351
- "workspace:write": "workspace management, invites, profile edits, moving events between workspaces",
117366
+ "workspace:write": "workspace management, invites, profile edits",
117352
117367
  "leads:read": "reading and exporting leads"
117353
117368
  };
117354
117369
  function presetsWithScope(scope) {
@@ -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: {
@@ -118855,7 +118891,6 @@ async function recordToolAudit(toolName, outcome, args, startedAt, error3) {
118855
118891
  var REPORT_URL = `${APP_ORIGIN}/contact`;
118856
118892
  var KEYS_URL = `${APP_ORIGIN}/app/mcp`;
118857
118893
  var SCOPE_WORKAROUNDS = {
118858
- oko_move_event: "Without workspace:write you can still place the event in another workspace: call oko_duplicate_event with targetWorkspaceId to create a copy there. The original stays where it is; live overrides (chat mode, placeholder visibility) are not copied and must be set again on the copy.",
118859
118894
  oko_trash_event: "This key cannot delete events. Tell the organizer which event to remove; they can do it in the OKO cabinet, or create a key with the full preset.",
118860
118895
  oko_delete_event_permanently: "This key cannot delete events. Tell the organizer which event to remove; they can do it in the OKO cabinet, or create a key with the full preset.",
118861
118896
  oko_publish_telegram_post: "This key cannot publish to Telegram. The organizer can publish the announcement from the OKO cabinet, or create a key with the full preset."
@@ -119169,7 +119204,7 @@ function registerLifecycleTools(server2) {
119169
119204
  notes: [
119170
119205
  "Copies title, video, meta, blocks, forms, and Telegram config; does not copy analytics sessions or leads.",
119171
119206
  "Live overrides are NOT copied: the copy starts with chat mode public and the placeholder hidden, whatever the source had. Set them again with oko_set_chat_mode and oko_set_block_visibility on the new event.",
119172
- "Requires only events:write plus createEvents in the target workspace, so it also works as the way to place an event in another workspace when the key lacks workspace:write for oko_move_event."
119207
+ "Requires only events:write plus createEvents in the target workspace. To move (not copy) an event, use oko_move_event with the same scope."
119173
119208
  ]
119174
119209
  }),
119175
119210
  inputSchema: {
@@ -119222,7 +119257,7 @@ function registerLifecycleTools(server2) {
119222
119257
  examples: ["Use when an event belongs in another workspace. Call oko_list_workspaces first to choose the target."],
119223
119258
  notes: [
119224
119259
  "Reads target workspace shares from Firestore with permissions; does not use RTDB workspaceMembers.",
119225
- "Requires the workspace:write scope (preset full). Keys with the operator preset cannot move events: use oko_duplicate_event with targetWorkspaceId instead, which creates a copy in the target workspace and leaves the original in place."
119260
+ "Requires events:write plus ownership of the event (or of its source workspace) and createEvents in the target workspace; no workspace:write needed. Live overrides (chat mode, placeholder) travel with the event: they live in the event's own RTDB node."
119226
119261
  ]
119227
119262
  }),
119228
119263
  inputSchema: {
@@ -119233,7 +119268,7 @@ function registerLifecycleTools(server2) {
119233
119268
  outputSchema: updateOutputSchema,
119234
119269
  annotations: writeTool
119235
119270
  }, async ({ eventId, targetWorkspaceId, confirm }) => {
119236
- await authed(["events:write", "workspace:write"]);
119271
+ await authed(["events:write"]);
119237
119272
  requireConfirm(confirm, "oko_move_event", { eventId, targetWorkspaceId });
119238
119273
  const moveEvent = httpsCallable(functions, "moveEventToWorkspace");
119239
119274
  const result = await moveEvent({ eventId, targetWorkspaceId });
@@ -119273,7 +119308,8 @@ function registerLiveTools(server2) {
119273
119308
  returns: "eventId, block, and effective override value.",
119274
119309
  examples: ["Use visible=false to hide the CTA live; use visible=null to return to setup defaults."],
119275
119310
  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."
119311
+ "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
+ "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
119313
  ]
119278
119314
  }),
119279
119315
  inputSchema: {
@@ -119286,8 +119322,17 @@ function registerLiveTools(server2) {
119286
119322
  annotations: idempotentWriteTool
119287
119323
  }, async ({ eventId, block, visible, confirm }) => {
119288
119324
  const { uid } = await authed(["live:control"]);
119289
- await readEvent(eventId, uid, "live");
119325
+ const event = await readEvent(eventId, uid, "live");
119290
119326
  requireConfirm(confirm, "oko_set_block_visibility", { eventId, block, visible });
119327
+ const setupBlocks = event.blocks && typeof event.blocks === "object" ? event.blocks : {};
119328
+ const setupEnabled = {
119329
+ chat: setupBlocks.chat?.enabled === true,
119330
+ banner: setupBlocks.promoBanner?.enabled === true,
119331
+ cta: setupBlocks.primaryCta?.enabled === true,
119332
+ cards: setupBlocks.cards?.enabled === true,
119333
+ placeholder: setupBlocks.video?.placeholder?.enabled === true
119334
+ };
119335
+ 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
119336
  const paths = {
119292
119337
  chat: "chatVisible",
119293
119338
  banner: "bannerVisible",
@@ -119309,14 +119354,14 @@ function registerLiveTools(server2) {
119309
119354
  await remove(modeRef);
119310
119355
  await remove(legacyRef);
119311
119356
  }
119312
- return textResult({ eventId, block, visible });
119357
+ return textResult({ eventId, block, visible, hints });
119313
119358
  }
119314
119359
  const target = ref(rtdb, `events/${eventId}/ctrl/${paths[block]}`);
119315
119360
  if (visible === null)
119316
119361
  await remove(target);
119317
119362
  else
119318
119363
  await set(target, visible);
119319
- return textResult({ eventId, block, visible });
119364
+ return textResult({ eventId, block, visible, hints });
119320
119365
  });
119321
119366
  server2.registerTool("oko_refresh_viewers", {
119322
119367
  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.5",
4
4
  "description": "Control OKO Stream webinars from Claude, Codex, and other MCP clients.",
5
5
  "license": "UNLICENSED",
6
6
  "author": {