@okostream/mcp 0.13.0 → 0.13.2
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/server.js +24 -19
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -116230,6 +116230,15 @@ if (!env.firebase.chatDatabaseURL) {
|
|
|
116230
116230
|
throw new Error("OKO MCP: chat database URL is not configured. Set OKO_FIREBASE_CHAT_DB_URL (or keep the bundled default) \u2014 chat paths do not exist in the main database.");
|
|
116231
116231
|
}
|
|
116232
116232
|
var chatRtdb = getDatabase(firebaseApp, env.firebase.chatDatabaseURL);
|
|
116233
|
+
async function serverNowMs(db = chatRtdb) {
|
|
116234
|
+
const offset = await new Promise((resolve3) => {
|
|
116235
|
+
onValue(ref(db, ".info/serverTimeOffset"), (snap) => {
|
|
116236
|
+
const v = snap.val();
|
|
116237
|
+
resolve3(typeof v === "number" && Number.isFinite(v) ? v : 0);
|
|
116238
|
+
}, () => resolve3(0), { onlyOnce: true });
|
|
116239
|
+
});
|
|
116240
|
+
return Date.now() + offset;
|
|
116241
|
+
}
|
|
116233
116242
|
var functions = getFunctions(firebaseApp, "us-central1");
|
|
116234
116243
|
|
|
116235
116244
|
// build/scopes.js
|
|
@@ -116291,7 +116300,7 @@ function sanitizeScopes(scopes) {
|
|
|
116291
116300
|
}
|
|
116292
116301
|
|
|
116293
116302
|
// build/version.js
|
|
116294
|
-
var OKO_MCP_VERSION = "0.13.
|
|
116303
|
+
var OKO_MCP_VERSION = "0.13.2";
|
|
116295
116304
|
|
|
116296
116305
|
// build/auth.js
|
|
116297
116306
|
var state = null;
|
|
@@ -118346,7 +118355,7 @@ function registerChatTools(server2) {
|
|
|
118346
118355
|
const { uid } = await authed(["chat:moderate"]);
|
|
118347
118356
|
await readEvent(eventId, uid, "moderate");
|
|
118348
118357
|
requireConfirm(confirm, "oko_delete_chat_message", { eventId, messageId });
|
|
118349
|
-
await set(ref(chatRtdb, `mod/deleted/${eventId}/${messageId}`), { deletedAt: serverTimestamp(), ts:
|
|
118358
|
+
await set(ref(chatRtdb, `mod/deleted/${eventId}/${messageId}`), { deletedAt: serverTimestamp(), ts: await serverNowMs(), by: uid, reason: "manual" });
|
|
118350
118359
|
return textResult({ eventId, messageId, deleted: true });
|
|
118351
118360
|
});
|
|
118352
118361
|
server2.registerTool("oko_mute_user", {
|
|
@@ -118364,7 +118373,7 @@ function registerChatTools(server2) {
|
|
|
118364
118373
|
const actor = await authed(["chat:moderate"]);
|
|
118365
118374
|
await readEvent(eventId, actor.uid, "moderate");
|
|
118366
118375
|
requireConfirm(confirm, "oko_mute_user", { eventId, targetUid, minutes });
|
|
118367
|
-
await set(ref(chatRtdb, `mutes/${eventId}/${targetUid}`), { until:
|
|
118376
|
+
await set(ref(chatRtdb, `mutes/${eventId}/${targetUid}`), { until: await serverNowMs() + minutes * 6e4, by: actor.uid, reason: "manual" });
|
|
118368
118377
|
return textResult({ eventId, targetUid, mutedMinutes: minutes });
|
|
118369
118378
|
});
|
|
118370
118379
|
server2.registerTool("oko_ban_user", {
|
|
@@ -118386,9 +118395,10 @@ function registerChatTools(server2) {
|
|
|
118386
118395
|
const messagesSnap = await get(query(ref(chatRtdb, `messages/${eventId}`), limitToLast(500)));
|
|
118387
118396
|
const messages = messagesSnap.val() ?? {};
|
|
118388
118397
|
const deletes = {};
|
|
118398
|
+
const nowMs = await serverNowMs();
|
|
118389
118399
|
for (const [messageId, message] of Object.entries(messages)) {
|
|
118390
118400
|
if (message.uid === targetUid)
|
|
118391
|
-
deletes[`mod/deleted/${eventId}/${messageId}`] = { deletedAt: serverTimestamp(), ts:
|
|
118401
|
+
deletes[`mod/deleted/${eventId}/${messageId}`] = { deletedAt: serverTimestamp(), ts: nowMs, by: actor.uid, reason: "ban" };
|
|
118392
118402
|
}
|
|
118393
118403
|
if (Object.keys(deletes).length > 0)
|
|
118394
118404
|
await update(ref(chatRtdb), deletes);
|
|
@@ -119908,13 +119918,16 @@ function registerLifecycleTools(server2) {
|
|
|
119908
119918
|
|
|
119909
119919
|
// build/tools/live.js
|
|
119910
119920
|
var CHAT_LIVE_SETTINGS = ["mode", "slowModeMs", "automodEnabled", "allowViewerLinks"];
|
|
119921
|
+
async function writeChatControl(eventId, mode) {
|
|
119922
|
+
await update(ref(rtdb, `events/${eventId}/ctrl`), { chatMode: mode, chatVisible: null });
|
|
119923
|
+
}
|
|
119911
119924
|
function registerLiveTools(server2) {
|
|
119912
119925
|
server2.registerTool("oko_get_live_state", {
|
|
119913
119926
|
title: "Get live state",
|
|
119914
119927
|
description: toolDescription({
|
|
119915
119928
|
summary: "Read main RTDB live controls, aggregate analytics, and chat settings for an event.",
|
|
119916
119929
|
args: ["eventId: event to inspect."],
|
|
119917
|
-
returns: "eventId, agg metrics, ctrl live overrides, and chat settings (mode, slowModeMs, automodEnabled, allowViewerLinks, plus accepting \u2014 whether message intake is open right now, as the server enforces it).",
|
|
119930
|
+
returns: "eventId, agg metrics, ctrl live overrides, and chat settings (mode, slowModeMs, automodEnabled, allowViewerLinks, plus accepting \u2014 whether message intake is open right now, as the server enforces it). ctrl.chatMode is the live control for message intake: public, off, or absent (then the event's starting state blocks.chat.intake applies and accepting shows the result).",
|
|
119918
119931
|
examples: ["Use during a webinar before changing live block visibility or starting/ending sessions."],
|
|
119919
119932
|
notes: [
|
|
119920
119933
|
"Live state does not carry the event team: to see who has access to an event and with which permissions, use oko_list_workspace_access on the event's workspace."
|
|
@@ -119949,7 +119962,7 @@ function registerLiveTools(server2) {
|
|
|
119949
119962
|
returns: "eventId, block, and effective override value.",
|
|
119950
119963
|
examples: ["Use visible=false to hide the CTA live; use visible=null to return to setup defaults."],
|
|
119951
119964
|
notes: [
|
|
119952
|
-
"block=chat
|
|
119965
|
+
"block=chat controls MESSAGE SENDING, never the panel: visible=true OPENS sending (same as oko_set_chat_mode mode=public), visible=false PAUSES it (mode=off \u2014 viewers keep seeing the history but cannot send), visible=null returns the chat to its starting state (blocks.chat.intake). The panel itself is blocks.chat.enabled in oko_configure_blocks.",
|
|
119953
119966
|
"Chat is the only block whose override the SERVER enforces: it is written as the chat mode and mirrored into the chat security rules, so a paused chat refuses messages from every client. The other four overrides are page presentation only \u2014 they change what viewers see, not what the server accepts.",
|
|
119954
119967
|
"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."
|
|
119955
119968
|
]
|
|
@@ -119974,7 +119987,8 @@ function registerLiveTools(server2) {
|
|
|
119974
119987
|
cards: setupBlocks.cards?.enabled === true,
|
|
119975
119988
|
placeholder: setupBlocks.video?.placeholder?.enabled === true
|
|
119976
119989
|
};
|
|
119977
|
-
const
|
|
119990
|
+
const chatHint = visible === null ? "Live control cleared: message intake follows the starting state (blocks.chat.intake)." : visible ? "Message sending is open (chat mode public); the panel was not touched." : "Message sending is paused (chat mode off); history stays visible, the panel was not touched.";
|
|
119991
|
+
const hints = !setupEnabled[block] ? [`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"}).`] : block === "chat" ? [chatHint] : [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.`];
|
|
119978
119992
|
const paths = {
|
|
119979
119993
|
chat: "chatVisible",
|
|
119980
119994
|
banner: "bannerVisible",
|
|
@@ -119983,16 +119997,7 @@ function registerLiveTools(server2) {
|
|
|
119983
119997
|
placeholder: "placeholderVisible"
|
|
119984
119998
|
};
|
|
119985
119999
|
if (block === "chat") {
|
|
119986
|
-
|
|
119987
|
-
const patch = { chatVisible: null };
|
|
119988
|
-
if (visible === null || visible === false) {
|
|
119989
|
-
patch.chatMode = visible === false ? "off" : null;
|
|
119990
|
-
} else {
|
|
119991
|
-
const current = await get(modeRef);
|
|
119992
|
-
if (current.val() === "off")
|
|
119993
|
-
patch.chatMode = null;
|
|
119994
|
-
}
|
|
119995
|
-
await update(ref(rtdb, `events/${eventId}/ctrl`), patch);
|
|
120000
|
+
await writeChatControl(eventId, visible === null ? null : visible ? "public" : "off");
|
|
119996
120001
|
return textResult({ eventId, block, visible, hints });
|
|
119997
120002
|
}
|
|
119998
120003
|
const target = ref(rtdb, `events/${eventId}/ctrl/${paths[block]}`);
|
|
@@ -120077,7 +120082,7 @@ function registerLiveTools(server2) {
|
|
|
120077
120082
|
examples: ['Use mode="off" to pause a chat storm; use mode="public" to reopen.'],
|
|
120078
120083
|
notes: [
|
|
120079
120084
|
'\u{1F534} "Turn off the chat" means one of TWO different things. THIS tool stops new messages: the panel stays on the page, history stays readable, nothing changes for the audience except the input. The other one \u2014 oko_configure_blocks with chat.enabled=false \u2014 HIDES the whole panel (history is kept for 90 days and returns when re-enabled), which is a page-layout decision, not a live-show one. When the organizer says "turn off the chat", "close the chat", "stop the chat", "mute the chat", "disable chat" during or after a webinar, they almost always mean THIS tool. Ask before hiding the panel.',
|
|
120080
|
-
'
|
|
120085
|
+
'oko_set_block_visibility(block="chat") writes this same state (visible=true \u2192 public, false \u2192 off, null \u2192 starting state); prefer this tool for the chat, it says what it does.',
|
|
120081
120086
|
"There are no other levels: the server has exactly two states, sending open or closed. History is always visible; the mode never restricts who can read or hides anyone's messages."
|
|
120082
120087
|
]
|
|
120083
120088
|
}),
|
|
@@ -120095,7 +120100,7 @@ function registerLiveTools(server2) {
|
|
|
120095
120100
|
const { uid } = await authed(["live:control"]);
|
|
120096
120101
|
await readEvent(eventId, uid, "live");
|
|
120097
120102
|
requireConfirm(confirm, "oko_set_chat_mode", { eventId, mode });
|
|
120098
|
-
await
|
|
120103
|
+
await writeChatControl(eventId, mode);
|
|
120099
120104
|
return textResult({ eventId, mode });
|
|
120100
120105
|
});
|
|
120101
120106
|
server2.registerTool("oko_force_viewer_reload", {
|